﻿/* LCM · sistema de diseño del rediseño responsive
 *
 * Portado de camasa-generals/informes/LCM-rediseno-responsive.html.
 * Convive con lcm.css: nada de acá pisa una pantalla que todavía no se
 * rediseñó. El interruptor es la clase `ui`, que una página pone en su
 * contenedor raíz; a partir de ahí manda este sistema.
 *
 * Tres decisiones que gobiernan todo el archivo:
 *
 *   1. Ámbito `.ui`. Los nombres son los de la maqueta (.card, .li, .row,
 *      .btn, .chip). Varios coinciden con bootstrap.min.css, que se carga
 *      antes; el prefijo `.ui` sube la especificidad a 0,2,0 y gana siempre.
 *   2. Los quiebres se miden CONTRA EL CONTENEDOR (`container-type:
 *      inline-size`), no contra la ventana: 700 / 1080 / 1440 px.
 *   3. El shell se adapta con `:has(.ui)` — una página rediseñada ensancha
 *      la columna, estrena los tabs nuevos y estrena el riel lateral y el
 *      topbar de escritorio, sin tocar a las vistas de antes.
 *   4. El bloque de contenido es una TARJETA (2026-08-12). La primera versión
 *      del sistema separaba los bloques con filetes horizontales y sin marco:
 *      funcionaba dentro de una columna centrada de 1180 px, porque el borde
 *      de esa columna hacía de marco. Con el marco a ancho completo —que es
 *      como se ve la App en un monitor real— hacía falta que cada bloque
 *      dijera dónde empieza y dónde termina. Lo que NO cambió es el interior:
 *      las listas y las tablas siguen sin paredes verticales, con filetes que
 *      no llegan a los cantos. Marco por fuera, nada por dentro.
 *
 * Estructura
 *   1. Ámbito y tokens (claro / oscuro)
 *   2. Shell: riel lateral, topbar, columna, encabezado móvil, tabs, panel
 *      de contexto
 *   3. Primitivas: tipografía, tarjetas (card, card-h/b/f, kpis), botones,
 *      campos
 *   4. Elección directa: opt, opt-g, fichas, seg, slider
 *   5. Bloques de datos: banda, cifras, tejas, rank, turno
 *   6. Lista de registros: lista, li, carril de prioridad, swipe
 *   7. Tabla, línea de vida, línea de tiempo, evidencia
 *   8. Avisos, hojas, barra de acción, instalar la App
 *   9. Responsive por container query
 */

/* ── 1 · Ámbito y tokens ──────────────────────────────────────────── */

/* Los tokens se declaran también en `.ui-shell` porque el riel y el topbar
   viven FUERA de `.ui` —son del layout, no de la página— y sin esto no verían
   un solo color. Se comparten SOLO las variables: ni fondo, ni tinta, ni
   tipografía, para que una vista todavía no rediseñada que cuelga del mismo
   layout no cambie de aspecto. */
:root,
.ui,
.ui-shell {
    /* El lienzo casi blanco y el borde apenas insinuado. Antes el lienzo era
       #f3f6f8 y el borde #e2e8ee: un gris azulado con bastante cuerpo, que con
       una tarjeta por bloque dibujaba una reja sobre la pantalla. Bajar el
       contraste ENTRE superficies es lo que deja que el contenido sea lo más
       oscuro de la vista; el contraste del TEXTO no se toca. */
    /* Los controles nativos no leen tokens: el desplegable de un <select>, la
       barra de desplazamiento y el selector de fecha los pinta el navegador, y
       sin esta declaración los pinta SIEMPRE en claro. Era el menú blanco con
       las opciones en gris que asomaba encima de la pantalla oscura al elegir
       una prioridad — ninguna regla de CSS lo alcanza, porque ese menú no se
       dibuja dentro de la página. */
    color-scheme: light;

    --canvas:   #f7f8fa;
    --surface:  #ffffff;
    --sunken:   #f1f3f6;
    --line:     #e9ebef;
    --line-soft:#f2f4f7;
    --ink:      #16181d;
    --ink-2:    #383f4a;
    --muted:    #5d6b7a;
    /* Sube de #8b9aa9 porque ahí no se leía: 2.47:1 sobre el lienzo hundido y
       2.88:1 sobre blanco, contra el 4.5:1 que pide una etiqueta de texto
       normal. No es tinta decorativa — sostiene los rótulos de las cifras, las
       cabeceras de tabla y el paginado. Ahora pasa sobre las tres superficies
       (4.96 / 5.39 / 4.62) y sigue siendo el gris más tenue de los dos. */
    --muted-2:  #606c75;

    --verde:    #3f5d4a;
    --verde-d:  #2f4838;
    --verde-l:  #e9efea;
    --verde-b:  #cedcd3;

    --ambar:    #b45309;  --ambar-l: #fef3c7;  --ambar-b: #fde68a;
    --rojo:     #c0392f;  --rojo-l:  #fdecea;  --rojo-b:  #f6c9c4;
    --azul:     #1d5fbf;  --azul-l:  #e8f0fd;  --azul-b:  #c6dcf8;
    --violeta:  #5b4bc4;  --violeta-l:#eeecfd;
    --indigo:   #4338ca;  --indigo-l: #eef2ff;  --indigo-b: #d7ddfd;
    --exito:    #16794a;  --exito-l: #e3f4ea;  --exito-b: #bfe3cf;

    /* Magnitud comparable: una sola tinta. Nunca naranja. */
    --viz:      #1a7f4f;
    --viz-soft: #d9ece2;
    /* Rampa de severidad — EXCLUSIVA de prioridad y criticidad. */
    --sev-1:    #e8a05c;
    --sev-2:    #dd7c34;
    --sev-3:    #c2571e;
    --sev-4:    #983510;
    --grid:     #e6ebf0;

    /* La hoja de la firma. El trazo se captura en tinta oscura sobre lienzo
       transparente (#1e293b en wwwroot/js/signature-pad.js) porque su destino
       final es el papel, así que la rúbrica necesita fondo claro debajo
       SIEMPRE. En claro lo pone la tarjeta y no hay nada que pintar; en oscuro
       se pinta la hoja. La raya en la que se apoya la firma va con la hoja. */
    --firma-papel: transparent;
    --firma-linea: var(--ink);

    --r-s: 8px; --r-m: 10px; --r-l: 12px; --r-xl: 16px;
    /* Sombra de reposo casi imperceptible: con una tarjeta por bloque, la sombra
       de antes sumaba un halo gris debajo de cada una y la pantalla quedaba
       moteada. El marco lo dice el borde; la sombra solo despega la tarjeta del
       lienzo lo justo. */
    --sh-s: 0 1px 2px rgba(22,24,29,.03);
    --sh-m: 0 4px 14px rgba(22,24,29,.06);
    --sh-l: 0 18px 44px rgba(22,24,29,.14);

    /* ── Aire vertical de una fila, en tokens ──────────────────────────────
       La densidad de las listas es una PREFERENCIA DEL USUARIO y tiene que
       ganarle al reparto de cualquier pantalla. Como regla de padding no podía:
       el CSS aislado de una página suma su atributo de aislamiento, así que
       `.coord-inicio .card > .lista > .li[b-x]` vale 0,5,0 contra los 0,3,0 de
       la regla de densidad y la tapaba — el interruptor no movía nada en los
       tableros del Coordinador ni del Gerente de Tienda (medido).

       Los tokens no compiten: se HEREDAN desde <html>, donde el ayudante de
       preferencias estampa data-densidad. Cada regla que decide el aire de una
       fila lee el token en vez de fijar el número, y así una sola declaración
       —la de lcm.css— manda en todas las pantallas.

       `-densa` es la variante de los tableros, cuyas filas ya nacen más
       apretadas que las de una bandeja y no pueden usar el mismo número. */
    --li-py: 16px;
    --li-py-densa: 11px;
    --lista-h-py: 17px;
    --td-py: 12px;
    --td-py-densa: 9px;
}

/* En teléfono la fila cede un escalón de aire, igual que el resto de los
   rellenos. Va por consulta de MEDIO y no de contenedor porque un `@container`
   no puede estilar al elemento que lo consulta, y el que lleva el token es
   justamente la raíz `.ui`.

   Repite los tres selectores del bloque de arriba a propósito: como el token se
   declara TAMBIÉN sobre cada `.ui`, un valor puesto solo en `:root` no llegaría
   —lo que el elemento declara para sí mismo le gana a lo que hereda—. Vale
   0,1,0, así que la preferencia de densidad —0,2,0— le sigue ganando sin
   depender del orden en que se carguen las hojas. */
@media (max-width: 699px) {
    :root, .ui, .ui-shell { --li-py: 12px; --lista-h-py: 13px; --td-py: 10px; }
}

.ui {
    container-type: inline-size;
    display: flex;
    flex-direction: column;
    min-width: 0;

    background: var(--canvas);
    color: var(--ink);
    font-family: var(--lcm-font);
}

/* Tema oscuro. Los tokens ya están; el control que lo activa vive en
   Perfil (p08) y llega con el lote de pantallas transversales. */
/* Los tokens del oscuro valen tanto si el atributo está EN la raíz `.ui` como si
   está en un ancestro —hoy `<html>`, que es lo que evita el destello al navegar
   (ver la nota del script en index.html)—. Tienen que quedar declarados SOBRE
   `.ui` y `.ui-shell`, no solo heredados desde arriba: esos dos declaran los
   tokens claros en su propia regla base, y una declaración en el elemento le gana
   siempre a un valor heredado. */
/* Va dentro de `@media screen` a propósito, y esto es lo que devuelve la hoja
   impresa a tinta clara. `data-tema` vive en <html>, así que la impresión lo
   hereda: sin este envoltorio el papel salía con `color-scheme: dark` y el
   navegador pintaba de #121212 TODO lo que el documento no cubre — el marco
   negro alrededor de la hoja al imprimir desde el tema oscuro. El reinicio
   de `@media print` de lcm.css no alcanzaba: declara los mismos tokens con
   la misma especificidad sobre `:root[data-tema="oscuro"]`, pero esta hoja
   se carga DESPUÉS y ganaba por orden. Fuera de pantalla mandan los valores
   claros de la regla base, que es exactamente lo que el papel necesita. */
@media screen {
    :root[data-tema="oscuro"],
    [data-tema="oscuro"] .ui,
    [data-tema="oscuro"] .ui-shell,
    .ui[data-tema="oscuro"],
    .ui-shell[data-tema="oscuro"] {
        color-scheme: dark;

        --canvas:   #0f151b;
        --surface:  #161d24;
        --sunken:   #1c252e;
        --line:     #26313c;
        --line-soft:#1f2831;
        --ink:      #e9eef3;
        --ink-2:    #cdd7e1;
        --muted:    #93a1b0;
        /* Misma corrección que en claro, hacia el otro lado: #6f7f8f quedaba en
           3.77:1 sobre el lienzo hundido. Ahora 5.42 / 5.01 / 4.58. */
        --muted-2:  #7f8d9c;

        --verde:    #6fa285;
        --verde-d:  #8bb99e;
        --verde-l:  #1e2b23;
        --verde-b:  #2d4437;

        --ambar:    #e2a33c;  --ambar-l: #2c2415;  --ambar-b: #4a3a18;
        --rojo:     #e78078;  --rojo-l:  #2e1c1a;  --rojo-b:  #4d2b27;
        --azul:     #7dabf0;  --azul-l:  #16233a;  --azul-b:  #27395a;
        --violeta:  #9c92ec;  --violeta-l:#1e1c33;
        --indigo:   #9aa2f5;  --indigo-l: #1b1f38;  --indigo-b: #2c3260;
        --exito:    #5cbe8b;  --exito-l: #14291f;  --exito-b: #234634;

        --viz:      #45a675;
        --viz-soft: #1f3b2d;
        --sev-1:    #b8632c;
        --sev-2:    #d98038;
        --sev-3:    #eda254;
        --sev-4:    #f7c58c;
        --grid:     #232d37;

        /* La hoja se pinta clara a propósito y la raya baja a tinta para
           seguir viéndose sobre ella. */
        --firma-papel: #e9edf2;
        --firma-linea: #3a4756;

        --sh-s: 0 1px 2px rgba(0,0,0,.35);
        --sh-m: 0 4px 16px rgba(0,0,0,.4);
        --sh-l: 0 18px 44px rgba(0,0,0,.55);
    }
}

/* Reinicio del botón. Un <button> que hace de fila, de celda o de ficha
   arrastra el borde que le pone el navegador: era eso lo que dibujaba las
   paredes duras en las listas. Va con :where() para que cualquier
   componente que sí quiera borde lo declare y gane.

   La TINTA entra por el mismo motivo, y es el bug que se veía en Perfil: el
   navegador le pone `color: buttontext` a todo <button>, que es un negro fijo
   y no una variable del tema. En claro coincide con la tinta y no se nota; en
   oscuro el mismo negro queda sobre una superficie oscura y la fila se lee
   apagada —«Traer la última versión» salía gris— salvo que el componente
   declare su color a mano, que es lo que hacía «Cerrar sesión» y por eso ese
   sí se veía. Heredar es la respuesta correcta para cualquier botón que hace
   de superficie; el que lleva relleno propio declara su tinta y gana. */
.ui :where(button) { border: none; color: inherit; }

/* Reinicio del NEGRITA, y es la pieza que le faltaba a la escala tipográfica.
 *
 * La tanda que bajó el sistema a 600 / 500 / 400 corrigió las DECLARACIONES del
 * archivo, pero no tocó a `<b>` ni a `<strong>`, que no tienen ninguna regla y
 * se quedaron con el `font-weight: bolder` del navegador. Y `bolder` no es un
 * número: es un salto relativo al padre, así que el mismo `<strong>` pesaba
 * distinto según dónde cayera. Medido en Edge sobre este mismo archivo:
 *
 *     dentro de .note   (400) → 700
 *     dentro de .li-t   (500) → 700
 *     dentro de .h3     (600) → 900   ← y acá está el problema de verdad
 *
 * Los 900 son el defecto que ya se había diagnosticado una vez: index.html carga
 * la fuente con `wght@400;500;600;700;800`, así que el 900 NO EXISTE en el
 * archivo y el navegador lo SINTETIZA engordando los trazos. De ahí el aspecto
 * embarrado, y por eso volvía a aparecer aunque no quedara un solo 900 escrito.
 *
 * En esta escala el énfasis ES 600 —el mismo valor que `.strong`, que ya estaba
 * declarado como clase— así que se dice una vez para el elemento. Va con
 * `:where()` para que cualquier componente que fije su propio peso gane sin
 * pelear: `.li-hora b`, `.serie-v b`, `.slider-v b` y compañía siguen mandando. */
.ui :where(b, strong) { font-weight: 600; }

.ui * { box-sizing: border-box; }

/* ── 2 · Shell ────────────────────────────────────────────────────── */

/* El shell de escritorio —riel lateral y topbar— es del layout, no de la
   página: la página es dueña de su cuerpo y el layout del envase. De ahí las
   dos decisiones que gobiernan este bloque.

   1. El envase NO tiene tope de ancho: llega al borde de la pantalla, en
      cualquier monitor. La columna mide entonces «ventana menos riel», y sus
      container queries de 700 / 1080 / 1440 px caen donde el ancho real las
      pone. Antes el shell sumaba el ancho del riel a un máximo de 1440 px
      para que la columna conservara la medida de la maqueta; el precio eran
      dos franjas de lienzo vacío a los lados en cualquier pantalla de más de
      1656 px, y la maqueta no vale más que la pantalla en la que se usa.
   2. El riel y el topbar aparecen por MEDIA query y no por container query:
      su contenedor sería el propio shell, y un elemento no puede decidir si
      existe midiendo la caja que él mismo llena. Con el envase a ancho
      completo el quiebre de ventana y el de contenedor solo se separan por el
      riel y la barra de desplazamiento — ver LA FRANJA, al final. */

.ui-shell {
    display: flex;
    flex: 1;
    min-width: 0;
    min-height: 0;
    /* Alto de la barra inferior, en UN solo lugar. Se apoyan en él la barra de
       acción de las subpáginas y el botón de volver arriba: sin un número
       compartido, cada pieza se acomodaba con su propia constante y al cambiar el
       alto de la barra había que perseguir tres reglas. Los 62 px son icono (20)
       + etiqueta + los rellenos de `.lcm-tab`, más el área segura del teléfono. */
    --alto-tabs: calc(62px + env(safe-area-inset-bottom, 0px));
}
.ui-col {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* Riel lateral. Oculto en teléfono —manda la barra inferior— y en las vistas
   que todavía no se rediseñaron. Hasta 1080 px es una columna de iconos; de
   ahí en adelante se abre con etiquetas, contadores y el usuario al pie. */
.ui-rail {
    display: none;
    flex-direction: column;
    width: 68px;
    flex-shrink: 0;
    gap: 3px;
    padding: 14px 10px 12px;
    background: var(--surface);
    border-right: 1px solid var(--line);
    overflow-y: auto;
}
.ui-rail-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 2px 4px 16px;
    min-width: 0;
}
.ui-rail-mark {
    width: 32px; height: 32px; border-radius: 9px; flex-shrink: 0;
    background: var(--verde); padding: 6px;
    display: flex; align-items: center; justify-content: center;
}
/* El logo de la App es un SVG de relleno fijo: se usa de máscara para pintarlo
   blanco sobre el cuadro verde sin duplicar el archivo. */
.ui-rail-mark i {
    display: block; width: 100%; height: 100%; background: #fff;
    -webkit-mask: url("../logo.svg") no-repeat center / contain;
    mask: url("../logo.svg") no-repeat center / contain;
}
.ui-rail-name { display: none; min-width: 0; }
.ui-rail-name b {
    display: block; font-size: 13.5px; font-weight: 600;
    line-height: 1.15; color: var(--ink);
}
/* «La Colonia» en versalitas de 8,5 px era ilegible: se leía como un patrón, no
   como el nombre de la empresa. */
.ui-rail-name span {
    display: block; font-size: 11px; font-weight: 400; letter-spacing: 0;
    text-transform: none; color: var(--muted); margin-top: 2px; line-height: 1.4;
}

/* El menú en peso normal. Estaba en 700 con el activo en 800: los cuatro destinos
   se leían todos como el activo, y lo único que los distinguía era el fondo. Ahora
   el reposo es texto normal en gris y el activo sube un solo escalón — que es
   exactamente lo que hace falta para saber dónde estás. */
.ui-nav {
    display: flex; align-items: center; gap: 12px; min-width: 0;
    padding: 10px 11px; border-radius: var(--r-m);
    color: var(--muted); text-decoration: none;
    font-size: 13.5px; font-weight: 400; line-height: 1.35;
}
.ui-nav svg { flex-shrink: 0; }
.ui-nav-t { display: none; flex: 1; min-width: 0; }
.ui-nav-c {
    display: none; font-size: 10px; font-weight: 600;
    font-variant-numeric: tabular-nums;
    background: var(--sunken); color: var(--muted);
    border-radius: 999px; padding: 2px 7px;
}
.ui-nav:hover { background: var(--sunken); color: var(--ink); }
.ui-nav.on { background: var(--verde-l); color: var(--verde-d); font-weight: 500; }
.ui-nav.on .ui-nav-c { background: var(--verde-b); color: var(--verde-d); }

/* Menú de nivel superior que no es un destino: se pulsa y despliega debajo los
   suyos. Es una fila más del menú —misma geometría que `.ui-nav`— y lo único que
   agrega es el chevrón que dice que hay algo adentro. Los botones del riel no
   heredan la tipografía: el riel vive fuera de `.ui` y su reinicio no llega acá. */
.ui-rama {
    width: 100%; border: none; background: none; cursor: pointer;
    font-family: inherit; font-size: 13.5px; font-weight: 400; text-align: left;
}
.ui-rama-chev { display: none; }
.ui-hijo .ui-nav-t { font-size: 13px; }
/* El filete del canto es lo que dice que la fila cuelga de la rama, y es lo
   único que lo dice con el riel angosto: ahí las etiquetas no se pintan. */
.ui-hijo:not(.on) { box-shadow: inset 2px 0 0 var(--line); }

.ui-rail-foot {
    margin-top: auto; padding-top: 10px;
    border-top: 1px solid var(--line-soft);
    display: flex; align-items: center; gap: 10px; min-width: 0;
    text-decoration: none; color: inherit;
}

/* Cerrar sesión: es una fila más del menú, no un botón encima del menú. Copia la
   geometría de `.ui-nav` al detalle —mismo relleno, mismo radio, mismo hueco— y
   se distingue solo por ser más tenue y por virar al rojo del sistema al pasar
   por encima. Un recuadro con borde acá se lee como un cuerpo extraño. */
.ui-rail-salir {
    display: flex; align-items: center; gap: 11px; min-width: 0; width: 100%;
    padding: 9px; margin-top: 2px; border: none; border-radius: var(--r-m);
    background: none; color: var(--muted-2); cursor: pointer;
    font-family: inherit; font-size: 13px; font-weight: 500; line-height: 1.25;
    text-align: left;
}
.ui-rail-salir svg { flex-shrink: 0; }
.ui-rail-salir:hover { background: var(--sunken); color: var(--rojo); }
.ui-rail-ini {
    width: 32px; height: 32px; border-radius: 999px; flex-shrink: 0;
    background: var(--sunken); color: var(--ink-2);
    display: flex; align-items: center; justify-content: center;
    font-size: 11px; font-weight: 600;
}
.ui-who { display: none; min-width: 0; }
.ui-who .n {
    display: block; font-size: 12.5px; font-weight: 600;
    line-height: 1.25; color: var(--ink);
}
.ui-who .s {
    display: block; font-size: 10.5px; font-weight: 500;
    color: var(--muted-2); line-height: 1.35;
}

/* Topbar de escritorio: sección actual, buscador y los iconos que en teléfono
   viven en el encabezado de cada pantalla. */
.ui-top {
    display: none; align-items: center; gap: 10px; flex-shrink: 0;
    padding: 11px 22px;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}
.ui-crumb {
    flex: 1; min-width: 0;
    font-size: 13px; font-weight: 600; color: var(--ink); line-height: 1.3;
}
/* El primer tramo de la miga es el volver de la subpágina: desde 700 px el
   encabezado de teléfono no se pinta y este es el único camino de vuelta. Se lee
   apagado, como en la maqueta, y se enciende al pasar por encima. No lleva
   nowrap: una miga larga parte de renglón antes que recortarse. */
.ui-crumb-s { color: var(--muted-2); font-weight: 500; text-decoration: none; }
a.ui-crumb-s:hover { color: var(--ink); text-decoration: underline; }
.ui-crumb i { font-style: normal; font-weight: 500; color: var(--muted-2); margin: 0 4px; }

/* Los controles propios del encabezado de la página, cuando la página los
   declara con ShellPagina. */
.ui-top-u { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
/* El buscador del topbar tiene que leerse COMO un campo. Antes era `sunken` sin
   borde: un gris apenas más oscuro que la página, sobre una barra que también es
   clara — no se notaba que fuera un control hasta tocarlo. Ahora va sobre la
   superficie con borde propio y cursor de texto, que es lo que promete. */
.ui-search {
    display: flex; align-items: center; gap: 9px; flex-shrink: 0;
    width: min(340px, 34vw); height: 36px; padding: 0 12px;
    border: 1px solid var(--line); border-radius: 10px;
    background: var(--surface); color: var(--muted);
    font-family: inherit; font-size: 12.5px; font-weight: 500;
    line-height: 1.3; text-align: left; cursor: text;
    transition: border-color 140ms ease, box-shadow 140ms ease;
}
.ui-search:focus-visible {
    outline: none; border-color: var(--verde);
    box-shadow: 0 0 0 3px var(--verde-l);
}
.ui-search svg { flex-shrink: 0; }
/* La etiqueta no se parte: el pill tiene alto fijo y un segundo renglon se le
   sale. La tecla se va al extremo con margen automatico, como en la maqueta —
   con `flex: 1; min-width: 0` en la etiqueta el texto se partia en dos. */
.ui-search > span { white-space: nowrap; }
/* Debajo de 1080 px el pill baja de sus 320 px (34vw) y la frase larga ya no
   entra: se dice corto. Es el rotulo de un control, no contenido. */
.ui-search .larga { display: none; }
.ui-search:hover { border-color: var(--muted-2); color: var(--ink); }
.ui-top .lcm-bell-btn { position: relative; }

/* Una página rediseñada aprovecha TODO el ancho de la ventana: la columna de
   480 / 1040 px de lcm.css es del diseño anterior, y sin ancho no hay
   quiebres de 1080 / 1440 px que activar.

   Sin tope, y eso es una decisión, no un olvido: el ancho que sobra se
   convierte en COLUMNAS y no en renglones más largos. La rejilla de cifras
   reparte por `auto-fit`, los bloques se emparejan de dos en dos desde
   1080 px y el panel de contexto entra a los 1440 px de contenedor. Una lista
   de OT no se estira sola: vive dentro de un bloque que sí tiene medida.

   El interruptor es `ui ancho`, no `ui` a secas: hay vistas dibujadas para una
   columna angosta —el acceso, el rechazo— y estirarlas las desarma. */
.lcm-mobile-shell:has(.ui.ancho) { max-width: 100%; }
/* El scroller pasa a columna flex para que `.ui` mida el alto completo:
   de eso dependen el `margin-top: auto` y el sticky de `.bar-acc`. */
.lcm-mobile-shell:has(.ui) .lcm-body {
    display: flex;
    flex-direction: column;
    padding-bottom: 0;
    /* Cuando la vista angosta se centra en una columna ancha, lo que queda a los
       lados tiene que ser el lienzo del sistema y no el fondo de lcm.css: si no,
       la página parece pegada sobre otra. */
    background: var(--canvas);
}
.lcm-mobile-shell:has(.ui) .lcm-body > .ui { flex: 1; }
/* Los tableros del CMO viven dentro de una pantalla con pestañas: la vista que
   se monta sigue siendo la de siempre, así que hereda el alto como si colgara
   del cuerpo. */
.lcm-mobile-shell:has(.ui) .lcm-body > .ui.dbs > .ui { flex: 1; min-width: 0; }
.ui.dbs > .dbs-tabs { flex-shrink: 0; padding: 10px 16px 2px; }
.ui.dbs > .dbs-tabs .seg { max-width: 430px; }
@container (min-width: 700px)  { .ui.dbs > .dbs-tabs { padding: 20px 26px 0; } }
@container (min-width: 1440px) { .ui.dbs > .dbs-tabs { padding: 22px 44px 0; } }

.ui-pad {
    padding: 4px 16px 96px;
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}
/* Con barra de acción propia no hace falta reservar el alto de los tabs. */
.ui-pad:has(+ .bar-acc) { padding-bottom: 24px; }
.ui-wrap { width: 100%; }

/* Encabezado móvil: volver + título grande + acciones. */
.ui-mtop {
    padding: calc(16px + env(safe-area-inset-top, 0px)) 16px 10px;
    background: var(--canvas);
    flex-shrink: 0;
    display: flex;
    align-items: flex-start;
    gap: 10px;
}
.ui-back {
    width: 34px; height: 34px; margin: -4px 0 0 -6px; flex-shrink: 0;
    border-radius: 999px; background: transparent; color: var(--ink);
    display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer; text-decoration: none;
}
.ui-mtitle { flex: 1; min-width: 0; }
.ui-mtitle b {
    display: block; font-size: 27px; font-weight: 600; letter-spacing: -.025em;
    line-height: 1.08; color: var(--ink);
}
.ui-mtitle span {
    display: block; font-size: 12px; color: var(--muted); font-weight: 500;
    margin-top: 4px; line-height: 1.4;
}
.ui-mtop-acts { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
/* Los botones del encabezado (campana, manual, calendario) son componentes
   compartidos con los otros roles: se restilan acá, no en su marcado. En
   escritorio los mismos componentes se pintan en el topbar. */
.ui .lcm-bell-btn,
.ui-top .lcm-bell-btn {
    width: 34px; height: 34px; border-radius: 9px;
    border: 1px solid var(--line); background: var(--surface); color: var(--muted);
    display: inline-flex; align-items: center; justify-content: center;
}
.ui .lcm-bell-btn:hover,
.ui-top .lcm-bell-btn:hover { color: var(--ink); border-color: var(--verde-b); }
/* El conteo va en la ESQUINA del icono, no encima. La chapa de lcm.css mide
   18 px y se coloca a 4 px del canto: sobre un botón de 34 px eso es casi todo
   el botón, y la campana quedaba tapada por un disco rojo con un número —el
   control dejaba de leerse como campana—. Acá es más chica, se sale del botón
   y lleva el aro del fondo para separarse del borde. */
.ui .lcm-bell-badge,
.ui-top .lcm-bell-badge {
    top: -5px; right: -5px;
    min-width: 16px; height: 16px;
    padding: 0 4px;
    font-size: 10px; line-height: 16px;
    box-shadow: 0 0 0 2px var(--surface);
}
/* La misma campana se pinta en el encabezado de teléfono y en el topbar, y su
   hoja se declara en lcm.css como un desplegable FIJO y centrado en la columna
   de 480 px. Eso es lo correcto en un teléfono y absurdo en una ventana ancha:
   la hoja aparecía a medio lienzo, lejos del icono que la abrió. Desde 700 px
   cuelga del icono. `.lcm-bell-wrap` ya es el ancla (`position: relative`).
   Sigue siendo `fixed` la cortina, que es de la ventana entera. */
@media (min-width: 700px) {
    .ui-top .lcm-bell-panel {
        position: absolute;
        top: calc(100% + 10px);
        right: 0;
        left: auto;
        width: min(400px, calc(100vw - 32px));
        max-height: min(70vh, 560px);
    }
}

/* Barra inferior de pestañas — mismo marcado de BottomTabs, acabado nuevo.
   Es del teléfono: desde 700 px la reemplaza el riel lateral. Como isla
   centrada de 520 px para que no queden tres iconos separados por medio
   metro en una tableta angosta. */
/* Barra inferior FIJA al pie, de canto a canto.

   Probé la variante flotante —isla despegada de los tres bordes— y no va: la
   barra de navegación es el suelo de la app, y un suelo que flota deja ver
   contenido por debajo y por los costados, así que se lee como una tarjeta más y
   no como el marco de la aplicación. Va pegada abajo y a todo el ancho.

   Todos los colores salen de TOKENS y no de valores literales. La barra vive
   fuera de `.ui` —es del layout— pero DENTRO de `.ui-shell`, que también recibe
   el `data-tema`, así que las variables del tema oscuro le llegan por herencia.
   Con `#fff` y `rgba(22,24,29,…)` escritos a mano la barra se quedaba blanca
   sobre una app oscura.

   El indicador del destino activo es una pastilla detrás del icono, no la raya
   pegada al techo: la raya al ras del canto se leía como un corte de la barra. */
.lcm-mobile-shell:has(.ui) .lcm-tabs {
    left: 0; right: 0; bottom: 0;
    max-width: 100%;
    margin: 0;
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: blur(18px) saturate(1.3);
    -webkit-backdrop-filter: blur(18px) saturate(1.3);
    border: none;
    border-top: 1px solid var(--line);
    border-radius: 0;
    box-shadow: none;
    padding-bottom: calc(6px + env(safe-area-inset-bottom, 0px));
}
.lcm-mobile-shell:has(.ui) .lcm-tab {
    padding: 9px 4px 7px; gap: 3px;
    position: relative; border-radius: 14px;
}

/* Las tintas de la pestaña vienen de lcm.css con los tokens VIEJOS
   (`--lcm-muted`, `--lcm-primary`), que no tienen variante oscura. Se traen al
   sistema nuevo para que sigan el tema. */
.ui-shell .lcm-tab { color: var(--muted); }
.ui-shell .lcm-tab.active { color: var(--verde-d); }
.ui-shell .lcm-tab.active .lcm-tab-label { font-weight: 600; }
.ui-shell .lcm-tab-label { font-weight: 500; letter-spacing: 0; font-size: 10.5px; }
/* La pastilla del activo va DETRÁS del contenido del botón, así que se dibuja
   con un pseudoelemento y no con el fondo del botón: el icono y la etiqueta
   conservan su color y no hay que repintarlos. */
.lcm-mobile-shell:has(.ui) .lcm-tab.active::before {
    content: ""; position: absolute; inset: 4px 8px;
    background: var(--verde-l); border-radius: 11px; z-index: 0;
}
.lcm-mobile-shell:has(.ui) .lcm-tab > * { position: relative; z-index: 1; }
.lcm-mobile-shell:has(.ui) .lcm-tab-indicator { display: none; }

/* ── Un nodo del índice de fraccionamiento ────────────────────────────────
   Vive acá y no en el css aislado del panel porque lo pinta `FraccNodo`, que es
   un componente aparte —y recursivo: el árbol tiene tantos niveles como
   dimensiones queden por abrir—.

   La anatomía es la de las gráficas apiladas: nombre y resumen, la barra con lo
   que pesa el nodo contra su hermano mayor, y el monto al canto. La versión
   anterior ponía el nombre a la izquierda y el monto a la derecha con el ancho
   entero de la pantalla vacío en medio; la barra ocupa ese hueco con el dato que
   faltaba —cuánto pesa esto contra el resto— en lugar de rellenarlo. */
.ui .fr-n { min-width: 0; }
/* La columna del nombre mide su CONTENIDO (`auto`) y no una fracción del ancho:
   con `1fr` se quedaba con la mitad de la fila para escribir «Raúl Tinoco» y
   dejaba trescientos píxeles de nada antes de la barra — el hueco que había que
   cerrar. Lo que sobra se lo lleva la barra, que es la que crece con gusto. */
.ui .fr-h {
    display: grid; grid-template-columns: 15px minmax(150px, auto) minmax(120px, 1fr) auto auto;
    align-items: center; column-gap: 10px; row-gap: 4px;
    width: 100%; padding: 8px 0; margin: 0;
    background: none; border: 0; border-radius: 8px;
    font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.ui .fr-h:hover .fr-nom { color: var(--verde-d); }
.ui .fr-ch {
    grid-column: 1; grid-row: 1; align-self: center;
    display: inline-flex; color: var(--muted-2); transition: transform .15s ease;
}
.ui .fr-ch.abierto { transform: rotate(90deg); }
.ui .fr-t { grid-column: 2; grid-row: 1; min-width: 0; display: flex; flex-direction: column; }
.ui .fr-nom {
    font-size: 12.5px; font-weight: 600; color: var(--ink);
    line-height: 1.35; overflow-wrap: anywhere;
}
.ui .fr-nom em {
    font-style: normal; font-weight: 500; color: var(--muted-2);
    font-size: 10.5px; margin-left: 5px;
}
.ui .fr-sub {
    font-size: 10.5px; font-weight: 500; color: var(--muted);
    line-height: 1.4; font-variant-numeric: tabular-nums;
}
.ui .fr-bar {
    grid-column: 3; grid-row: 1;
    display: block; height: 10px; border-radius: 999px;
    background: var(--grid); overflow: hidden;
}
.ui .fr-bar > i { display: block; height: 100%; min-width: 2px; border-radius: 999px; background: var(--sev-3); }
.ui .fr-v {
    grid-column: 4; grid-row: 1; min-width: 66px; text-align: right;
    font-size: 12.5px; font-weight: 600; font-variant-numeric: tabular-nums;
}
.ui .fr-p {
    grid-column: 5; grid-row: 1; min-width: 44px; text-align: right;
    font-size: 10.5px; font-weight: 500; color: var(--muted-2);
    font-variant-numeric: tabular-nums;
}

/* El cuerpo de un nodo abierto: sangra un escalón y lleva un filete que dice
   hasta dónde llega la rama. Sin él, cuatro niveles de sangría se leen como
   cuatro listas pegadas. */
.ui .fr-b {
    padding: 2px 0 8px 14px; margin-left: 6px;
    border-left: 1px solid var(--line-soft);
    display: flex; flex-direction: column; gap: 2px; min-width: 0;
}
.ui .fr-cruz { align-self: flex-start; margin: 2px 0 6px; }
.ui .fr-cruz.on { border-color: var(--verde); color: var(--verde-d); }
.ui .fr-um { font-size: 11px; font-weight: 500; color: var(--sev-3); line-height: 1.5; margin-bottom: 4px; }
.ui .fr-wos { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.ui .fr-ver { margin-left: auto; }

/* En teléfono la barra baja a su propio renglón: a 390 px, cinco columnas dejan
   el nombre en 90 px y la barra en 40 — dos datos ilegibles para que entre un
   tercero. Mismo criterio que las filas apiladas del panel. */
@container (max-width: 560px) {
    .ui .fr-h { grid-template-columns: 15px minmax(0, 1fr) auto auto; }
    .ui .fr-bar { grid-column: 2 / -1; grid-row: 2; height: 8px; }
    .ui .fr-v { grid-column: 3; grid-row: 1; }
    .ui .fr-p { grid-column: 4; grid-row: 1; }
}

/* ── La hoja de «Más» ─────────────────────────────────────────────────────
   La quinta pestaña no navega: abre esto. Es la puerta de desborde de la
   navegación —de tres a cinco pestañas manda la barra, el resto va detrás de
   una sola puerta— y con ella el encabezado de cada pantalla se quedó con un
   solo icono en lugar de cinco.

   Vive fuera de `.ui` (es del layout, como la barra), así que no puede usar
   `.ui .sheet`: se declara acá con los mismos tokens, que le llegan por
   `.ui-shell`.

   Rejilla de dos columnas y no lista de filas: son de seis a nueve destinos,
   y en dos columnas entran todos sin desplazar en un teléfono de 390. */
.lcm-mas-bd {
    position: fixed; inset: 0; z-index: 60;
    background: rgba(10, 15, 20, .5);
    display: flex; align-items: flex-end; justify-content: center;
    animation: lcm-mas-velo .16s ease both;
}
.lcm-mas {
    width: 100%; max-width: var(--lcm-shell-max, 560px);
    background: var(--canvas); color: var(--ink);
    border-radius: 20px 20px 0 0;
    padding: 10px 14px calc(16px + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -14px 44px rgba(0, 0, 0, .28);
    max-height: 86vh; overflow-y: auto;
    animation: lcm-mas-sube .2s cubic-bezier(.16, 1, .3, 1) both;
}
@keyframes lcm-mas-velo { from { opacity: 0; } to { opacity: 1; } }
@keyframes lcm-mas-sube { from { transform: translateY(14px); } to { transform: none; } }
/* El tirador: dice que la hoja se cierra tirándola hacia abajo aunque el gesto
   no esté programado —tocar afuera hace lo mismo— y da el canto superior. */
.lcm-mas-tira {
    display: block; width: 38px; height: 4px; margin: 0 auto 12px;
    border-radius: 999px; background: var(--line-soft);
}
.lcm-mas-h { padding: 0 6px 12px; }
.lcm-mas-h b { display: block; font-size: 15px; font-weight: 600; line-height: 1.25; }
.lcm-mas-h span { display: block; margin-top: 2px; font-size: 11.5px; color: var(--muted); }
.lcm-mas-g { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
/* Las tejas van sobre `--sunken` y no sobre `--surface`, y la razon es que está
   hoja vive FUERA de `.ui`: los tokens los resuelve `.ui-shell`, que declara los
   valores de escritorio —ahí `--surface` es blanco— y sobre una hoja blanca las
   tejas quedaban invisibles. `--sunken` se lee en los dos temas. */
.lcm-mas-i {
    display: flex; align-items: center; gap: 10px; min-width: 0;
    padding: 12px 12px; border-radius: var(--r-m);
    background: var(--sunken); color: var(--ink); text-decoration: none;
    font-size: 13px; font-weight: 500; line-height: 1.3;
}
.lcm-mas-i:active { filter: brightness(.96); }
.lcm-mas-i.on { box-shadow: inset 0 0 0 1.5px var(--verde); color: var(--verde-d); }
.lcm-mas-ic {
    flex-shrink: 0; width: 32px; height: 32px; border-radius: 9px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--surface); color: var(--muted);
}
.lcm-mas-i.on .lcm-mas-ic { background: var(--verde-l); color: var(--verde-d); }
.lcm-mas-t { min-width: 0; overflow-wrap: anywhere; }
/* La rama es una teja que no lleva a ningún lado: abre las suyas debajo, en la
   misma rejilla. Se distingue por el chevrón, y sus hijas por el filete del
   canto — el área de toque de una teja no se recorta. */
.lcm-mas-rama {
    width: 100%; border: 0; cursor: pointer; text-align: left;
    font-family: inherit; font-size: 13px; font-weight: 500; line-height: 1.3;
}
.lcm-mas-chev { margin-left: auto; flex-shrink: 0; color: var(--muted); display: inline-flex; }
.lcm-mas-rama.abierta { grid-column: 1 / -1; }
.lcm-mas-sub {
    grid-column: 1 / -1;
    display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
    margin-left: 4px; padding-left: 14px;
    border-left: 2px solid var(--line);
}

/* Cerrar sesión no es un destino: renglón propio, filete de por medio y la tinta
   de lo que no se deshace. Mismo alto de toque que una teja. */
.lcm-mas-salir {
    display: flex; align-items: center; gap: 10px; width: 100%;
    margin-top: 10px; padding: 12px 12px;
    background: none; border: 0; border-top: 1px solid var(--line-soft);
    border-radius: 0;
    font-family: inherit; font-size: 13px; font-weight: 600; line-height: 1.3;
    color: var(--rojo); text-align: left; cursor: pointer;
}
.lcm-mas-salir:disabled { cursor: default; opacity: .6; }
.lcm-mas-salir .lcm-mas-ic { background: var(--rojo-l); color: var(--rojo); }


/* Botón flotante del sistema: la misma acción primaria que el topbar pinta como
   botón, que es lo que hace la maqueta. Va absoluto dentro del shell —el
   ancestro posicionado— así que acompaña la columna centrada sin hacer cuentas
   con la ventana. Es del teléfono: desde 700 px lo reemplaza el del topbar. */
.ui-fab {
    display: none;
    position: absolute; right: 16px; bottom: 16px; z-index: 45;
    width: 54px; height: 54px; border-radius: 999px;
    border: none; background: var(--verde); color: #fff;
    align-items: center; justify-content: center;
    box-shadow: 0 8px 20px rgba(18,24,31,.24);
    cursor: pointer; text-decoration: none;
}
.ui-shell:has(.ui) .ui-fab { display: flex; }
/* Con barra inferior hay que subirlo por encima de ella. */
.ui-shell:has(.lcm-tabs) .ui-fab { bottom: 84px; }
[data-tema="oscuro"] .ui-fab { color: #10161b; }

/* Las capas de ATRÁS también van oscuras, y esto es lo que mata el destello al
   cambiar de sección.
   `.lcm-body` se recrea en cada navegación —lleva `@key` por ruta— así que su
   animación `lcmFadeIn` corre cada vez, y mientras dura el fundido la capa es
   semitransparente y se ve lo que hay detrás: `body`, `.lcm-app` y
   `.lcm-mobile-shell`, que se pintan con `--lcm-page-bg` (#f8fafc) del sistema
   anterior, sin variante oscura. El resultado era un flash claro por debajo del
   contenido en cada cambio de pantalla.
   Va con el valor literal del lienzo oscuro y no con `var(--canvas)` porque esos
   tres elementos están fuera de `.ui`, que es donde se declara el token. */
[data-tema="oscuro"] body,
[data-tema="oscuro"] .lcm-app,
[data-tema="oscuro"] .lcm-mobile-shell { background: #0f151b; }
/* Volver arriba. Aparece cuando el desplazamiento ya es largo —el umbral vive en
   el listener de index.html, que le pone `.is-abajo` al scroller— y desaparece al
   volver. El botón es hermano de `.lcm-body`, así que el selector es de hermanos:
   sin JavaScript propio, sin estado en Blazor.

   NO se superpone con el botón flotante de «Nueva OT» de Co y GM: cuando ese
   botón existe, este se apila ENCIMA. La detección va con `:has(.ui-fab)`, que es
   fiable porque ShellFab no pinta nada cuando el rol no tiene acción primaria —no
   es un botón oculto, es un botón ausente—. Y los quiebres van por MEDIA query y
   no por `:has()` de la barra inferior, porque tanto la barra como el flotante
   siguen en el DOM en escritorio, solo que en `display: none`: preguntar por su
   presencia daría verdadero donde no se ven. */
.subir {
    display: none;
    position: absolute; right: 16px; bottom: 16px; z-index: 44;
    width: 44px; height: 44px; border-radius: 999px;
    border: 1px solid var(--line);
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    color: var(--ink-2);
    /* Solo la sombra del sistema: un anillo con un rgba literal no seguiría al
       tema oscuro, que es el defecto que tenía la barra inferior. */
    box-shadow: var(--sh-m);
    align-items: center; justify-content: center;
    cursor: pointer;
}
/* Aparece cuando SU scroller está lejos del tope. Dos selectores porque hay dos
   clases de scroller: el cuerpo de la página y los que una vista declara con
   `data-scroller` —la agenda del calendario—. En los dos casos el botón es el
   hermano siguiente del contenedor que se desplaza. */
.lcm-body.is-abajo ~ .subir,
[data-scroller].is-abajo ~ .subir { display: flex; }
.subir:hover { color: var(--verde-d); border-color: var(--verde-b); }

@media (max-width: 699px) {
    /* Por encima de la barra inferior. */
    .ui-shell:has(.lcm-tabs) .subir { bottom: calc(var(--alto-tabs) + 14px); }
    /* Y por encima del flotante de acción primaria, que se apoya en la misma
       barra y mide 54. */
    .ui-shell:has(.lcm-tabs):has(.ui-fab) .subir { bottom: calc(var(--alto-tabs) + 82px); }
    /* Con barra de acción en la pantalla, el botón NO se pinta.
     *
     * Antes se subía 76 px por encima de la barra inferior, con la cuenta hecha
     * sobre una barra de acción de un renglón. La de los cheques lleva cinco
     * botones que envuelven en tres renglones —«Limpiar», «Abrir», «Imprimir»,
     * «Ver documentos de OT», «Anular»— y el botón redondo caía justo encima de
     * ellos: dos blancos de toque peleando el mismo pixel, y el de arriba tapando
     * una acción que sí decide algo. Ningún número fijo sirve, porque el alto de
     * esa barra depende de cuántas acciones traiga la pantalla.
     *
     * Con barra de acción, ese rincón es de ella. Volver arriba sigue siendo un
     * gesto —el pulgar llega al tope— y el encabezado sigue ahí. */
    .lcm-body.is-abajo:has(.bar-acc) ~ .subir { display: none; }
    /* Sin barra inferior el flotante está en 16. */
    .ui-shell:not(:has(.lcm-tabs)):has(.ui-fab) .subir { bottom: 84px; }
}
@media (min-width: 700px) {
    /* En escritorio no hay flotante: la acción primaria vive en el topbar. */
    .subir { right: 26px; bottom: 26px; }
    /* El de la agenda del calendario vive dentro de SU columna y no en el canto de
       la pantalla, así que se acerca al borde de su panel. No compite con el
       flotante de «Nueva OT»: ese scroller solo existe desde 1080 px de contenedor
       y ahí el flotante ya no se pinta. Un poco de aire a la derecha para no
       quedar encima de la barra de desplazamiento del propio panel. */
    .subir-agenda { right: 18px; bottom: 14px; width: 40px; height: 40px; }
}

/* Esperando los catálogos maestros: mismo hueco, sin promesa de que abra. */
.ui-fab.off {
    background: var(--sunken); color: var(--muted-2);
    box-shadow: none; cursor: progress; pointer-events: none;
}

/* Quiebres del shell de escritorio. Van por media query a propósito (ver la
   nota del arranque de la sección) y solo sobre las vistas rediseñadas:

     < 700   teléfono — barra inferior, encabezado con volver, sin riel
     ≥ 700   riel de iconos (68 px) + topbar; sin barra inferior ni encabezado
     ≥ 1080  el riel se abre a 216 px con etiquetas, contadores y usuario

   Aplica sin importar de qué layout cuelgue la vista: una subpágina también
   lleva riel y topbar, y ahí el volver es el primer tramo de la miga. */
@media (min-width: 700px) {
    .ui-shell:has(.ui) .ui-rail { display: flex; }
    .ui-shell:has(.ui) .ui-top { display: flex; }
    .lcm-mobile-shell:has(.ui) .lcm-tabs { display: none; }
    /* La hoja de «Más» es del teléfono: en escritorio el riel ya lista los
       mismos destinos y la barra que la abre no se pinta. */
    .lcm-mas-bd { display: none; }
    /* El nombre de la sección lo dice ahora el topbar; el título grande de la
       página y sus iconos son del encabezado de teléfono. */
    .ui-shell:has(.ui) .ui-mtop { display: none; }
    /* El riel y el topbar son de la VENTANA, no de la página: el envase llega
       al borde de la pantalla. Vale también para las vistas angostas —el
       rechazo, el acceso—: encogerles el shell a 548 px dejaba un topbar de
       480 y la miga se partía en seis renglones. Lo que se angosta es el
       CUERPO, no el envase (regla de abajo). */
    .lcm-mobile-shell:has(.ui-shell .ui) { max-width: 100%; }
    /* La vista sin ensanchar conserva la columna con la que fue dibujada,
       centrada en la que ahora sobra. El ancho lo sigue diciendo lcm.css, así
       que sus container queries siguen midiendo lo mismo que antes del riel. */
    .ui-shell .lcm-body > .ui:not(.ancho) {
        max-width: var(--lcm-shell-max);
        width: 100%;
        margin-inline: auto;
    }
    /* La acción primaria ya está en el topbar. */
    .ui-shell:has(.ui) .ui-fab { display: none; }
    /* LA FRANJA. Entre 700 y ~777 px de ventana el riel ya está y el encabezado
       de teléfono ya no, pero la columna —68 px menos por el riel y 10 menos por
       la barra de desplazamiento— todavía no llega a los 700 px que sus
       container queries esperan, así que el CUERPO se pinta en modo teléfono.
       Se deja así a propósito: el riel aparece donde lo pone la maqueta, y la
       alternativa —esperar a los 778 px— es un número sin significado que se
       desajusta el día que el riel o la barra de desplazamiento cambien de
       ancho. Lo que sí corrige la franja es su único defecto real, el ritmo
       vertical: el relleno del cuerpo era del teléfono, que arriba tiene un
       encabezado grande y abajo una barra de pestañas, y acá no hay ninguno de
       los dos. Va anidado en un container query para no pisar el relleno que la
       propia columna se da cuando sí es de escritorio. */
    @container (max-width: 699px) {
        .ui-shell:has(.ui) .ui-pad { padding-top: 18px; padding-bottom: 40px; }
        .ui-shell:has(.ui) .pwa { bottom: 14px; margin-bottom: 18px; }
    }
}

@media (min-width: 1080px) {
    .ui-shell:has(.ui) .ui-rail { width: 216px; }
    /* Con el pill del buscador en sus 320 px, la frase larga entra. */
    .ui-top .ui-search .larga { display: inline; }
    .ui-top .ui-search .corta { display: none; }
    .ui-shell:has(.ui) .ui-rail-name,
    .ui-shell:has(.ui) .ui-nav-t,
    .ui-shell:has(.ui) .ui-who { display: block; }
    .ui-shell:has(.ui) .ui-nav-c { display: inline-block; margin-left: auto; }
    /* Con el riel angosto el submenú es una columna de iconos y el chevrón no
       cabe; abierto, la sangría es lo que dice de qué cuelgan. */
    .ui-shell:has(.ui) .ui-rama-chev {
        display: inline-flex; align-items: center; margin-left: auto; color: var(--muted-2);
    }
    .ui-shell:has(.ui) .ui-hijo { padding-left: 24px; }
}

/* Panel de contexto — solo en monitor (≥ 1440 px de contenedor). */
.ui-split { display: flex; min-height: 0; flex: 1; min-width: 0; }
/* Columna flex, igual que `.ui`. La barra de acción se pega al pie con
   `margin-top: auto`, y eso solo empuja dentro de un contenedor flex en columna:
   en Atender y en Evaluación funciona porque ahí la barra es hija directa de
   `.ui`, pero en el detalle de OT vive dentro de `.ui-main` y quedaba a media
   pantalla, encima del contenido. */
.ui-split > .ui-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* El panel de contexto se queda arriba al desplazar: es la vista previa de la fila
   seleccionada, y su razón de ser es leerla SIN perder de vista la lista. Si se va
   con el desplazamiento hay que subir para consultarlo, que es justo lo que venía
   a evitar.
   `align-self: flex-start` es obligatorio: como hijo de un flex row estirado a
   toda la altura de la línea, un elemento sticky no tiene hacia dónde moverse. */
.ui-ctx {
    display: none; width: 344px; flex-shrink: 0;
    position: sticky; top: 0; align-self: flex-start;
    max-height: 100dvh;
    border-left: 1px solid var(--line); background: var(--surface);
    padding: 20px; overflow-y: auto;
    flex-direction: column; gap: 15px;
}

/* ── 3 · Primitivas ───────────────────────────────────────────────── */

/* Escala de títulos. La jerarquía la hacen el TAMAÑO y el COLOR, no el peso: los
   tres niveles viven en 600, y lo que los separa de su texto es cuánto miden y
   qué tan oscuros son. Con peso 800 en cada nivel la pantalla parecía subrayada
   entera y no se distinguía un título de una cifra. */
.ui .h1 { font-size: 27px; font-weight: 600; letter-spacing: -.028em; line-height: 1.15; margin: 0; }
.ui .h2 { font-size: 20px; font-weight: 600; letter-spacing: -.018em; line-height: 1.3; margin: 0; }
.ui .h3 { font-size: 15px; font-weight: 600; letter-spacing: -.008em; line-height: 1.4; margin: 0; }
.ui .lead { font-size: 13.5px; color: var(--muted); line-height: 1.65; margin: 6px 0 0; font-weight: 400; }
/* El rótulo de un bloque se dice, no se grita. Era 9,5 px en peso 900, en
   MAYÚSCULAS y con 1,4 px de tracking: a ese tamaño las versalitas se leen letra
   por letra, y el peso las ponía a competir con el dato que anuncian. Ahora es
   texto normal en gris tenue — el tamaño y el color ya dicen que es secundario, y
   para eso no hace falta deformar la palabra. */
.ui .eyebrow {
    font-size: 11.5px; font-weight: 500; letter-spacing: 0;
    text-transform: none; color: var(--muted); line-height: 1.5;
}
.ui .muted { color: var(--muted); }
.ui .small { font-size: 12.5px; line-height: 1.6; }
.ui .tiny { font-size: 11.5px; line-height: 1.55; }
.ui .mono {
    font-family: var(--lcm-mono-font);
    font-size: 11.5px; font-weight: 500; color: var(--muted);
    letter-spacing: .2px; overflow-wrap: anywhere;
}
.ui .tnum { font-variant-numeric: tabular-nums; }
.ui .strong { font-weight: 600; }

.ui .sec { display: flex; flex-direction: column; gap: 9px; min-width: 0; }
.ui .sec-h { display: flex; align-items: baseline; gap: 9px; }
/* Los tres encabezados de bloque —`.sec-h`, `.banda-h`, `.card-h`— miden lo mismo
   y pesan lo mismo a propósito: son el MISMO nivel de la jerarquía, esté el título
   sobre el lienzo o dentro de la tarjeta. Antes uno decía 12,5 px / 900 con
   tracking suelto y otro 13,5 px / 800 con tracking negativo, y dos bloques
   hermanos se veían de rango distinto sin ninguna razón. */
.ui .sec-h h3 { font-size: 14.5px; font-weight: 600; letter-spacing: -.008em; margin: 0; line-height: 1.4; }
.ui .sec-h .n {
    font-size: 10.5px; font-weight: 600; color: var(--muted);
    background: var(--sunken); border-radius: 999px; padding: 2px 8px;
}
.ui .sec-h .act {
    margin-left: auto; font-size: 12px; font-weight: 600; color: var(--verde);
    cursor: pointer; text-decoration: none; background: none; padding: 0;
}

.ui .card {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-l); box-shadow: var(--sh-s);
    min-width: 0;
    /* `card` también es de bootstrap, y bootstrap le fija el color de texto de
       su tema claro. En tema oscuro eso dejaba a TODO el contenido de una
       tarjeta en 1.1:1 —invisible— por más que el contenedor del sistema tenga
       la tinta correcta: el color se hereda desde la tarjeta, no desde el
       contenedor. Con `inherit` la cadena vuelve a pasar por `--ink`. Es la
       tercera colisión del mismo tipo, después de `row` y de los `d-*`. */
    color: inherit;
}
/* Los rellenos suben: 14 px era el aire de una columna de 480 px. Los ejemplos
   respiran entre 20 y 24 px, y a ancho completo la diferencia es lo que separa un
   panel de una planilla. */
.ui .card.pad { padding: 18px; }
.ui .card.pad-l { padding: 22px; }
.ui .card.flat { box-shadow: none; }
.ui .card.soft { background: var(--sunken); border-color: transparent; box-shadow: none; }
.ui .card.acc-verde { border-left: 3px solid var(--verde); }
.ui .card.acc-ambar { border-left: 3px solid var(--ambar); }
.ui .card.acc-rojo  { border-left: 3px solid var(--rojo); }

/* Bloque con encabezado propio: el título va DENTRO de la tarjeta, separado del
   cuerpo por un filete, y a la derecha su conteo y su enlace. Los hijos se
   llaman igual que en `.sec-h` (h3, .n, .act) a propósito: una sola forma de
   escribir «título de bloque» en toda la App, esté el título dentro de la
   tarjeta o sobre el lienzo.

   Una lista o una tabla adentro pierden su propio marco —ya lo pone la
   tarjeta— y solo la última redondea las esquinas de abajo. El radio interior
   descuenta el borde: con el mismo valor que la tarjeta queda un hilo de
   fondo asomando en la curva. No se usa `overflow: clip` en la tarjeta porque
   los desplegables (`.pop-p`) se abren hacia afuera y quedarían cortados. */
.ui .card-h {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 16px 20px; border-bottom: 1px solid var(--line-soft);
}
.ui .card-h h3 { font-size: 14.5px; font-weight: 600; letter-spacing: -.008em; margin: 0; line-height: 1.4; }
.ui .card-h .n {
    font-size: 10.5px; font-weight: 600; color: var(--muted);
    font-variant-numeric: tabular-nums;
    background: var(--sunken); border-radius: 999px; padding: 2px 8px;
}
.ui .card-h .act {
    margin-left: auto; font-size: 12px; font-weight: 600; color: var(--verde);
    cursor: pointer; text-decoration: none; background: none; padding: 0;
    font-family: inherit; line-height: 1.4;
}
.ui .card-h .act:hover { color: var(--verde-d); text-decoration: underline; }
.ui .card-b { padding: 18px 20px 20px; display: flex; flex-direction: column; gap: 15px; min-width: 0; }
.ui .card-f {
    padding: 14px 20px 16px; border-top: 1px solid var(--line-soft);
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    font-size: 11.5px; font-weight: 500; color: var(--muted-2); line-height: 1.5;
}
.ui .card > .lista,
.ui .card > .tbl-wrap { border: none; box-shadow: none; border-radius: 0; }
.ui .card > .lista:last-child,
.ui .card > .tbl-wrap:last-child {
    border-radius: 0 0 calc(var(--r-l) - 1px) calc(var(--r-l) - 1px);
}

/* Rejilla de cifras en tarjeta — el banco de indicadores de una pantalla de
   inicio o de un panel.

   Las columnas las reparte `auto-fit` y no una cuenta por tramo: el marco
   ahora llega al borde de la pantalla, así que el número de columnas depende
   del ancho real y no de tres quiebres escritos a mano. Cada tarjeta pide
   210 px; lo que sobra se reparte por igual.

   Anatomía: `.kpi-i` el cuadro del icono en su tinta, `.kpi-l` el rótulo,
   `.kpi-v` la cifra y al pie un `.chip` con la nota que la califica. La nota
   es dato, no adorno: si no hay algo cierto que decir, no se pinta el chip. */
/* El `min()` del mínimo no es adorno: `minmax(210px, 1fr)` a secas NO baja de
   210 px, así que en un contenedor más angosto que eso la rejilla se sale de la
   pantalla en vez de encogerse. Con `min(210px, 100%)` el mínimo cede cuando no
   cabe y la columna queda de una sola tarjeta. */
.ui .kpis {
    display: grid; gap: 12px; min-width: 0;
    grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
}
.ui .kpi {
    display: flex; flex-direction: column; gap: 13px; min-width: 0;
    padding: 19px 20px 18px;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-l); box-shadow: var(--sh-s);
    color: inherit; text-decoration: none; text-align: left; font-family: inherit;
}
.ui a.kpi, .ui button.kpi { cursor: pointer; }
.ui a.kpi:hover, .ui button.kpi:hover { border-color: var(--verde-b); box-shadow: var(--sh-m); }
.ui a.kpi:hover .kpi-v, .ui button.kpi:hover .kpi-v { color: var(--verde-d); }

/* La tarjeta con DOS destinos: la cifra lleva a su lista y el chip del pie a la
   suya, que es un recorte distinto («1 vence hoy» dentro de «Vencidas» no es el
   mismo conjunto). No se puede anidar un enlace dentro de otro, así que la
   tarjeta deja de ser el enlace: el destino principal lo cubre un enlace
   estirado —el mismo patrón de `.li-ir` en las listas— y el chip queda por
   encima con su propio toque.

   El enlace estirado no tiene texto: su nombre viaja en aria-label.

   El chip clicable se selecciona POR ELEMENTO (`a.chip`) y no por una clase
   propia. Una clase suelta acá es una colisión esperando: el sistema ya tiene
   `.toca` para la tarjeta de «tu turno», que se declara más abajo y por tanto
   gana, y un chip con ese nombre heredaba su fondo, su borde y su ancho
   completo — un cuadro blanco del ancho de la tarjeta en lugar de una
   pastilla. */
.ui .kpi.dos-destinos { position: relative; }
.ui .kpi-ir { position: absolute; inset: 0; border-radius: inherit; }
.ui .kpi.dos-destinos:hover { border-color: var(--verde-b); box-shadow: var(--sh-m); }
.ui .kpi.dos-destinos:hover .kpi-v { color: var(--verde-d); }
.ui .kpi > a.chip { position: relative; z-index: 1; text-decoration: none; cursor: pointer; }
.ui .kpi > a.chip:hover { border-color: currentColor; }
.ui .kpi-h { display: flex; align-items: center; gap: 10px; min-width: 0; }
.ui .kpi-i {
    width: 34px; height: 34px; border-radius: 10px; flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--sunken); color: var(--muted);
}
.ui .kpi-i.azul    { background: var(--azul-l);    color: var(--azul); }
.ui .kpi-i.ambar   { background: var(--ambar-l);   color: var(--ambar); }
.ui .kpi-i.rojo    { background: var(--rojo-l);    color: var(--rojo); }
.ui .kpi-i.verde   { background: var(--verde-l);   color: var(--verde-d); }
.ui .kpi-i.exito   { background: var(--exito-l);   color: var(--exito); }
.ui .kpi-i.violeta { background: var(--violeta-l); color: var(--violeta); }
.ui .kpi-i.indigo  { background: var(--indigo-l);  color: var(--indigo); }
/* El rótulo envuelve en dos renglones antes que recortarse: es el nombre del
   dato, y un nombre a medias no se puede leer. */
.ui .kpi-l { font-size: 12px; font-weight: 500; color: var(--muted); line-height: 1.35; min-width: 0; }
/* La cifra en 600 y no más: a 29 px con tracking cerrado, el tamaño ya la pone al
   frente. El peso de más solo la engorda. */
.ui .kpi-v {
    font-size: 30px; font-weight: 600; letter-spacing: -.035em; line-height: 1.05;
    font-variant-numeric: tabular-nums; overflow-wrap: break-word;
}
.ui .kpi-v.chica { font-size: 21px; }
.ui .kpi.alerta .kpi-v { color: var(--ambar); }
.ui .kpi.urg .kpi-v { color: var(--rojo); }
.ui .kpi.exito .kpi-v { color: var(--exito); }
/* La nota del pie se ancla abajo para que tarjetas de distinto alto de rótulo
   alineen sus chips en la misma línea. Va en chip cuando califica la cifra
   («2 vencen hoy») y en texto llano cuando explica de dónde sale («últimos
   30 días»): una frase de doce palabras dentro de una pastilla se lee como un
   párrafo con borde. */
.ui .kpi > .chip { align-self: flex-start; margin-top: auto; max-width: 100%; }
.ui .kpi-f {
    font-size: 11px; font-weight: 600; color: var(--muted-2);
    line-height: 1.45; margin-top: auto;
}
.ui .chip.cuadro { border-radius: 8px; padding: 4px 9px; }

/* Rejillas de bloque. Solo se vuelven rejilla en monitor (ver el container
   query de 1080 px); debajo de eso los bloques se APILAN, y se apilan con
   separación. Sin esta declaración base dos tarjetas hermanas quedaban pegadas
   por el canto en teléfono y en tableta, porque la rejilla —y con ella su
   `gap`— solo existía a partir de 1080 px. */
.ui .g2, .ui .g3, .ui .g-main, .ui .g-form {
    display: flex; flex-direction: column; gap: 16px; min-width: 0;
}

.ui .stack { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.ui .stack-s { display: flex; flex-direction: column; gap: 6px; }
.ui .row { display: flex; align-items: center; gap: 10px; margin: 0; }
/* bootstrap.min.css se carga antes y su `.row > *` le pone width: 100%, gotera
   lateral y margen superior a TODO hijo de una fila. El prefijo `.ui` gana en
   `.row`, pero los hijos no tenían contraparte: cualquier fila de la maqueta
   con dos elementos los apilaba a lo ancho, uno por renglón.
   Va con `:where()` para que el selector valga 0,1,0: le basta para ganarle a
   bootstrap —que se carga antes— y no puede pisarle el relleno propio a
   ninguna clase del sistema, sin importar en qué orden se declaren. */
.ui :where(.row) > * {
    width: auto; max-width: none;
    padding-left: 0; padding-right: 0; margin-top: 0;
}
.ui .row-t { display: flex; align-items: flex-start; gap: 10px; margin: 0; }
.ui .wrapr { flex-wrap: wrap; }
.ui .grow { flex: 1; min-width: 0; }
.ui .g8 { gap: 8px; } .ui .g12 { gap: 12px; } .ui .g16 { gap: 16px; }

/* El topbar entra en el ámbito del botón porque vive FUERA de `.ui` —es del
   layout— y la acción primaria que pinta es el mismo botón de la maqueta
   (`btn sm`). Sin esto habría que redibujarlo con otro nombre, que es como
   nacen las dos verdades. */
.ui .btn,
.ui-top .btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    height: 40px; padding: 0 18px; border-radius: var(--r-m);
    border: 1px solid transparent; background: var(--verde); color: #fff;
    font-family: inherit; font-size: 13.5px; font-weight: 500; cursor: pointer;
    text-decoration: none; line-height: 1.2; text-align: center;
}
[data-tema="oscuro"] .btn,
[data-tema="oscuro"] .ui-top .btn { color: #10161b; }
/* Todo lo que se rellena con `--verde` lleva tinta OSCURA en tema oscuro, igual
   que el botón: ahí el verde de marca se aclara a #6fa285 y el blanco encima cae
   a 2,3:1. El botón ya lo resolvía; estos se habían quedado atrás. */
[data-tema="oscuro"] .chip.solida,
[data-tema="oscuro"] .chips button.on,
[data-tema="oscuro"] .pill.on,
[data-tema="oscuro"] .ficha.on,
[data-tema="oscuro"] .opt-g.on .opt-g-i,
[data-tema="oscuro"] .radio.on,
[data-tema="oscuro"] .li-swipe .acc .a1 { color: #10161b; }
.ui .btn.lg { height: 44px; font-size: 13.5px; padding: 0 20px; }
.ui .btn.sm,
.ui-top .btn.sm { height: 32px; font-size: 12px; padding: 0 12px; border-radius: 9px; }
.ui .btn.full { width: 100%; }
.ui .btn.ghost { background: var(--surface); border-color: var(--line); color: var(--ink); }
.ui .btn.subtle { background: var(--sunken); border-color: transparent; color: var(--ink-2); }
.ui .btn.danger { background: var(--rojo); color: #fff; }
.ui .btn.quiet { background: transparent; border-color: transparent; color: var(--verde); }
.ui .btn[disabled], .ui .btn.off,
.ui-top .btn[disabled], .ui-top .btn.off { opacity: .45; cursor: default; }

/* El chip es una etiqueta, no un botón: peso normal y algo más de aire. En 11 px
   con peso 800 una fila con tres chips tenía tres manchas oscuras compitiendo con
   el título del registro. */
.ui .chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 11px; border-radius: 999px;
    font-size: 11.5px; font-weight: 500; line-height: 1.5;
    background: var(--sunken); color: var(--muted); border: 1px solid transparent;
}
.ui .chip .d { width: 6px; height: 6px; border-radius: 999px; background: currentColor; flex-shrink: 0; }
.ui .chip.verde  { background: var(--verde-l); color: var(--verde-d); border-color: var(--verde-b); }
.ui .chip.ambar  { background: var(--ambar-l); color: var(--ambar); border-color: var(--ambar-b); }
.ui .chip.rojo   { background: var(--rojo-l);  color: var(--rojo);  border-color: var(--rojo-b); }
.ui .chip.azul   { background: var(--azul-l);  color: var(--azul);  border-color: var(--azul-b); }
.ui .chip.exito  { background: var(--exito-l); color: var(--exito); border-color: var(--exito-b); }
.ui .chip.violeta{ background: var(--violeta-l); color: var(--violeta); }
.ui .chip.indigo { background: var(--indigo-l); color: var(--indigo); border-color: var(--indigo-b); }
.ui .chip.solida { background: var(--verde); color: #fff; border-color: transparent; }

/* Dentro de una tabla el chip va PLANO, como en la lista de teléfono.

   Una tabla de treinta filas con dos pastillas rellenas por fila es una grilla de
   manchas de color: el relleno se lee como jerarquía y acá todas las filas valen
   igual. El color del texto y el punto ya dicen prioridad y estado; el fondo solo
   agregaba peso. La versión rellena sigue viva donde el chip es una etiqueta
   suelta —cabecera de una OT, ficha del perfil—, que es donde sí destaca. */
.ui .tbl .chip {
    background: none; border-color: transparent;
    padding-left: 0; padding-right: 0;
}
.ui .tbl .chip.solida { background: var(--verde); padding: 3px 9px; }

.ui .pill {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px; border-radius: 999px;
    border: 1px solid var(--line); background: var(--surface); color: var(--muted);
    font-family: inherit; font-size: 11.5px; font-weight: 600;
    cursor: pointer; line-height: 1.4;
}
/* «Activo» se dice de UNA sola manera en toda la app: el verde de marca.
   La pastilla se rellenaba con `--ink` —tinta sólida, negra en claro— mientras el
   chip y el segmentado de opciones usaban el verde, así que el mismo estado tenía
   dos aspectos según qué control lo mostrara. Y en oscuro `--ink` es casi blanco:
   el filtro aplicado quedaba como una losa blanca sobre pantalla negra, legible
   pero gritando. Con el verde entra en la misma familia que `.chip.solida` y
   `.chips button.on`, y hereda su regla de tinta oscura. */
.ui .pill.on { background: var(--verde); color: #fff; border-color: var(--verde); }

.ui .avatar {
    width: 38px; height: 38px; border-radius: 999px; flex-shrink: 0;
    background: var(--sunken); color: var(--ink-2);
    display: flex; align-items: center; justify-content: center;
    font-size: 12.5px; font-weight: 600;
}
.ui .avatar.sq { border-radius: 11px; }
.ui .avatar.verde { background: var(--verde-l); color: var(--verde-d); }
.ui .avatar.azul { background: var(--azul-l); color: var(--azul); }
.ui .avatar.ambar { background: var(--ambar-l); color: var(--ambar); }
.ui .avatar.ink { background: var(--ink); color: var(--surface); }
.ui .avatar.lg { width: 52px; height: 52px; font-size: 16px; }

/* Ficha de datos: la separación entre pares la hace el espaciado, nunca
   una línea por fila — si no, cualquier bloque de datos se lee como una
   tabla de Excel. */
.ui .meta-list { display: flex; flex-direction: column; gap: 11px; margin: 0; }
.ui .meta { display: flex; justify-content: space-between; gap: 14px; align-items: baseline; }
.ui .meta dt { font-size: 11.5px; font-weight: 500; color: var(--muted-2); margin: 0; line-height: 1.45; }
.ui .meta dd { font-size: 12.5px; font-weight: 600; margin: 0; text-align: right; line-height: 1.4; }
.ui .meta dd em {
    display: block; font-style: normal; font-size: 11px; font-weight: 600;
    color: var(--muted-2); margin-top: 1px;
}

.ui .field { display: block; margin-bottom: 18px; }
/* La etiqueta de un campo es una PREGUNTA que la persona tiene que leer entera
   («¿El activo está disponible y en condiciones para intervenir?»). En 10 px, peso
   900 y versalitas con 1,1 px de tracking, una frase así se vuelve un bloque de
   ruido: se lee dos veces y se entiende a la tercera. Ahora es texto llano, del
   tamaño de lo que se va a escribir debajo. */
.ui .field > .lb {
    display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
    font-size: 13px; font-weight: 500; letter-spacing: 0;
    text-transform: none; color: var(--ink-2); margin-bottom: 8px; line-height: 1.5;
}
.ui .field > .lb .hint {
    text-transform: none; letter-spacing: 0; font-weight: 500;
    color: var(--muted-2); font-size: 10.5px;
}
/* Los campos suben a 44 px y a peso normal. Un input de 40 px con el texto en
   peso 500 se leía como una etiqueta rellena y no como algo donde se escribe. */
.ui .input {
    width: 100%; min-height: 44px; padding: 11px 14px;
    border: 1px solid var(--line); border-radius: var(--r-m);
    background: var(--surface); color: var(--ink);
    font-family: inherit; font-size: 14px; font-weight: 400; line-height: 1.55;
}
.ui textarea.input { resize: vertical; }
.ui .input:focus { outline: none; border-color: var(--verde); }
.ui .input.ta { min-height: 92px; }
.ui .input.ro {
    background: var(--sunken); border-color: transparent; font-weight: 500;
    display: flex; align-items: center; gap: 8px;
}
.ui .help { font-size: 11px; color: var(--muted-2); margin-top: 5px; line-height: 1.5; }
.ui .help.err { color: var(--rojo); font-weight: 500; }
.ui .count {
    font-size: 11px; color: var(--muted-2); text-align: right;
    margin-top: 4px; font-variant-numeric: tabular-nums;
}

/* ── 4 · Elección directa ─────────────────────────────────────────── */

.ui .seg { display: flex; gap: 4px; padding: 4px; background: var(--sunken); border-radius: 11px; }
.ui .seg button {
    flex: 1; background: transparent; cursor: pointer;
    padding: 8px 10px; border-radius: 8px;
    font-family: inherit; font-size: 12.5px; font-weight: 600;
    color: var(--muted); line-height: 1.3;
}
.ui .seg button.on { background: var(--surface); color: var(--ink); box-shadow: var(--sh-s); }

.ui .chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ui .chips button {
    border: 1px solid var(--line); background: var(--surface); color: var(--ink-2);
    padding: 7px 12px; border-radius: 999px;
    font-family: inherit; font-size: 12px; font-weight: 500;
    cursor: pointer; line-height: 1.35;
}
.ui .chips button.on { background: var(--verde); border-color: var(--verde); color: #fff; }

.ui .radio {
    width: 19px; height: 19px; border-radius: 999px; flex-shrink: 0;
    border: 2px solid var(--muted-2); background: var(--surface);
    display: flex; align-items: center; justify-content: center; color: #fff;
}
.ui .radio.on { border-color: var(--verde); background: var(--verde); }

/* Cuando hay pocas opciones no se esconden detrás de un selector: se
   muestran todas con su consecuencia escrita y se toca una. */
.ui .opt {
    display: flex; align-items: center; gap: 11px; width: 100%;
    padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--r-m);
    background: var(--surface); cursor: pointer; text-align: left;
    font-family: inherit; font-size: 13px; color: var(--ink); line-height: 1.45;
}
.ui .opt.on { border-color: var(--verde); background: var(--verde-l); }
.ui .opt .grow { font-weight: 600; }

.ui .opt-g {
    display: flex; flex-direction: column; gap: 4px; text-align: left;
    padding: 15px 16px 16px; border-radius: var(--r-l);
    border: 1.5px solid var(--line); background: var(--surface);
    color: var(--ink); cursor: pointer; font-family: inherit;
}
.ui .opt-g:hover { border-color: var(--verde-b); }
.ui .opt-g.on { border-color: var(--verde); background: var(--verde-l); }
.ui .opt-g-i {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; border-radius: 11px; margin-bottom: 6px;
    background: var(--sunken); color: var(--muted);
}
.ui .opt-g.on .opt-g-i { background: var(--verde); color: #fff; }
.ui .opt-g-t { font-size: 14px; font-weight: 600; line-height: 1.35; }
.ui .opt-g-s { font-size: 11.5px; font-weight: 600; color: var(--muted); line-height: 1.5; }
.ui .opt-g.on .opt-g-s { color: var(--verde-d); }

.ui .fichas { display: flex; flex-wrap: wrap; gap: 8px; }
.ui .ficha {
    padding: 10px 15px; border-radius: 999px;
    border: 1px solid var(--line); background: var(--surface);
    color: var(--ink-2); font-family: inherit;
    font-size: 12.5px; font-weight: 500; line-height: 1.35; cursor: pointer;
}
.ui .ficha:hover { border-color: var(--verde-b); }
.ui .ficha.on { background: var(--verde); border-color: var(--verde); color: #fff; }

/* Fila de acción: lleva a algún lado, no muestra un registro. Se apoya en
   el fondo hundido en vez de en un marco con sombra, para que no se lea
   como una tarjeta. */
.ui .lrow {
    display: flex; align-items: center; gap: 12px;
    padding: 13px 15px; background: var(--sunken);
    border-radius: var(--r-l);
    text-decoration: none; color: inherit;
    width: 100%; cursor: pointer; text-align: left; font-family: inherit;
}
.ui .lrow:hover { background: var(--verde-l); }
.ui .lrow .t { font-size: 13.5px; font-weight: 600; line-height: 1.35; }
.ui .lrow .s { font-size: 11.5px; color: var(--muted); margin-top: 2px; line-height: 1.45; }
.ui .lrow .n {
    font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums;
    background: var(--verde-l); color: var(--verde-d);
    border-radius: 999px; padding: 4px 11px; flex-shrink: 0;
}
.ui .lrow .n.cero { background: var(--sunken); color: var(--muted-2); }
.ui .chev { color: var(--muted-2); flex-shrink: 0; }

/* Deslizador — el único selector de escala de la App. Manda la palabra;
   el número queda de apoyo. La posición va como fracción 0–1 en el
   calc() de cada instancia. */
.ui .slider { padding: 22px 0; border-bottom: 1px solid var(--line-soft); }
.ui .slider:first-child { padding-top: 6px; }
.ui .slider:last-child { border-bottom: none; padding-bottom: 6px; }
.ui .slider-h { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.ui .slider-h .t { font-size: 13.5px; font-weight: 600; line-height: 1.35; letter-spacing: -.005em; }
.ui .slider-h .r { display: flex; align-items: baseline; gap: 12px; flex-shrink: 0; }
.ui .slider-h .p { font-size: 9px; font-weight: 600; letter-spacing: 1.2px; color: var(--muted-2); }
.ui .slider-q { font-size: 11.5px; color: var(--muted); margin: 5px 0 0; line-height: 1.55; }
.ui .slider-v { display: flex; align-items: baseline; gap: 9px; margin-top: 14px; flex-wrap: wrap; }
.ui .slider-v b {
    font-size: 21px; font-weight: 600; letter-spacing: -.03em;
    color: var(--verde-d); line-height: 1.15;
}
.ui .slider-v span {
    font-size: 11px; font-weight: 600; color: var(--muted-2);
    font-variant-numeric: tabular-nums; letter-spacing: .3px;
}
.ui .slider-t { position: relative; height: 30px; margin-top: 8px; }
.ui .slider-t .via {
    position: absolute; top: 11px; left: 0; right: 0; height: 8px;
    border-radius: 999px; background: var(--verde); opacity: .16;
}
.ui .slider-t .fill {
    position: absolute; top: 11px; left: 0; height: 8px;
    border-radius: 999px; background: var(--verde);
}
.ui .slider-t .dots {
    position: absolute; top: 11px; left: 0; right: 0; height: 8px;
    display: flex; justify-content: space-between; align-items: center;
}
.ui .slider-t .dots i {
    width: 2px; height: 8px; border-radius: 1px; flex-shrink: 0;
    background: var(--surface); opacity: .55;
}
.ui .slider-t .dots i:first-child, .ui .slider-t .dots i:last-child { opacity: 0; }
.ui .slider-t .knob {
    position: absolute; top: 2px; width: 26px; height: 26px; border-radius: 999px;
    background: var(--surface); transform: translateX(-50%);
    box-shadow: 0 2px 8px rgba(18, 24, 31, .22), 0 0 0 1px var(--line);
    display: grid; place-items: center;
}
.ui .slider-t .knob::after {
    content: ""; width: 12px; height: 12px; border-radius: 999px; background: var(--verde);
}
.ui .slider-t input[type="range"] {
    position: absolute; inset: 0; width: 100%; height: 100%;
    margin: 0; opacity: 0; cursor: pointer;
}
.ui .slider-e {
    display: flex; justify-content: space-between; gap: 16px; margin-top: 2px;
    font-size: 9.5px; font-weight: 500; color: var(--muted-2); line-height: 1.45;
}
.ui .slider-hint { font-size: 11px; color: var(--muted); margin-top: 12px; line-height: 1.5; }
.ui .slider.corto { padding: 4px 0 0; border-bottom: none; }
.ui .slider.corto .slider-v { margin-top: 6px; }

/* ── 5 · Bloques de datos ─────────────────────────────────────────── */

/* La banda es el bloque de lectura de una pantalla: un título y su contenido.
   Desde el rediseño card-based es una TARJETA —superficie, borde y radio
   propios— y no una franja separada por un filete horizontal.

   El filete alcanzaba mientras el marco era una columna de 1180 px centrada:
   ahí el borde de la columna hacía de marco y las bandas solo tenían que
   separarse entre sí. A ancho completo ese borde desapareció, y una pila de
   bandas sin marco se lee como un documento largo en lugar de un panel — nada
   agrupa visualmente una cifra con el título que la nombra.

   Dos excepciones, las dos por doble marco:
     · `.plana` — la banda vive DENTRO de otra tarjeta y solo aporta el título.
     · una banda cuyo único hijo es una rejilla de tejas: cada teja ya es una
       tarjeta suelta, así que la banda queda de puro andamio. */
.ui .banda {
    min-width: 0;
    padding: 15px 16px 16px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-l);
    box-shadow: var(--sh-s);
}
.ui .banda.plana,
/* Anidada, el marco ya lo puso la de afuera. Pasa de verdad y en varios lados:
   el panel del CMO y el dashboard agrupan bandas hermanas dentro de una banda
   madre (una `.g2` con dos bandas adentro), y con marco propio cada una eso
   daban tres bordes concéntricos. Se resuelve por anidamiento y no marcando cada
   caso a mano, porque el que agregue la próxima banda no va a saber que tenía
   que marcarla. */
.ui .banda .banda,
.ui .card .banda {
    padding: 0; background: none; border: none; border-radius: 0; box-shadow: none;
}
.ui .banda-h { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 13px; }
.ui .banda-h h3 { font-size: 14.5px; font-weight: 600; letter-spacing: -.008em; margin: 0; line-height: 1.4; }
.ui .banda-h .u { margin-left: auto; font-size: 11.5px; font-weight: 400; color: var(--muted); line-height: 1.45; }

.ui .cifras { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); row-gap: 16px; }
.ui .cifra { padding: 0 14px; border-left: 1px solid var(--line); min-width: 0; }
/* El filete vertical y su reinicio por posición son de la rejilla SIN tarjetas:
   dentro de `.tejas` cada cifra trae su propio marco y una raya de más entre
   dos tarjetas se lee como un error de dibujo. El `:not(.tejas)` va en el
   padre y no en la cifra porque lo que decide es la rejilla, no la celda —y
   porque estas reglas se repiten en los container queries, donde llegan
   después y con la misma fuerza que las de la teja. */
.ui .cifras:not(.tejas) > .cifra:nth-child(2n+1) { border-left: none; padding-left: 0; }
/* La cifra de dinero se lleva la fila entera en teléfono: en media columna, un
   monto de ocho dígitos con su «C$» no entra en un renglón a ningún tamaño que
   siga siendo legible. Con la fila completa vuelve al cuerpo grande y no se
   parte. Del quiebre de 700 hacia arriba es una celda más. */
.ui .cifras:not(.tejas) > .cifra.ancha { grid-column: 1 / -1; border-left: none; padding-left: 0; }
.ui .cifras:not(.tejas) > .cifra.ancha .v { font-size: 27px; }
/* Con una cifra ancha adelante, la paridad de las filas se invierte: la que
   abre cada fila pasa a ser la par, y es esa la que no lleva filete. */
.ui .cifras:not(.tejas):has(> .cifra.ancha) > .cifra:nth-child(2n) { border-left: none; padding-left: 0; }
.ui .cifras:not(.tejas):has(> .cifra.ancha) > .cifra:nth-child(2n+1):not(.ancha) {
    border-left: 1px solid var(--line); padding-left: 14px;
}
.ui .cifra .l {
    font-size: 11.5px; font-weight: 500; letter-spacing: 0; text-transform: none;
    color: var(--muted); line-height: 1.45;
}
/* En teléfono la rejilla es de dos columnas y un monto de siete cifras con su
   «C$» no cabe a 27 px: se escala contra el ancho real del contenedor hasta
   que entra en un renglón, en vez de partirse. Del quiebre de 700 hacia
   arriba sobra ancho y vuelve al tamaño fijo. */
.ui .cifra .v {
    font-size: clamp(18px, 5.2cqi, 27px); font-weight: 600; letter-spacing: -.035em;
    line-height: 1.05; margin-top: 6px; font-variant-numeric: tabular-nums;
    overflow-wrap: break-word;
}
.ui .cifra .v.chica { font-size: 19px; }
.ui .cifra .d { font-size: 11px; font-weight: 500; color: var(--muted); margin-top: 5px; line-height: 1.45; }
.ui .cifra .d.sube { color: var(--exito); }
.ui .cifra .d.baja { color: var(--rojo); }
.ui .cifra.alerta .v { color: var(--ambar); }
.ui .cifra.exito .v { color: var(--exito); }

/* Cifra que además filtra: se nota que se puede tocar. */
.ui button.cifra { background: none; text-align: left; font-family: inherit; }
.ui a.cifra { display: block; color: inherit; text-decoration: none; }
.ui .cifra.link { cursor: pointer; }
.ui .cifra.link .l { display: flex; align-items: center; gap: 5px; }
.ui .cifra.link .l::after {
    content: ""; width: 5px; height: 5px;
    border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
    transform: rotate(-45deg) translateY(-1px);
}
.ui .cifra.link:hover .v { color: var(--verde-d); }
.ui .cifra.link:hover .l { color: var(--verde); }

/* ── 5b · Inicio: tejas y tarjeta de orden ────────────────────────────

   El rediseño del inicio (2026-08-12). Vale SOLO para las cuatro pantallas de
   inicio: el resto de las vistas sigue leyendo sus cifras con la banda de
   arriba, sin tarjeta.

   Dos cosas cambian respecto de la banda:

     1. Cada cifra es una TARJETA suelta. Nueve números sobre el lienzo se
        leían como una tabla de contabilidad.
     2. El número va ARRIBA y el rótulo debajo, en gris y en minúsculas. El
        rótulo en versalitas pesaba más que el dato que anunciaba.

   El orden visual lo da `column-reverse`, no el marcado: el rótulo se sigue
   escribiendo primero, que es como lo lee un lector de pantalla.

   Card-based (2026-08-12): las tejas eran un solo bloque con hilos interiores
   dibujados por cada celda con dos sombras de 1 px. Ahora cada una lleva su
   propio marco y se separan con `gap`, que es lo que hace un banco de
   indicadores. Con eso se va también la cuenta de columnas por tramo: reparte
   `auto-fit` contra un mínimo de 190 px, así que el número de columnas lo pone
   el ancho real de la pantalla y no tres quiebres escritos a mano — que era
   justo lo que no podía funcionar con el marco a ancho completo. */
.ui .cifras.tejas {
    grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
    gap: 12px; row-gap: 12px;
    background: none; border: none; border-radius: 0; box-shadow: none;
    overflow: visible;
}
/* Grupo de dos (las dos cifras de dinero del CMO, por ejemplo): piden más
   ancho porque su contenido es un monto y no un conteo de dos dígitos. */
.ui .cifras.tejas.dos { grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr)); }

.ui .cifras.tejas > .cifra {
    display: flex; flex-direction: column-reverse; justify-content: flex-end;
    padding: 18px 20px 17px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-l);
    box-shadow: var(--sh-s);
}
.ui .cifras.tejas > .cifra .v {
    font-size: clamp(18px, 5.2cqi, 27px); font-weight: 600; letter-spacing: -.033em; margin: 0 0 5px;
}
.ui .cifras.tejas > .cifra .v.chica { font-size: 19px; }
.ui .cifras.tejas > .cifra .l {
    font-size: 11px; font-weight: 600; letter-spacing: 0; text-transform: none;
    color: var(--muted);
}
/* Sin la flechita del rótulo: la teja entera es el destino y se nota al tocarla. */
.ui .cifras.tejas > .cifra.link .l::after { display: none; }
.ui .cifras.tejas > .cifra.link:hover {
    background: var(--surface); border-color: var(--verde-b); box-shadow: var(--sh-m);
}
.ui .cifras.tejas > .cifra.link:hover .v { color: var(--verde-d); }

/* La banda que envuelve un bloque de tejas se queda de andamio: cada teja ya
   es una tarjeta, y encerrarlas en otra da dos marcos concéntricos. */
.ui .banda:has(> .cifras.tejas) {
    padding: 0; background: none; border: none; border-radius: 0; box-shadow: none;
}
.ui .banda:has(> .cifras.tejas) .banda-h { margin-bottom: 10px; }

/* Tarjeta de orden — la cola de firma en el inicio.

   Es la misma información que la fila de lista (`.li`), en tarjeta y ordenada
   por lo que decide la firma: quién pide, qué pide, cuánto y para cuándo. El
   número de la OT sube al tope, la comparación de cotizaciones se guarda en un
   icono y la criticidad baja a una pastilla junto a los botones. Se usa donde
   hay que DECIDIR sobre pocas órdenes; para recorrer muchas sigue mandando la
   lista. */
.ui .otcs { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
/* `.par` reparte la cola en columnas cuando hay ancho. Una pila de tarjetas de
   260 px de alto sobre un marco de 1200 obliga a desplazar para ver la quinta
   orden y deja media pantalla vacía al lado de cada una; la cola de firma
   existe para VERLA ENTERA y decidir. El mínimo va con `min()` por lo mismo que
   `.kpis`: `minmax(340px, 1fr)` a secas no baja de 340 y se sale del marco en un
   contenedor más angosto. */
.ui .otcs.par {
    display: grid; align-items: start;
    grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
}
/* Con Virtualize adentro la separación va en margen, no en `gap`: los rellenos
   que Virtualize calcula para lo que no se pinta son alto de ítem por cantidad
   y no cuentan el `gap`, así que la barra de desplazamiento se iría corriendo
   un poco por cada fila fuera de pantalla. */
.ui .otcs.virtual { display: block; }
.ui .otcs.virtual > .otc { margin-bottom: 10px; }
.ui .otc {
    position: relative; min-width: 0;
    background: var(--surface);
    border: 1px solid var(--line); border-left: 3px solid var(--line);
    border-radius: var(--r-l); box-shadow: var(--sh-s);
    padding: 12px 14px 13px;
}
/* Carril de severidad, igual que en la lista: única tinta naranja legítima. */
.ui .otc.baja   { border-left-color: var(--sev-1); }
.ui .otc.media  { border-left-color: var(--sev-2); }
.ui .otc.alta   { border-left-color: var(--sev-3); }
.ui .otc.emerg  { border-left-color: var(--sev-4); }

.ui .otc-top { display: flex; align-items: center; gap: 8px; min-width: 0; }
.ui .otc-no {
    flex-shrink: 0; padding: 3px 7px; border-radius: 7px;
    background: var(--sunken); color: var(--ink-2);
    font-family: var(--lcm-mono-font); font-size: 10.5px; font-weight: 500; letter-spacing: .2px;
}
.ui .otc-loc { min-width: 0; font-size: 11.5px; font-weight: 600; color: var(--muted); overflow-wrap: anywhere; }
/* Va sobre el enlace estirado de la tarjeta, así que sube de plano. */
.ui .otc-ico {
    margin-left: auto; flex-shrink: 0; position: relative; z-index: 1;
    width: 32px; height: 32px; border-radius: 9px;
    border: 1px solid var(--line); background: var(--surface); color: var(--muted);
    display: inline-flex; align-items: center; justify-content: center; text-decoration: none;
}
.ui .otc-ico:hover { color: var(--verde-d); border-color: var(--verde-b); }
.ui .otc-t { margin-top: 9px; font-size: 15px; font-weight: 600; line-height: 1.35; color: var(--ink); }
.ui .otc-s { margin-top: 3px; font-size: 12px; font-weight: 500; color: var(--muted); line-height: 1.4; }
.ui .otc-sep { height: 1px; margin: 11px 0 10px; background: var(--line-soft); }
.ui .otc-monto {
    font-size: 21px; font-weight: 600; letter-spacing: -.03em; line-height: 1.15;
    font-variant-numeric: tabular-nums;
}
.ui .otc-vence { margin-top: 3px; font-size: 11.5px; font-weight: 500; color: var(--ambar); line-height: 1.4; }
.ui .otc-vence.urg { color: var(--rojo); }
.ui .otc-prov { margin-top: 9px; font-size: 12px; font-weight: 500; color: var(--ink-2); line-height: 1.45; }
.ui .otc-meta { margin-top: 2px; font-size: 11.5px; font-weight: 500; color: var(--muted); line-height: 1.45; }
.ui .otc-acts {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    margin-top: 12px; position: relative; z-index: 1;
}
.ui .otc-crit {
    margin-left: auto; flex-shrink: 0; padding: 4px 10px; border-radius: 999px;
    background: var(--sunken); color: var(--muted);
    font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.45;
}
.ui .otc-crit.rojo { background: var(--rojo-l); color: var(--rojo); }

/* Tendencia al pie de una cifra: barritas alineadas abajo, la última destacada.
   El alto de cada barra lo pone la página como porcentaje del máximo de su
   serie, así que la caja tiene alto fijo y `min-height` para que un día sin
   actividad siga dejando marca en lugar de desaparecer.
   Una sola tinta, `--viz`: es magnitud comparable, no severidad. La rampa
   `--sev-*` es exclusiva de prioridad y criticidad, y un sparkline con colores
   de alarma inventa una lectura que el dato no tiene. */
.ui .spark {
    display: flex; align-items: flex-end; gap: 2px;
    height: 20px; margin-top: 9px;
}
.ui .spark i { flex: 1; min-height: 2px; border-radius: 1px; background: var(--viz-soft); }
.ui .spark i.on { background: var(--viz); }

/* Ranking: una fila por elemento, barra comparable en el medio y la cifra
   a la derecha. Sustituye la rejilla de tarjetitas con un contador cada
   una — el orden se lee de un vistazo. Una sola tinta. */
.ui .rank { display: flex; flex-direction: column; }
.ui .rank-f {
    display: grid; grid-template-columns: minmax(96px, 1.1fr) minmax(60px, 2fr) auto;
    align-items: center; gap: 14px; width: 100%;
    padding: 9px 0; background: none;
    font-family: inherit; text-align: left; cursor: pointer;
    color: inherit; text-decoration: none;
}
.ui .rank-f:hover .rank-n { color: var(--verde-d); }
.ui .rank-n { font-size: 12.5px; font-weight: 500; color: var(--ink); line-height: 1.4; min-width: 0; }
.ui .rank-n em { font-style: normal; font-weight: 500; color: var(--muted-2); font-size: 10.5px; margin-left: 5px; }
.ui .rank-b { height: 8px; border-radius: 999px; background: var(--grid); overflow: clip; }
.ui .rank-b i { display: block; height: 100%; background: var(--viz); border-radius: 999px; }
.ui .rank-v { font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; min-width: 24px; text-align: right; }

/* Franja "tu turno" — lo que bloquea el flujo de este rol. */
/* Lo que le toca al usuario, en UNA línea.

   Reemplaza al bloque oscuro «Te toca a vos» en los cuatro inicios. El bloque
   traía su propio banco de cifras justo encima de la banda de estados, y los dos
   competían: en el inicio del Gerente el mismo 3 salía tres veces («Te toca a
   vos 3», «Aprobar cierre 3» y «Atendidas 3 · esperan tu firma»). Ahora el dato
   accionable se dice una vez y como frase, y las cifras quedan agrupadas por
   significado —estado de la orden y fecha— en bandas hermanas.

   Es un enlace: lleva a la lista ya filtrada, igual que cada cifra.

   Desde el rediseño del inicio (2026-08-12) es una TARJETA, no una franja de
   color: el número va en su propia pastilla, el asunto en negrita y lo que hay
   que hacer debajo, en gris. La franja verde competía con el botón primario de
   la tarjeta de orden que ahora viene abajo, y dos verdes seguidos no dejaban
   ver cuál se toca. */
.ui .toca {
    display: flex; align-items: center; gap: 13px; min-width: 0;
    padding: 12px 14px; border-radius: var(--r-l);
    background: var(--surface); border: 1px solid var(--line); box-shadow: var(--sh-s);
    color: var(--ink);
    text-decoration: none; font-family: inherit; text-align: left;
    cursor: pointer; width: 100%;
}
.ui .toca:hover { background: var(--verde-l); border-color: var(--verde-b); color: var(--ink); }
.ui .toca-n {
    flex-shrink: 0; width: 38px; height: 38px; border-radius: 12px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--ambar-l); color: var(--ambar);
    font-size: 16px; font-weight: 600; letter-spacing: -.02em; line-height: 1;
    font-variant-numeric: tabular-nums;
}
/* Los tres son <span> —van dentro de un enlace— así que el bloque se declara acá. */
.ui .toca-c { display: block; flex: 1; min-width: 0; }
.ui .toca-t { display: block; font-size: 14px; font-weight: 600; line-height: 1.3; }
.ui .toca-s { display: block; font-size: 11.5px; font-weight: 500; color: var(--muted); margin-top: 2px; line-height: 1.4; }
.ui .toca-cta { flex-shrink: 0; display: inline-flex; align-items: center; color: var(--muted-2); }
/* Al día: la misma tarjeta sin número ni destino, para que la ausencia de
   pendientes se lea como un estado y no como un hueco. */
.ui .toca.toca-ok { cursor: default; }
.ui .toca.toca-ok:hover { background: var(--surface); border-color: var(--line); }
.ui .toca-ok .toca-t { font-weight: 500; color: var(--ink-2); }
.ui .toca-i {
    flex-shrink: 0; width: 38px; height: 38px; border-radius: 12px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--exito-l); color: var(--exito);
}

.ui .turno {
    background: var(--ink); color: #fff; border-radius: var(--r-xl);
    padding: 16px 18px; display: flex; flex-direction: column; gap: 13px;
}
[data-tema="oscuro"] .turno { background: #0a0f14; border: 1px solid var(--line); }
.ui .turno .eyebrow { color: #8fb3a0; }
.ui .turno-h { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.ui .turno-h > .eyebrow { width: 100%; }
.ui .turno-n {
    font-size: 40px; font-weight: 600; letter-spacing: -.04em;
    line-height: .95; font-variant-numeric: tabular-nums;
}
.ui .turno-t { font-size: 13px; font-weight: 500; color: #b9c8d4; line-height: 1.45; flex: 1; min-width: 140px; }
.ui .turno-list { display: flex; flex-direction: column; gap: 7px; }
.ui .turno-item {
    display: flex; align-items: center; gap: 11px;
    background: rgba(255,255,255,.07); border-radius: var(--r-m);
    padding: 10px 12px; color: #fff; text-decoration: none;
    text-align: left; font-family: inherit; cursor: pointer;
}
.ui .turno-item .t { font-size: 12.5px; font-weight: 600; line-height: 1.35; }
.ui .turno-item .s { font-size: 11px; color: #9fb1c0; margin-top: 2px; line-height: 1.4; }
.ui .turno-item .n {
    font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums;
    background: #3f5d4a; color: #fff; border-radius: 999px; padding: 3px 10px; flex-shrink: 0;
}

/* Familias de lectura de datos que llegaron repetidas en el CSS aislado de
   varias vistas: panel del Coordinador y del CMO, mapa de sucursales, cierre
   del Gerente y planes preventivos declaraban las mismas clases con los mismos
   valores. Son del sistema, no de una pantalla, así que viven acá una sola vez.
   Los valores son los de la maqueta; donde dos copias diferían, la maqueta
   arbitró. Cada vista conserva solo sus variantes propias.

   Los elementos que además filtran son <button>, así que las clases traen el
   reinicio del cromo del navegador: sin él el borde y el fondo por defecto
   tapan el dato. */

/* Embudo: una fila por etapa, con la barra comparable bajo la etiqueta. */
.ui .embudo { display: flex; flex-direction: column; }
.ui .emb-f {
    display: grid; grid-template-columns: 1fr auto;
    column-gap: 10px; row-gap: 5px; padding: 9px 0;
    align-items: baseline; width: 100%;
    border: none; border-bottom: 1px solid var(--line-soft);
    background: none; color: inherit;
    font-family: inherit; text-align: left; cursor: pointer;
}
.ui .emb-f:last-child { border-bottom: none; }
.ui .emb-f:hover .emb-l { color: var(--verde-d); }
.ui .emb-f.on .emb-l { color: var(--verde-d); font-weight: 600; }
.ui .emb-l { font-size: 12.5px; font-weight: 500; color: var(--ink-2); line-height: 1.4; }
.ui .emb-n { font-size: 13.5px; font-weight: 600; font-variant-numeric: tabular-nums; text-align: right; }
.ui .emb-b {
    grid-column: 1 / -1; display: block; height: 20px;
    background: var(--grid); border-radius: 3px; overflow: clip;
}
.ui .emb-b i { display: block; height: 100%; background: var(--viz); border-radius: 3px; }
.ui .emb-b i.fin  { background: var(--exito); }
.ui .emb-b i.fuga { background: var(--sev-3); }
.ui .emb-t { grid-column: 1 / -1; font-size: 10.5px; font-weight: 500; color: var(--muted-2); line-height: 1.45; }

/* Barra chica comparable, dentro de una fila o de una celda. */
.ui .mini {
    display: block; height: 6px; min-width: 54px; margin-top: 6px;
    background: var(--grid); border-radius: 3px; overflow: clip;
}
.ui .mini i { display: block; height: 100%; background: var(--viz); border-radius: 3px; }
.ui .mini i.sev { background: var(--sev-3); }

/* Matriz: tabla de lectura sin paredes verticales, que se desliza dentro de su
   propia banda cuando no cabe. Es dato, no formulario: vive con las bandas. */
.ui .banda:has(> .matriz) {
    overflow-x: auto; padding-bottom: 12px;
    scrollbar-width: thin; scrollbar-color: var(--muted-2) var(--sunken);
}
.ui .banda:has(> .matriz)::-webkit-scrollbar { height: 10px; }
.ui .banda:has(> .matriz)::-webkit-scrollbar-track { background: var(--sunken); border-radius: 999px; }
.ui .banda:has(> .matriz)::-webkit-scrollbar-thumb {
    background: var(--muted-2); border-radius: 999px; border: 2px solid var(--sunken);
}
.ui .matriz { width: 100%; min-width: 620px; border-collapse: collapse; font-size: 12.5px; }

.ui .matriz th {
    text-align: left; padding: 0 12px 10px 0; border-bottom: 1px solid var(--line);
    font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none;
    color: var(--muted); line-height: 1.45; vertical-align: bottom;
}
.ui .matriz th.n, .ui .matriz td.n { text-align: right; }
.ui .matriz td {
    padding: 12px 12px 12px 0; border-bottom: 1px solid var(--line-soft);
    vertical-align: middle; line-height: 1.4;
}
.ui .matriz tr:last-child td { border-bottom: none; }
.ui .matriz tr.on td { background: var(--verde-l); }
/* El nombre de la fila abre el registro o filtra: <a> o <button>, mismo aspecto. */
.ui .matriz .nom {
    display: block; font-size: 12.5px; font-weight: 600; color: var(--ink);
    border: none; background: none; padding: 0;
    font-family: inherit; text-align: left; text-decoration: none; cursor: pointer;
}
.ui .matriz .nom:hover { color: var(--verde-d); }
.ui .matriz .sub { display: block; font-size: 10.5px; font-weight: 500; color: var(--muted-2); margin-top: 2px; }
.ui .matriz .val { font-weight: 600; font-variant-numeric: tabular-nums; }

/* En teléfono la matriz mide 620 px dentro de una pantalla de 390: se desliza,
   y eso NO era evidente —quedaba media tabla cortada por el borde sin ninguna
   señal—. Dos cosas lo arreglan: un degradado en el borde derecho que aparece
   solo mientras haya algo más a la derecha, y menos relleno lateral para que
   entre más contenido por pantallazo. */
@container (max-width: 699px) {
    .ui .banda:has(> .matriz) {
        /* El degradado se pega al contenedor y se desvanece al llegar al final:
           `local` sigue el scroll, `scroll` se queda fijo. Los dos juntos hacen
           la sombra que aparece y desaparece sola, sin JavaScript. */
        background:
            linear-gradient(to right, var(--canvas) 30%, transparent) left / 24px 100% no-repeat local,
            linear-gradient(to left, var(--canvas) 30%, transparent) right / 24px 100% no-repeat local,
            linear-gradient(to right, rgba(18, 24, 31, .13), transparent) left / 14px 100% no-repeat scroll,
            linear-gradient(to left, rgba(18, 24, 31, .13), transparent) right / 14px 100% no-repeat scroll;
    }
    .ui .matriz { min-width: 560px; font-size: 12px; }
    .ui .matriz th { padding-right: 9px; }
    .ui .matriz td { padding-right: 9px; }
    .ui .matriz .nom { font-size: 12.5px; }
}

/* Rejilla de cifras chicas comparables. */
.ui .multi { display: grid; grid-template-columns: repeat(auto-fit, minmax(146px, 1fr)); gap: 20px 24px; }
.ui .multi-i {
    min-width: 0; display: block; width: 100%; padding: 0;
    border: none; background: none; color: inherit;
    font-family: inherit; text-align: left;
}
.ui button.multi-i { cursor: pointer; }
.ui .multi-i .l {
    display: block; font-size: 11px; font-weight: 600;
    color: var(--ink-2); line-height: 1.4; overflow-wrap: break-word;
}
.ui .multi-i .v {
    display: block; font-size: 21px; font-weight: 600; letter-spacing: -.03em;
    font-variant-numeric: tabular-nums; margin-top: 3px;
}
.ui .multi-i .s {
    display: block; font-size: 10.5px; font-weight: 500;
    color: var(--muted-2); margin-top: 2px; line-height: 1.4;
}
.ui button.multi-i:hover .l, .ui .multi-i.on .l { color: var(--verde-d); }

/* Severidad: una sola barra apilada con su leyenda tocable. */
.ui .sevbar { display: flex; gap: 2px; height: 18px; border-radius: 4px; overflow: hidden; }
.ui .sevbar i { display: block; height: 100%; }
.ui .sevleg { display: flex; flex-wrap: wrap; gap: 10px 16px; margin-top: 11px; }
.ui .sevleg button {
    display: flex; align-items: center; gap: 7px;
    border: none; background: none; padding: 0;
    font-family: inherit; font-size: 11.5px; font-weight: 500;
    color: var(--ink-2); line-height: 1.45; cursor: pointer;
}
.ui .sevleg button:hover { color: var(--verde-d); }
.ui .sevleg button.on { color: var(--verde-d); font-weight: 600; }
.ui .sevleg i { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }
.ui .sevleg b { color: var(--ink); font-variant-numeric: tabular-nums; }

/* Cuadre de un monto contra su referencia — cierre del Gerente y cierre de OT. */
.ui .cuadre { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; }
.ui .cuadre-n {
    font-size: 30px; font-weight: 600; letter-spacing: -.035em; line-height: 1;
    font-variant-numeric: tabular-nums; overflow-wrap: break-word;
}
.ui .cuadre-c { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
/* El veredicto al lado del número. Los tonos son los del sistema, no un juego
   propio: el cierre del Gerente y el de la OT dicen lo mismo con lo mismo. */
.ui .cuadre-v {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 12px; font-weight: 600; line-height: 1.45;
}
.ui .cuadre-v svg { flex-shrink: 0; }
.ui .cuadre-v.verde { color: var(--exito); }
.ui .cuadre-v.ambar { color: var(--ambar); }
.ui .cuadre-v.rojo  { color: var(--rojo); }

/* Rúbrica: la firma se apoya en una línea, nunca en una caja. */
.ui .rubrica { padding-top: 6px; }
.ui .rubrica-t {
    height: 76px; display: flex; align-items: flex-end; justify-content: center;
    padding-bottom: 6px; border-bottom: 1.5px solid var(--firma-linea); color: var(--ink);
}
.ui .rubrica-t img { max-height: 100%; max-width: 100%; object-fit: contain; }
/* En el tema oscuro la firma va sobre HOJA CLARA, no invertida.

   El trazo se captura en tinta oscura sobre lienzo transparente (#1e293b en
   wwwroot/js/signature-pad.js) porque su destino final es el papel. Sobre el
   lienzo del oscuro no se veía —se adivinaba el garabato y nada más— y el
   primer arreglo lo daba vuelta con un filtro: quedaba legible, pero ya no era
   la firma de la persona sino su negativo en blanco. Una rúbrica es tinta
   oscura sobre papel, y así es como sale impresa; lo que faltaba era el papel.

   Nada de esto toca los píxeles que `toDataURL` devuelve: lo que se guarda y lo
   que se imprime siguen siendo iguales. Vale para el trazo en vivo y para la
   firma ya guardada, que son el mismo problema. La hoja no entra en el estado
   `vacia`, que no tiene trazo que sostener: ahí el rótulo va en tinta del tema.
   El documento imprimible usa sus propias clases y ya nace en blanco. */
[data-tema="oscuro"] .lcm-sigpad-canvas {
    background: var(--firma-papel);
    border-radius: var(--r-s) var(--r-s) 0 0;
}
/* La raya en la que se apoya el trazo va DENTRO de la hoja, como capa de
   fondo: de borde caía en el canto del papel y ahí no se lee como una raya
   sino como el filo de la hoja. */
[data-tema="oscuro"] .ui .rubrica-t:not(.vacia) {
    background:
        linear-gradient(var(--firma-linea), var(--firma-linea))
            no-repeat left 10px bottom 8px / calc(100% - 20px) 1.5px,
        var(--firma-papel);
    border-bottom-color: transparent;
    border-radius: var(--r-s);
    padding: 5px 10px 11px;
}
.ui .rubrica-t.vacia {
    border-bottom-style: dashed; border-bottom-color: var(--line);
    color: var(--muted-2); font-size: 12px; font-weight: 500;
    align-items: center; padding-bottom: 0; text-align: center;
}
.ui .rubrica-p {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px; flex-wrap: wrap; margin-top: 8px;
}
.ui .rubrica-p .n { font-size: 12.5px; font-weight: 600; line-height: 1.4; }
.ui .rubrica-p .c {
    font-size: 10.5px; font-weight: 500; color: var(--muted-2);
    line-height: 1.45; font-variant-numeric: tabular-nums;
}

/* Serie de visitas de un plan preventivo. */
.ui .serie { display: flex; flex-wrap: wrap; gap: 7px; }
.ui .serie-v {
    display: flex; flex-direction: column; gap: 2px; align-items: center;
    min-width: 62px; padding: 9px 10px; border-radius: var(--r-m);
    background: var(--indigo-l); color: var(--indigo);
}
.ui .serie-v b { font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1; }
.ui .serie-v span { font-size: 11px; font-weight: 400; letter-spacing: 0; text-transform: none; }
.ui .serie-v.hecha { background: var(--exito-l); color: var(--exito); }
.ui .serie-v.cancel { background: var(--sunken); color: var(--muted-2); }

/* ── 6 · Lista de registros ───────────────────────────────────────── */

/* Sustituye la pila de tarjetas: UNA tarjeta con todas las filas dentro, en
   vez de una tarjeta por registro. Las filas se separan con un filete interior
   que no llega a los cantos y el carril de prioridad es una barrita
   redondeada, no un borde de celda — la lista tiene marco por fuera y ninguna
   pared por dentro.

   La lista NUNCA sangra: es un bloque, en teléfono igual que en escritorio. */
.ui .lista {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-l);
    box-shadow: var(--sh-s);
    overflow: clip;
    min-width: 0;
}

/* `.sangre` queda RETIRADA — ya no sangra, y no declara nada.
 *
 * Significaba «esta lista es el contenido principal de la pantalla, así que puede
 * llegar a los cantos y ganar el ancho que gastaban los márgenes». Tenía sentido
 * cuando la lista era una pila de tarjetas sueltas sobre el lienzo.
 *
 * Con el lenguaje de bloques ya no: el bloque redondeado ES la unidad de lectura,
 * y sangrando la lista queda soldada a los dos filos de la pantalla, con el carril
 * de prioridad pegado al vidrio y los filetes de canto a canto. Al lado de
 * cualquier otro bloque se lee como una tabla cruda incrustada en el teléfono.
 * La prueba está en la app: el inicio del técnico nunca llevó `sangre` y su lista
 * —la misma lista, con las mismas filas— se lee mejor que la de la bandeja.
 *
 * Se neutraliza acá, en un solo lugar, en vez de quitar la clase de diecinueve
 * marcados repartidos en cinco roles: así las listas de TODOS los roles quedan
 * iguales de una vez y sin tocar pantallas que todavía no se revisaron. La clase
 * queda inerte y se puede barrer del marcado cuando le toque a cada rol. */

/* Cabecera de grupo. En esta versión es un separador normal, no pegajoso:
   la bandeja conserva la virtualización y las dos cosas no conviven. */
.ui .lista-h {
    display: flex; align-items: baseline; gap: 9px;
    padding: var(--lista-h-py) 18px 9px;
    background: var(--surface);
    font-size: 12px; font-weight: 500; letter-spacing: 0;
    text-transform: none; color: var(--muted); line-height: 1.45;
}
.ui .lista-h::before {
    content: ""; width: 6px; height: 6px; border-radius: 999px;
    background: currentColor; flex-shrink: 0; align-self: center; opacity: .5;
}
.ui .lista-h .n {
    margin-left: auto; font-variant-numeric: tabular-nums; letter-spacing: .4px;
    color: var(--muted-2);
}
.ui .lista-h.urgente { color: var(--rojo); }
.ui .lista-h.urgente::before { opacity: 1; }
.ui .lista-h.proximo { color: var(--ambar); }
.ui .lista-h.proximo::before { opacity: 1; }

.ui .li {
    position: relative;
    display: flex; align-items: flex-start; gap: 14px;
    width: 100%; padding: var(--li-py) 18px;
    background: transparent; color: inherit;
    text-align: left; text-decoration: none; cursor: pointer;
    font-family: inherit;
}
/* Filete entre filas: interior, nunca de canto a canto. */
.ui .li::after {
    content: ""; position: absolute; left: 18px; right: 18px; bottom: 0;
    height: 1px; background: var(--line-soft);
}
/* El filete se apaga en la ÚLTIMA FILA DE LA LISTA, no en cualquier `.li` que
   resulte ser el último hijo de su envoltorio.

   `.li:last-child` a secas era un error de bulto: `SwipeRow` envuelve la fila en
   `.li-swipe` y pone el carril de acciones ANTES, así que ahí el `.li` es siempre
   el último hijo y perdía su filete. Y como `SwipeRow` solo envuelve las filas que
   tienen acción —sin acciones renderiza la fila desnuda— en la misma lista
   convivían filas con separador y filas sin él, alternándose según si la OT
   admitía o no una acción rápida. Eso es lo que se veía como cortes en la bandeja
   del técnico, y solo ahí porque es la única pantalla con el gesto.
   Ahora se pregunta por el envoltorio, no por la fila. */
.ui .lista > .li:last-child::after,
.ui .lista > .li-swipe:last-child > .li::after { display: none; }
/* Carril de prioridad: barrita redondeada que no toca los filetes. Único
   uso legítimo de la rampa naranja. */
.ui .li::before {
    content: ""; position: absolute; left: 0; top: 10px; bottom: 10px;
    width: 3px; border-radius: 0 3px 3px 0; background: transparent;
}
.ui .li:hover { background: var(--sunken); }
/* La fila que no abre nada no se ofrece: sin mano y sin realce. Lo que sí se
   puede hacer en ella —«Entendido» en un aviso del CMO— es su botón, que
   conserva los suyos. */
.ui .li.quieta { cursor: default; }
.ui .li.quieta:hover { background: transparent; }
.ui .li.baja::before   { background: var(--sev-1); }
.ui .li.media::before  { background: var(--sev-2); }
.ui .li.alta::before   { background: var(--sev-3); }
.ui .li.emerg::before  { background: var(--sev-4); }
.ui .li.plan::before   { background: var(--indigo); }
.ui .li.sel { background: var(--verde-l); }
.ui .li.sel::before { background: var(--verde); }
.ui .li.off { opacity: .45; cursor: default; }

.ui .li-c { flex: 1; min-width: 0; }
.ui .li-top {
    display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
    font-size: 11px; font-weight: 500; color: var(--muted-2); line-height: 1.45;
}
.ui .li-top .no {
    font-family: var(--lcm-mono-font);
    letter-spacing: .2px; color: var(--muted); overflow-wrap: anywhere;
}
/* La descripción de una fila se lee ENTERA. Nunca se recorta.
 *
 * Acá vivía la única excepción declarada a «nada de texto recortado»: un corte
 * a dos renglones con `-webkit-line-clamp`, justificado en que una descripción
 * larga estira su fila al triple de las vecinas. La excepción se cae por dos
 * motivos, y los dos son de uso real y no de gusto:
 *
 *   1. Dos renglones son ~68 caracteres en un teléfono de 390 px. Las
 *      descripciones de las OT de La Colonia rondan los ochenta —«Reemplazo del
 *      compresor de la cámara de congelados del centro de distribución»— así que
 *      el corte no era un caso extremo: era el caso normal.
 *   2. El texto completo viajaba en el `title` de la fila, y `title` NO EXISTE
 *      sin puntero. En el dispositivo donde la fila se corta es justo donde no
 *      hay forma de leer lo que falta.
 *
 * Una fila alta es un precio menor que una fila que miente. La regla vale para
 * toda la App, sin excepción: nada de nowrap ni de puntos suspensivos sobre
 * contenido. */
.ui .li-t {
    font-size: 14px; font-weight: 500; line-height: 1.5; margin-top: 5px; color: var(--ink);
    overflow-wrap: anywhere;
}
.ui .li-m {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    margin-top: 6px; font-size: 11px; font-weight: 500; color: var(--muted); line-height: 1.45;
}
.ui .li-m .st { display: inline-flex; align-items: center; gap: 5px; }
.ui .li-m .st i { width: 6px; height: 6px; border-radius: 999px; background: currentColor; flex-shrink: 0; }
.ui .li-m .st.azul { color: var(--azul); }
.ui .li-m .st.ambar { color: var(--ambar); }
.ui .li-m .st.verde { color: var(--exito); }
.ui .li-m .st.violeta { color: var(--violeta); }
.ui .li-m .st.indigo { color: var(--indigo); }
.ui .li-m .st.rojo { color: var(--rojo); }

/* Estado suelto (celda de tabla, panel de contexto): punto + texto, nunca un
   chip con fondo. Misma familia de tintas que .li-m .st. */
.ui .st-p {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 11.5px; font-weight: 500; color: var(--muted); line-height: 1.45;
}
.ui .st-p i { width: 6px; height: 6px; border-radius: 999px; background: currentColor; flex-shrink: 0; }
.ui .st-p.azul { color: var(--azul); }
.ui .st-p.ambar { color: var(--ambar); }
.ui .st-p.verde { color: var(--exito); }
.ui .st-p.violeta { color: var(--violeta); }
.ui .st-p.indigo { color: var(--indigo); }
.ui .st-p.rojo { color: var(--rojo); }

.ui .li-r { flex-shrink: 0; text-align: right; }
.ui .li-due { font-size: 11.5px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--muted); line-height: 1.4; }
.ui .li-due.urg  { color: var(--rojo); }
.ui .li-due.pron { color: var(--ambar); }
.ui .li-sub { font-size: 10px; font-weight: 500; color: var(--muted-2); margin-top: 3px; line-height: 1.4; }
/* Texto escrito por una persona dentro de una fila —lo que se cotizó, lo que se
   pidió—. Es contenido, no una seña: se lee ENTERO y parte donde haga falta
   antes que salirse de la fila. */
.ui .li-txt {
    margin: 6px 0 0; font-size: 11.5px; color: var(--ink-2); line-height: 1.55;
    overflow-wrap: anywhere;
}
.ui .li-monto { font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.3; }
.ui .li-acts { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 10px; position: relative; z-index: 1; }
/* La fila que no ofrece un paso porque espera una fecha. Se alinea con los
   botones que la acompañan y se lee como dato, no como acción: sin esto la
   fila quedaba muda y se leía como que la OT ya no necesitaba nada. */
.ui .li-espera {
    display: inline-flex; align-items: center; align-self: center;
    font-size: 11.5px; font-weight: 600; color: var(--muted);
    line-height: 1.4;
}

/* Enlace estirado: la fila entera abre el registro sin anidar un <a> dentro
   de otro elemento interactivo (marcado inválido, y en la App ya rompió el
   cierre del lightbox una vez). El <a> absoluto se pinta sobre el contenido
   en flujo y recibe el toque; las acciones suben con z-index. */
.ui .li-ir { position: absolute; inset: 0; }
/* La fila y el enlace estirado también sirven para alternar una selección o
   abrir una hoja, y entonces son <button>. El navegador les pone borde y fondo
   propios: sin apagarlos, el estirado tapa la fila entera. */
.ui button.li { border: none; }
.ui button.li-ir { border: none; background: none; padding: 0; font: inherit; color: inherit; cursor: pointer; }
.ui button.li-ir:disabled { cursor: default; }

/* Hora al margen — la agenda del técnico. */
.ui .li-hora { flex-shrink: 0; width: 50px; text-align: center; padding-top: 1px; }
.ui .li-hora b { display: block; font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.1; }
.ui .li-hora span {
    display: block; font-size: 11px; font-weight: 500; color: var(--muted);
    margin-top: 3px; text-transform: none; letter-spacing: 0;
}
.ui .li-hora.sin b { font-size: 12px; color: var(--ambar); line-height: 1.25; }

.ui .li-pick { flex-shrink: 0; padding-top: 2px; }

/* Fila con la acción del rol revelada al deslizar. El desplazamiento vive
   en --sw, que el módulo js/swipe-row.js mueve con el dedo; al soltar, la
   clase .abierta lo deja fijo. */
.ui .li-swipe { position: relative; overflow: clip; touch-action: pan-y; }
/* La fila TAPA el carril de acciones mientras está en reposo, y eso exige fondo
   OPACO. `.li` nace con `background: transparent` —lo que quiere en una lista
   normal, donde el color lo pone el contenedor— y acá el resultado era que el
   panel verde de «Programar» se veía a través de cada fila, en todas las filas a
   la vez: una columna de bloques verdes que no se podía leer y que además
   prometía una acción que no estaba activa. El carril se revela deslizando, que
   es su único momento legítimo. */
.ui .li-swipe > .li {
    background: var(--surface);
    transform: translateX(var(--sw, 0px));
    transition: transform .18s var(--lcm-ease-out, ease-out);
}
.ui .li-swipe.arrastrando > .li { transition: none; }
.ui .li-swipe.abierta > .li { transform: translateX(-152px); }
.ui .li-swipe .acc { position: absolute; top: 0; right: 0; bottom: 0; width: 152px; display: flex; }
.ui .li-swipe .acc button {
    flex: 1; cursor: pointer; color: #fff;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
    font-size: 11px; font-weight: 600; font-family: inherit; line-height: 1.3; padding: 4px;
}
.ui .li-swipe .acc .a1 { background: var(--verde); }
.ui .li-swipe .acc .a2 { background: var(--ambar); }

/* Sin puntero táctil no hay gesto: el carril se apaga y las acciones se
   muestran como botones dentro de la fila (el patrón de p09). */
.ui .li-acts.si-gesto { display: none; }
@media (pointer: coarse) {
    .ui .li-acts.si-gesto { display: flex; }
    .ui .li-acts.sin-gesto { display: none; }
}
@media not all and (pointer: coarse) {
    .ui .li-swipe .acc { display: none; }
    .ui .li-swipe > .li { transform: none; }
}

/* Tira de filtros: NUNCA se desliza en horizontal, envuelve. En móvil los
   desplegables se esconden detrás de un solo botón «Filtros» y el
   buscador toma su propia línea. */
.ui .filtros { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ui .filtros > * { flex-shrink: 0; }
/* `.tira` agrupa las pastillas de la tira para que en TELÉFONO puedan
   deslizarse en horizontal como un carril propio mientras el buscador se queda
   con su renglón completo. En escritorio no existe: `display: contents` disuelve
   el envoltorio y sus hijos vuelven a ser hijos directos de `.filtros`, así que
   envuelven igual que siempre y ninguna regla de escritorio se enterá. */
.ui .tira { display: contents; }

/* Los controles que gobiernan lo que se está viendo —el buscador, el botón de
   filtros, la medida— no se van con el desplazamiento. El scroller es
   `.lcm-body`, así que `top: 0` los deja arriba de todo en teléfono y justo
   bajo el topbar en escritorio.

   El colchón de lienzo arriba y abajo se pinta con dos sombras y no con
   relleno: así la barra conserva su caja y el ritmo vertical de `.ui-pad` no
   cambia, pero lo que pasa por debajo queda tapado en lugar de asomar pegado
   al borde. */
.ui .fija {
    position: sticky; top: 0; z-index: 25;
    background: var(--canvas);
    /* El colchón de lienzo se pinta con dos sombras y no con relleno: así la barra
       conserva su caja y el ritmo vertical de `.ui-pad` no cambia, pero lo que
       pasa por debajo queda tapado en lugar de asomar pegado al borde. Son 20 px
       para cubrir el `gap` de la columna, que a ancho completo llega a 18. */
    box-shadow: 0 -20px 0 var(--canvas), 0 20px 0 var(--canvas);
}
.ui .pill.busca {
    flex: 1 1 200px; justify-content: flex-start; min-width: 0;
    color: var(--muted-2); font-weight: 600; cursor: text;
}
/* La fila de búsqueda de la lista de órdenes viene de lcm.css y se pinta con los
   tokens VIEJOS (`--lcm-border`, `--lcm-card`). Es el patrón que se adoptó también
   para la bandeja del técnico, así que acá se la trae al sistema nuevo: mismo
   borde, misma superficie y mismo radio que el resto, y así sigue la inversión de
   superficies del teléfono en lugar de quedarse blanca sobre blanco. */
.ui .lcm-search-input,
.ui .lcm-tools-btn {
    background: var(--surface);
    border-color: var(--line);
    border-radius: var(--r-m);
    color: var(--muted);
}
.ui .lcm-search-input { height: 44px; font-size: 14px; color: var(--ink); }
.ui .lcm-search-input::placeholder { color: var(--muted-2); }
.ui .lcm-tools-btn { width: 44px; height: 44px; }
.ui .lcm-tools-btn:hover { color: var(--ink); border-color: var(--verde-b); }
.ui .lcm-tools-btn.active { background: var(--verde-l); border-color: var(--verde-b); color: var(--verde-d); }
.ui .lcm-tools-dot { background: var(--verde); border-color: var(--surface); }
.ui .lcm-search-row { gap: 8px; }

.ui .f-mas { display: none; }
.ui .f-mas b {
    font-variant-numeric: tabular-nums;
    background: var(--verde); color: #fff; border-radius: 999px;
    min-width: 17px; height: 17px; padding: 0 5px;
    display: inline-flex; align-items: center; justify-content: center; font-size: 10px;
}

.ui .lista-pie {
    display: flex; align-items: center; gap: 9px;
    padding: 12px 15px 14px;
    font-size: 11px; font-weight: 500; color: var(--muted-2); line-height: 1.5;
}

/* ── 7 · Tabla, línea de vida, historial, evidencia ───────────────── */

/* Las tablas nunca se comprimen hasta romper el texto: conservan un ancho
   mínimo legible y se deslizan dentro de su propio marco, con la barra
   visible para que se note que hay más columnas. Sin paredes verticales. */
.ui .tbl-wrap {
    border: 1px solid var(--line);
    border-radius: var(--r-l);
    box-shadow: var(--sh-s);
    overflow-x: auto; background: var(--surface);
    scrollbar-width: thin; scrollbar-color: var(--muted-2) var(--sunken);
}
.ui .tbl-wrap::-webkit-scrollbar { height: 10px; }
.ui .tbl-wrap::-webkit-scrollbar-track { background: var(--sunken); }
.ui .tbl-wrap::-webkit-scrollbar-thumb { background: var(--muted-2); border-radius: 999px; border: 2px solid var(--sunken); }
.ui .tbl { width: 100%; min-width: 680px; border-collapse: collapse; font-size: 12.5px; }
/* Cabecera de tabla en texto llano. Las versalitas de 9,5 px en peso 900 pesaban
   más que las celdas que encabezan: la primera fila de la tabla era lo más oscuro
   de la pantalla. */
.ui .tbl th {
    text-align: left; padding: 16px 14px 10px;
    font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none;
    color: var(--muted); border-bottom: 1px solid var(--line-soft); line-height: 1.45;
}
.ui .tbl td { padding: var(--td-py) 13px; border-bottom: 1px solid var(--line-soft); vertical-align: top; line-height: 1.45; }
.ui .tbl tr:last-child td { border-bottom: none; }
.ui .tbl tbody tr:hover { background: var(--sunken); }
.ui .tbl tr.on td { background: var(--verde-l); }
.ui .tbl .num { text-align: right; font-variant-numeric: tabular-nums; }
.ui .tbl-foot {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 11px 13px 14px; flex-wrap: wrap;
    font-size: 11.5px; font-weight: 500; color: var(--muted-2);
}

/* Línea de vida de la OT. */
.ui .pipe { display: flex; gap: 4px; }
.ui .pipe-s { flex: 1; min-width: 0; }
.ui .pipe-s .bar { height: 5px; border-radius: 999px; background: var(--sunken); }
.ui .pipe-s.done .bar { background: var(--verde); }
.ui .pipe-s.now .bar { background: var(--verde); }
.ui .pipe-s .lb {
    font-size: 9.5px; font-weight: 600; color: var(--muted-2); margin-top: 6px;
    line-height: 1.35; overflow-wrap: break-word;
}
.ui .pipe-s.now .lb { color: var(--verde-d); }
.ui .pipe-s.done .lb { color: var(--verde-d); }

.ui .tl { display: flex; flex-direction: column; }
.ui .tl-i { display: flex; gap: 12px; }
.ui .tl-dotc { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
.ui .tl-dot { width: 10px; height: 10px; border-radius: 999px; background: var(--sunken); border: 2px solid var(--line); margin-top: 4px; }
.ui .tl-i.on .tl-dot { background: var(--verde); border-color: var(--verde); }
.ui .tl-line { flex: 1; width: 2px; background: var(--line-soft); margin: 3px 0; }
.ui .tl-b { padding-bottom: 15px; min-width: 0; flex: 1; }
.ui .tl-b .t { font-size: 12.5px; font-weight: 600; line-height: 1.35; }
.ui .tl-b .w { font-size: 11px; color: var(--muted); margin-top: 2px; line-height: 1.45; }
.ui .tl-b .nt {
    font-size: 11.5px; color: var(--ink-2); margin-top: 6px; line-height: 1.5;
    background: var(--sunken); border-radius: 9px; padding: 8px 10px;
}

.ui .evi { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.ui .evi-t {
    aspect-ratio: 1; border-radius: var(--r-m); border: 1px solid var(--line);
    position: relative; overflow: hidden;
    display: flex; align-items: flex-end; padding: 7px;
    font-size: 9.5px; font-weight: 600; color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,.5);
    background: var(--sunken);
}
.ui .evi-t img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ui .evi-add {
    aspect-ratio: 1; border-radius: var(--r-m);
    border: 1.5px dashed var(--line); background: var(--sunken);
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
    color: var(--muted); cursor: pointer; padding: 8px; text-align: center;
    position: relative; overflow: hidden;
}
.ui .evi-add span { font-size: 10.5px; font-weight: 600; line-height: 1.3; }
.ui .evi-x {
    position: absolute; top: 5px; right: 5px; z-index: 2;
    width: 22px; height: 22px; border-radius: 999px;
    background: rgba(10,15,20,.62); color: #fff; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
}

/* ── 8 · Avisos, hojas, barra de acción, instalar ─────────────────── */

.ui .note {
    display: flex; gap: 11px; align-items: flex-start;
    border-radius: var(--r-l); padding: 13px 14px;
    background: var(--azul-l); border: 1px solid var(--azul-b);
    font-size: 12.5px; line-height: 1.55; color: var(--ink-2);
}
.ui .note.ambar { background: var(--ambar-l); border-color: var(--ambar-b); }
.ui .note.rojo  { background: var(--rojo-l);  border-color: var(--rojo-b); }
.ui .note.verde { background: var(--verde-l); border-color: var(--verde-b); }
.ui .note .ic,
.ui .note > svg { flex-shrink: 0; margin-top: 1px; }

/* El estado vacío ocupa el lugar del resultado que no vino, así que se pinta
   como el resultado: en tarjeta. Suelto sobre el lienzo —como estaba en once
   pantallas— se leía como que la vista todavía no había terminado de cargar, y
   justo ahí es donde el usuario necesita saber que sí terminó y que no hay nada.

   `.plana` y el caso anidado apagan el marco: donde el vacío ya vive dentro de
   una tarjeta, dos marcos concéntricos. */
.ui .vacio {
    text-align: center; padding: 34px 18px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-l);
    box-shadow: var(--sh-s);
}
.ui .card > .vacio,
.ui .lista > .vacio,
.ui .vacio.plana {
    background: none; border: none; border-radius: 0; box-shadow: none;
}
.ui .vacio .ib {
    width: 54px; height: 54px; border-radius: 999px; margin: 0 auto 13px;
    background: var(--sunken); color: var(--muted-2);
    display: flex; align-items: center; justify-content: center;
}
.ui .vacio .t { font-size: 14.5px; font-weight: 600; line-height: 1.35; }
.ui .vacio .s { font-size: 12.5px; color: var(--muted); margin-top: 5px; line-height: 1.55; }

.ui .bar-acc {
    position: sticky; bottom: 0; margin-top: auto; z-index: 10;
    display: flex; gap: 9px; align-items: center;
    padding: 12px 16px calc(18px + env(safe-area-inset-bottom, 0px));
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
    border-top: 1px solid var(--line);
}

/* Hoja inferior sobre el contenido atenuado. */
.ui .sheet-bd {
    position: fixed; inset: 0; z-index: 10000;
    background: rgba(10,15,20,.55);
    display: flex; align-items: flex-end; justify-content: center;
}
.ui .sheet {
    width: 100%; max-width: 560px; max-height: 92%;
    background: var(--canvas); border-radius: 20px 20px 0 0;
    padding: 20px 18px calc(22px + env(safe-area-inset-bottom, 0px));
    overflow-y: auto;
    box-shadow: 0 -14px 44px rgba(0,0,0,.3);
}
.ui .sheet-h { margin-bottom: 14px; }
.ui .sheet-h .t { font-size: 17px; font-weight: 600; line-height: 1.3; }
.ui .sheet-h .s { font-size: 12.5px; color: var(--muted); margin-top: 4px; line-height: 1.55; }
.ui .atenuado { opacity: .4; }

/* El bloque al que acaba de llevar una cifra del banco. Un aro que se apaga: si
   el bloque ya estaba a la vista, el desplazamiento no se nota y el toque se
   leía como que no había pasado nada. */
@keyframes lcm-destello {
    from { box-shadow: 0 0 0 2px var(--verde); }
    to   { box-shadow: 0 0 0 2px transparent; }
}
.lcm-destello {
    border-radius: var(--r-l);
    animation: lcm-destello 1.4s ease-out both;
}
@media (prefers-reduced-motion: reduce) {
    .lcm-destello { animation-duration: .01ms; }
}

/* Las explicaciones largas dejan de ocupar pantalla: viven detrás de un
   enlace. Es un <details>, así que funciona sin JavaScript. */
.ui .aclara { margin-top: 10px; }
.ui .aclara > summary {
    display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
    font-size: 11px; font-weight: 600; color: var(--verde);
    list-style: none; line-height: 1.5;
}
.ui .aclara > summary::-webkit-details-marker { display: none; }
.ui .aclara > summary::after {
    content: ""; width: 6px; height: 6px; flex-shrink: 0;
    border-right: 1.8px solid currentColor; border-bottom: 1.8px solid currentColor;
    transform: rotate(45deg) translate(-1px, -1px);
}
.ui .aclara[open] > summary::after { transform: rotate(-135deg) translate(-1px, -1px); }
.ui .aclara > div, .ui .aclara > p {
    margin: 8px 0 0; font-size: 11px; color: var(--muted); line-height: 1.6;
    border-left: 2px solid var(--line); padding-left: 11px;
}

/* Ayuda a un toque: una «i» junto al control que explica, y el texto se abre
   encima en lugar de ocupar un renglón permanente de la pantalla.

   Sustituye al `<details class="aclara">` que vivía debajo del buscador: la
   gramática de búsqueda es una consulta ocasional —se lee una vez y no se vuelve
   a mirar— y ahí estaba gastando alto en cada carga, además de partir la tira de
   controles en dos. Sigue siendo un `<details>`, así que funciona sin JavaScript
   y el teclado lo abre solo.

   La geometría es la del botón de campana del encabezado: mismo cuadrado de
   34 px, mismo radio, mismo borde. Es un icono más de la fila de controles. */
.ui .info { position: relative; display: inline-flex; flex-shrink: 0; }
.ui .info > summary {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; border-radius: var(--r-m);
    border: 1px solid var(--line); background: var(--surface); color: var(--muted);
    cursor: help; list-style: none;
    font-size: 13px; font-weight: 600; font-style: italic; line-height: 1;
    font-family: Georgia, "Times New Roman", serif;
}
.ui .info > summary::-webkit-details-marker { display: none; }
.ui .info > summary:hover { color: var(--verde-d); border-color: var(--verde-b); }
.ui .info[open] > summary { color: var(--verde-d); border-color: var(--verde); background: var(--verde-l); }
/* El panel se abre hacia la derecha y hacia abajo, y se limita al ancho de la
   ventana: la «i» puede quedar cerca del canto derecho de la pantalla. */
.ui .info-p {
    position: absolute; z-index: 60; top: calc(100% + 8px); left: 0;
    width: max-content; max-width: min(420px, calc(100vw - 32px));
    padding: 15px 17px;
    background: var(--surface); border-radius: var(--r-l);
    box-shadow: var(--sh-l), 0 0 0 1px var(--line);
    font-size: 12.5px; font-weight: 400; color: var(--muted); line-height: 1.65;
}
.ui .info-p > :first-child { margin-top: 0; }
.ui .info-p > :last-child { margin-bottom: 0; }
.ui .info-p code {
    font-family: var(--lcm-mono-font); font-size: .92em; font-weight: 500;
    background: var(--sunken); color: var(--ink-2); border-radius: 5px; padding: 1px 5px;
}
/* Pegada al canto derecho cuando la «i» vive al final de la tira. */
.ui .info.der .info-p { left: auto; right: 0; }

/* Conjuntos largos que no valen media pantalla: el botón dice cuántos hay
   y la lista se abre encima. */
.ui .pop { position: relative; display: inline-block; }
.ui .pop > summary {
    display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
    padding: 9px 14px; border-radius: 999px; border: 1px solid var(--line);
    background: var(--surface); color: var(--ink-2);
    font-size: 12.5px; font-weight: 600; line-height: 1.35; list-style: none;
}
.ui .pop > summary::-webkit-details-marker { display: none; }
.ui .pop > summary::after {
    content: ""; width: 6px; height: 6px; flex-shrink: 0; margin-left: 2px;
    border-right: 1.8px solid var(--muted-2); border-bottom: 1.8px solid var(--muted-2);
    transform: rotate(45deg) translateY(-2px);
}
.ui .pop[open] > summary { border-color: var(--verde); color: var(--verde-d); }
.ui .pop[open] > summary::after { transform: rotate(-135deg) translateY(-1px); }
.ui .pop-p {
    position: absolute; z-index: 30; top: calc(100% + 7px); left: 0;
    min-width: 260px; max-width: min(320px, 78vw); max-height: 208px; overflow-y: auto;
    background: var(--surface); border-radius: var(--r-l);
    box-shadow: var(--sh-l), 0 0 0 1px var(--line);
    scrollbar-width: thin; scrollbar-color: var(--muted-2) var(--sunken);
}
.ui .pop-r {
    display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
    padding: 11px 15px; font-size: 12.5px; line-height: 1.4;
}
.ui .pop-r + .pop-r { border-top: 1px solid var(--line-soft); }
.ui .pop-r b { font-weight: 600; }
.ui .pop-r span { font-size: 11px; font-weight: 500; color: var(--muted-2); font-variant-numeric: tabular-nums; }

/* Aviso de instalar la App, al pie del inicio. Panel oscuro para que no se
   confunda con un registro. Se descarta y no vuelve en 30 días. */
.ui .pwa {
    position: sticky; bottom: 14px; z-index: 40; margin: 4px 16px 18px;
    display: flex; align-items: center; gap: 13px;
    padding: 13px 14px; border-radius: var(--r-l);
    background: var(--ink); color: #fff;
    box-shadow: 0 12px 34px rgba(0,0,0,.28);
}
[data-tema="oscuro"] .pwa { background: #0a0f14; box-shadow: 0 12px 34px rgba(0,0,0,.55), inset 0 0 0 1px var(--line); }
.ui .pwa-i {
    width: 38px; height: 38px; border-radius: 10px; flex-shrink: 0; padding: 7px;
    background: #fff; display: flex; align-items: center; justify-content: center;
}
.ui .pwa-i img, .ui .pwa-i svg { width: 100%; height: 100%; }
.ui .pwa-c { flex: 1; min-width: 0; }
.ui .pwa-c b { display: block; font-size: 13px; font-weight: 600; line-height: 1.35; }
.ui .pwa-c span { display: block; font-size: 11.5px; color: #9fb1c0; margin-top: 2px; line-height: 1.45; }
.ui .pwa-x {
    flex-shrink: 0; width: 30px; height: 30px; border-radius: 999px;
    background: transparent; color: #9fb1c0; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
}
.ui .pwa-x:hover { background: rgba(255,255,255,.1); color: #fff; }

/* El último aviso, primera fila del inicio de cada rol. Es una tarjeta de una
   línea, no un bloque de contenido: se lee de un vistazo y se pulsa para ir a la
   OT. Con más de uno sin leer lleva el carril verde a la izquierda, que es lo
   único que la distingue de una fila cualquiera. */
.ui .aviso-ult {
    display: block; text-decoration: none; color: inherit;
    padding: 12px 14px; margin-bottom: 12px;
}
.ui .aviso-ult:hover { border-color: var(--verde-b); }
.ui .aviso-ult.varios { border-left: 3px solid var(--verde); }
.ui .aviso-ult-t {
    font-size: 13.5px; font-weight: 500; line-height: 1.35; margin-top: 1px;
    /* Un aviso largo envuelve: nunca se recorta. */
    overflow-wrap: anywhere;
}

/* El aviso de permitir notificaciones es anterior al sistema y trae sus colores
   fijos de tema claro: un degradado casi blanco con texto azul marino. Dentro de
   una vista `.ui` en tema oscuro se veía como un recorte de papel pegado sobre
   el lienzo, y el botón secundario quedaba en 1.3:1. Acá adopta las superficies
   del sistema, así que sigue el tema como todo lo demás. Se deja acotado a `.ui`
   para no cambiarle el aspecto a ninguna vista que aún no lo use. */
.ui .lcm-push-banner {
    background: var(--surface);
    border-color: var(--line);
}
.ui .lcm-push-banner-title { color: var(--ink); }
.ui .lcm-push-banner-sub { color: var(--muted); }
.ui .lcm-push-banner .lcm-btn-ghost { color: var(--ink-2); }

/* ── 8b · Visor de documentos ─────────────────────────────────────────
 *
 * El envase de cualquier documento que llegue como HTML autocontenido y se
 * pinte en un iframe: los manuales de hoy y lo que venga después
 * (presentaciones, informes, el portal del desarrollador).
 *
 * Vive acá y no en el CSS aislado de la pantalla a propósito: son piezas del
 * sistema —barra, progreso, buscador, marco— y la segunda vista que muestre un
 * documento las tiene que poder usar sin copiarlas. Las clases van con prefijo
 * `doc-` y no `vis-`, que nombraba una pantalla y no una función.
 */

/* Barra de herramientas del documento. Se queda arriba mientras se baja y no le
   roba ancho al texto: es una banda sobre el lienzo, sin marco. */
.ui .doc-barra {
    position: sticky; top: 0; z-index: 5;
    background: var(--canvas);
    padding: 12px 0;
    display: flex; flex-direction: column; gap: 10px;
    /* Tapa el contenido que pasa por debajo sin alterar el ritmo de la columna. */
    box-shadow: 0 -14px 0 var(--canvas);
}
.ui .doc-barra-fila { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }

.ui .doc-progreso {
    height: 4px; border-radius: 999px;
    background: var(--sunken); overflow: hidden;
}
.ui .doc-progreso i { display: block; height: 100%; background: var(--verde); }

/* Buscador dentro del documento. Crece con el espacio disponible en vez de
   medir un ancho fijo: con `width: 12ch` el rótulo salía recortado —«Buscar en
   el c»— que es justo lo que la App no hace con el texto. */
.ui .doc-busca {
    display: flex; align-items: center; gap: 8px;
    flex: 1 1 300px; min-width: 0;
    height: 40px; padding: 0 6px 0 13px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-m);
    color: var(--muted-2);
}
.ui .doc-busca:focus-within { border-color: var(--verde); }
.ui .doc-busca svg { flex-shrink: 0; }
.ui .doc-campo {
    flex: 1; min-width: 0; width: auto;
    border: none; background: none; padding: 0;
    font-family: inherit; font-size: 13.5px; font-weight: 400;
    color: var(--ink);
}
.ui .doc-campo::placeholder { color: var(--muted-2); }
.ui .doc-campo:focus { outline: none; }
/* El contador y las flechas de coincidencia no se parten del campo. */
.ui .doc-busca-n { flex-shrink: 0; font-variant-numeric: tabular-nums; }
.ui .doc-paso {
    flex-shrink: 0; width: 30px; height: 30px; padding: 0;
    border-radius: var(--r-s); border: none;
    background: var(--sunken); color: var(--ink-2);
    font-family: inherit; font-size: 15px; line-height: 1; cursor: pointer;
}
.ui .doc-paso:hover { background: var(--verde-l); color: var(--verde-d); }

/* El marco del documento. UNA sola barra de desplazamiento en la pantalla: el
   marco crece hasta el alto de su contenido —lo pone el script del visor, que es
   el único que lo conoce— y el scroller es la página. Antes tenía alto fijo y
   barra propia, así que quedaban dos barras verticales pegadas y la rueda del
   ratón hacía una cosa u otra según dónde estuviera el puntero.
   El alto de acá es solo el de arranque, hasta que el documento se mide. */
.ui .doc-marco {
    display: block; width: 100%; min-width: 0;
    height: 70dvh; min-height: 420px;
    overflow: hidden;
    border: 1px solid var(--line);
    border-radius: var(--r-l);
    background: #fff;
}

/* Menú de secciones del documento. Se apoya en `.pop` del sistema —el mismo
   desplegable de las tiendas del perfil— y solo ajusta lo suyo: el rótulo no se
   parte, y el panel entra más alto porque un manual tiene veintitantas
   secciones y valen la pena de un vistazo. */
.ui .doc-indice { flex-shrink: 0; min-width: 0; }
.ui .doc-indice > summary { max-width: min(340px, 100%); }
.ui .doc-indice-t { overflow-wrap: anywhere; }
.ui .doc-indice-p { max-height: 60dvh; min-width: 280px; max-width: min(420px, 88vw); padding: 6px; }
/* Una fila del índice: el número pegado al nombre y el nombre completo, que
   nunca se recorta — acá sí es contenido. */
.ui .doc-sec {
    display: block; width: 100%; text-align: left;
    background: none; border: none; border-radius: var(--r-s);
    font-family: inherit; font-size: 12.5px; font-weight: 400;
    line-height: 1.5; color: var(--ink-2);
    padding: 8px 10px; cursor: pointer;
}
.ui .doc-sec span { color: var(--muted-2); margin-right: 7px; font-variant-numeric: tabular-nums; }
.ui .doc-sec:hover { background: var(--sunken); color: var(--ink); }
.ui .doc-sec.on { background: var(--verde-l); color: var(--verde-d); font-weight: 500; }
.ui .doc-sec.on span { color: var(--verde); }

@container (max-width: 699px) {
    /* La barra SIGUE pegada en teléfono: acá vive el menú de secciones, y un menú
       que se va con el desplazamiento no sirve para saltar de sección — que es
       justo para lo que existe. Lo que se compacta es el resto: el buscador toma
       su renglón y el menú se estira a todo el ancho del primero. */
    .ui .doc-busca { flex: 1 1 100%; }
    .ui .doc-indice { flex: 1 1 auto; }
    .ui .doc-indice > summary { max-width: none; width: 100%; }
}

/* ── 9 · Responsive por container query ───────────────────────────── */

/* Helpers de visibilidad por tramo: `d-*` aparece de 700 px de contenedor para
   arriba, `x-*` solo en monitor, `m-only` solo en teléfono.

   Los tres `d-*` COLISIONAN CON BOOTSTRAP, que los declara con !important
   (`.d-block{display:block!important}`, 5.3.3). Sin !important acá el
   `display: none` perdía por más específico que fuera el selector —!important
   gana antes de que la especificidad se mire—, y la tabla de escritorio se
   dibujaba en el teléfono ADEMÁS de la lista `m-only`: nueve usos en siete
   pantallas.

   El !important tiene que ir en LOS DOS lados: acá y en el container query que
   los enciende. Si solo va en este, el tramo de escritorio pierde contra él y
   la tabla no aparece nunca.

   `x-*` no colisiona —bootstrap no tiene esos nombres— pero se escribe igual:
   son la misma familia, y la simetría es lo que evita que el próximo que se
   agregue nazca roto. */
.ui .d-block, .ui .d-flex, .ui .d-grid { display: none !important; }
.ui .x-block, .ui .x-flex, .ui .x-grid { display: none !important; }
.ui .x-cell { display: none !important; }

.ui .meta dd.urg { color: var(--rojo); }
.ui input.pill.busca { color: var(--ink); font-weight: 600; }
.ui input.pill.busca::placeholder { color: var(--muted-2); font-weight: 600; }
.ui input.pill.busca:focus { outline: none; border-color: var(--verde); }

/* ── El teléfono INVIERTE las superficies ─────────────────────────────────
 *
 * En escritorio el bloque es una tarjeta blanca con filete sobre un lienzo gris:
 * hay ancho de sobra y el borde es lo que separa un panel de su vecino. En un
 * teléfono ese lenguaje se cae. La pantalla es un solo bloque de 390 px, así que
 * el «lienzo» apenas se ve —queda un marco de 16 px por lado— y lo único que
 * aporta cada filete es una raya oscura pegada al canto. Diez bloques hacen diez
 * rectángulos dibujados y la vista se lee como una planilla.
 *
 * En teléfono se da la vuelta: la PÁGINA es blanca y el BLOQUE es gris claro, sin
 * borde y sin sombra, con más radio. El contraste que separa un bloque de otro lo
 * hace el relleno, no una línea.
 *
 * Se resuelve redefiniendo los TOKENS y no regla por regla: la app entera
 * —tarjetas, listas, tejas, indicadores, hojas— cambia de piel de una vez, y
 * cualquier bloque que se agregue mañana nace adaptado.
 *
 * ⚠️ VA POR MEDIA QUERY, NO POR CONTAINER QUERY, y esto no es una preferencia.
 * Un `@container` no puede estilar al contenedor que consulta: solo alcanza a sus
 * descendientes. Los tokens viven en `.ui`, que ES el contenedor —lleva
 * `container-type: inline-size`— así que dentro de un `@container` la regla nunca
 * se aplicaba. Estuvo escrita así desde el primer día y no hizo NADA: el teléfono
 * siguió pintando con los tokens de escritorio, tarjetas blancas con filete
 * visible y sombra, que es lo que se veía y yo daba por corregido. Medido: los
 * fondos de la bandeja a 390 px salían en rgb(255,255,255).
 * Las demás reglas de ese bloque sí funcionaban, porque apuntan a descendientes
 * (`.ui .card`, `.ui .kpis`…); solo los tokens estaban muertos. */
@media (max-width: 699px) {
    .ui {
        --canvas:    #ffffff;
        --surface:   #f4f5f8;
        --sunken:    #eaecf1;
        /* Sin bordes: en teléfono el marco lo hace el color del bloque. */
        --line:      transparent;
        /* El filete ENTRE filas sí queda: es lo que separa un registro del
           siguiente dentro de un mismo bloque, y ahí sí hace falta. Vive sobre
           gris y no sobre blanco, así que sube algo de tono — pero lo justo: a
           #dfe3e9 la lista se leía rayada, con la línea compitiendo con el texto
           en vez de separarlo. */
        --line-soft: #e7eaef;
        --sh-s:      none;
        --sh-m:      none;
        --r-m: 12px; --r-l: 16px; --r-xl: 20px;
    }
    /* El tema oscuro no se invierte: ahí el lienzo ya es más oscuro que el
       bloque, que es la relación correcta en los dos tamaños. */
    [data-tema="oscuro"] .ui,
    .ui[data-tema="oscuro"] {
        --canvas:    #0f151b;
        --surface:   #161d24;
        --sunken:    #1c252e;
        --line:      transparent;
        --line-soft: #26313c;
    }

    /* El SCROLLER también tiene que ponerse blanco, y solo el lienzo.
     *
     * `.lcm-body` se pinta con `background: var(--canvas)` pero vive FUERA de
     * `.ui` —es su padre—, así que ese token lo resuelve contra `.ui-shell`, que
     * declara los valores de escritorio. Sin esta regla la inversión quedaba a
     * medias: los bloques bajaban a gris (#f4f5f8) sobre una página que seguía
     * en gris (#f7f8fa), dos por ciento de diferencia, y no se distinguía un
     * bloque de la página.
     *
     * Se le cambia SOLO `--canvas`. `--surface` se queda como está a propósito:
     * de él viven la barra inferior de pestañas y el botón de volver arriba, que
     * son el suelo y el cromo de la app, no bloques de contenido — y en una
     * página blanca tienen que seguir siendo claros. */
    .ui-shell:has(.ui) { --canvas: #ffffff; }
    /* En oscuro NO se invierte nada, así que el lienzo vuelve al suyo. La regla
       de arriba vale (0,2,0) igual que la del bloque oscuro base y llega
       después, así que sin esta contraparte le ganaba y dejaba la página blanca
       debajo de una app oscura. */
    [data-tema="oscuro"] .ui-shell:has(.ui) { --canvas: #0f151b; }
}

@container (max-width: 699px) {
    /* En un teléfono el panel oscuro se come media vista y no aporta nada:
       pierde el fondo y queda como una banda más, con la cifra en tinta y
       las acciones como filas normales. */
    .ui .turno, [data-tema="oscuro"] .turno {
        background: transparent; border: none; color: inherit;
        padding: 0; gap: 12px; border-radius: 0;
    }
    .ui .turno .eyebrow { color: var(--muted-2); }
    .ui .turno-n { font-size: 32px; }
    .ui .turno-t { color: var(--muted); font-size: 12.5px; }
    .ui .turno-list { gap: 0; background: var(--surface); border-radius: var(--r-l); overflow: clip; }
    .ui .turno-item {
        background: transparent; color: inherit; border-radius: 0;
        padding: 12px 14px; position: relative;
    }
    .ui .turno-item + .turno-item::before {
        content: ""; position: absolute; left: 14px; right: 14px; top: 0;
        height: 1px; background: var(--line-soft);
    }
    .ui .turno-item .s { color: var(--muted); }
    .ui .turno-item .n { background: var(--verde-l); color: var(--verde-d); }

    /* Seis etiquetas en 390 px se parten en tres renglones cada una y el
       resultado es ilegible: solo se nombra el paso actual. */
    .ui .pipe { position: relative; padding-bottom: 20px; }
    .ui .pipe-s .lb { display: none; }
    .ui .pipe-s.now .lb {
        display: block; position: absolute; top: 9px; left: 0; right: 0;
        margin: 0; font-size: 10.5px; font-weight: 600;
    }

    /* EL ENCABEZADO DE TELÉFONO, EN UN SOLO LUGAR.
     *
     * Cuatro piezas y un orden, igual en las treinta y tres pantallas y en los
     * cinco roles:
     *
     *     ┌─────────────────────────────────────────────┐
     *     │ ←  Titular                    ⚙ 📅 📖 🔔 👤 │
     *     │ subtítulo                                   │
     *     └─────────────────────────────────────────────┘
     *
     * El titular arriba y a la izquierda, los accesos del rol arriba y a la
     * derecha, el subtítulo debajo de los dos y a todo el ancho. Lo que cambia
     * de una pantalla a otra es QUÉ dice el titular y CUÁLES son los iconos —los
     * inyecta `AccesosRol` según el rol—; la forma no cambia nunca.
     *
     * El subtítulo vive DENTRO de `.ui-mtitle` en el marcado, que es donde tiene
     * sentido: es el subtítulo de ese titular. Para sacarlo a su propio renglón
     * sin migrar treinta y tres pantallas, el envoltorio se disuelve con
     * `display: contents` y sus dos hijos pasan a ser piezas del encabezado. Así
     * el layout se declara UNA vez y ninguna pantalla tiene que saber de él.
     *
     * El titular baja a 24 px en teléfono. A 27 px «Administración» mide 187 px
     * y junto a cinco accesos le quedaban 162: la única salida sin recortar el
     * nombre de la pantalla —que no se recorta— era mandarlo a un renglón
     * propio, y eso empujaba el contenido 40 px hacia abajo en todas las
     * pantallas. A 24 px entra al lado de los iconos y sigue siendo un titular
     * grande. */
    .ui-mtop { flex-wrap: wrap; align-items: center; column-gap: 8px; row-gap: 5px; }
    .ui-mtitle { display: contents; }
    .ui-back { order: 1; }
    /* `flex: 1 1 0` y no `auto`: con base automática el titular reserva su ancho
       natural, y uno largo —«Administración», 166 px— empujaba los accesos a un
       renglón propio. Con base cero el titular se queda con lo que sobra después
       del volver y de los iconos, así que la forma del encabezado NO depende de
       lo largo que sea el nombre de la pantalla: si no entra, envuelve él. */
    /* 21 px y no 24: el titular sigue siendo lo más grande del encabezado y
       deja de ser un cartel. `line-height: 1.2` y no 1.08 — a 1.08 la caja de la
       línea queda MÁS CORTA que el área del glifo, así que el acento de «Órdenes»
       se salía por arriba y el conteo del renglón de abajo aparecía cortado por
       el titular. Con la caja completa y 5 px de `row-gap`, el subtítulo se lee
       entero. */
    .ui-mtitle b { order: 2; flex: 1 1 0; min-width: 0; font-size: 21px; line-height: 1.2; overflow-wrap: anywhere; }
    .ui-mtop-acts { order: 3; margin-left: auto; }
    .ui-mtitle span { order: 4; flex: 1 1 100%; margin-top: 0; font-size: 11.5px; line-height: 1.45; }
    /* Los accesos se aprietan en teléfono: son cinco y compiten con el titular
       por 358 px. A 30 px el área de toque sigue por encima del mínimo de 44 px
       contando el relleno del encabezado. */
    .ui .lcm-bell-btn { width: 30px; height: 30px; border-radius: 8px; }
    .ui .ui-mtop-acts { gap: 3px; }

    .ui .pill.desp { display: none; }
    .ui .f-mas { display: inline-flex; }
    /* El buscador se queda con todo el renglón MENOS lo que ocupa la «i», que va
       a su lado. Con `flex: 1 1 100%` el campo forzaba línea completa y la «i»
       caía sola en un tercer renglón, gastando 34 px de alto para un icono. */
    .ui .pill.busca { flex: 1 1 auto; min-width: 0; height: 44px; padding: 0 15px; font-size: 14px; border-radius: var(--r-m); }
    .ui .filtros > .busca,
    .ui .filtros > .info { order: -1; }

    /* La tira de filtros SE DESLIZA en horizontal, no envuelve.
     *
     * Es lo contrario de lo que decía la regla original, y el cambio es a
     * conciencia: seis pastillas en 358 px de ancho útil se parten en TRES
     * renglones, y con el buscador arriba la tarjeta de controles se comía un
     * tercio de la pantalla antes de mostrar una sola orden. Un carril de una
     * línea que se arrastra con el dedo es el patrón del sistema operativo y el
     * de las referencias, y deja el mismo contenido en 44 px de alto.
     *
     * Vale para la tira de filtros, no para el contenido: una fila de OT sigue
     * envolviendo, porque ahí lo que se recorta es información y no controles.
     *
     * El desplazamiento se declara con `-webkit-overflow-scrolling` y se le
     * quita la barra: en un teléfono la barra tapa media pastilla y el gesto ya
     * dice que hay más. Se compensa con relleno para que la última no quede
     * lamiendo el canto. */
    .ui .tira {
        display: flex;
        order: 1;
        flex: 1 1 100%;
        min-width: 0;
        align-items: center;
        gap: 8px;
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
        /* Sangra hasta el canto y compensa con relleno, para que la primera
           pastilla arranque alineada con el texto y la última no quede lamiendo
           el borde de la pantalla. */
        margin-inline: -16px;
        padding-inline: 16px;
        padding-bottom: 2px;
    }
    .ui .tira::-webkit-scrollbar { display: none; }
    .ui .tira > * { flex-shrink: 0; }
    /* El buscador toma su propio renglón y va PRIMERO: es el control que más se
       usa y el único que necesita ancho para leerse. */
    .ui .filtros > .busca { order: -1; }

    /* Los controles NO se quedan fijos en teléfono. En escritorio la barra vive
       bajo el topbar y ocupa 60 px de 900 de alto; en un teléfono de 780 px se
       queda con el 20 % de la pantalla de forma permanente, tapando justo las
       órdenes que se fueron a buscar. Acá el pulgar llega al tope con un gesto,
       que es más barato que ceder ese alto para siempre. */
    .ui .fija { position: static; box-shadow: none; }

    /* La pista de las vistas guardadas es una frase de dos renglones que explica
       algo que se descubre usándolo. En teléfono se calla. */
    .ui .vistas-pista { display: none; }

    /* La barra de acción es el SUELO de la pantalla, así que toma el color de la
       página y no el del bloque. Con la inversión de superficies quedaba gris
       —`--surface` es el bloque en teléfono— y sin filete —`--line` es
       transparente—, o sea una banda del mismo color que las tarjetas y sin nada
       que la separara del contenido que pasa por debajo. Es el mismo defecto que
       tenía la barra inferior de navegación, en el otro extremo del sistema.
       Los botones se reparten el ancho: dos acciones a media pantalla cada una se
       aciertan con el pulgar; alineadas a la derecha, no. */
    .ui .bar-acc {
        background: color-mix(in srgb, var(--canvas) 94%, transparent);
        border-top: 1px solid var(--line-soft);
        padding: 12px 16px calc(14px + env(safe-area-inset-bottom, 0px));
        flex-wrap: wrap;
        /* Estirados para que los dos midan lo mismo cuando uno envuelve. */
        align-items: stretch;
    }
    .ui .bar-acc > .grow { flex: 1 1 100%; }
    /* El botón de la barra CRECE en alto en vez de recortar su etiqueta.
     *
     * `.btn.lg` tiene 44 px fijos, y la acción primaria de estas pantallas dice
     * «Confirmar y marcar como Atendida»: treinta y un caracteres en un botón que
     * en un teléfono mide dos tercios de 358 px. Envuelve en dos renglones y con
     * alto fijo el segundo se sale de la caja. La regla de la casa es que no se
     * recorta texto, así que manda el contenido y el alto se acomoda. */
    .ui .bar-acc > .btn {
        flex: 1 1 auto; max-width: none;
        height: auto; min-height: 48px;
        padding: 11px 16px; white-space: normal;
    }

    /* La barra de acción se sienta ENCIMA de la barra inferior.
     *
     * Las dos son fijas al pie y competían por el mismo lugar: la de navegación es
     * `fixed` y la de acción `sticky`, así que la acción primaria de la pantalla
     * quedaba detrás de los tres destinos.
     *
     * Hacen falta las dos medidas: `bottom` sube el punto donde la barra se pega
     * mientras se desplaza, y `margin-bottom` le reserva el hueco para cuando el
     * contenido termina — sin el margen, al llegar al final del desplazamiento la
     * barra volvía a su sitio natural y se metía debajo de las pestañas. */
    .ui-shell:has(.lcm-tabs) .ui .bar-acc {
        bottom: var(--alto-tabs);
        margin-bottom: var(--alto-tabs);
    }

    /* ── Los CONTROLES toman el color de la página ─────────────────────────
     *
     * Consecuencia obligada de invertir las superficies, y sin esto la
     * inversión es un downgrade: todos los controles del sistema se pintan con
     * `--surface` o `--sunken`, que en teléfono son el color del BLOQUE. Un
     * campo gris sobre una tarjeta gris es un campo invisible; la pestaña
     * activa del segmentado quedaba en #f4f5f8 sobre #eaecf1 —dos por ciento de
     * diferencia y sin sombra— así que no se sabía cuál estaba elegida.
     *
     * La regla es la del sistema operativo del teléfono: el bloque es gris y lo
     * que se toca es BLANCO, es decir el color de la página. Se invierte la
     * relación completa, no solo el fondo. */
    .ui .input,
    .ui .pill,
    .ui .opt,
    .ui .ficha,
    .ui .chips button,
    .ui .lrow,
    .ui .lcm-search-input,
    .ui .lcm-tools-btn,
    .ui .card.soft { background: var(--canvas); }
    .ui .lcm-search-input,
    .ui .lcm-tools-btn { border-color: var(--line-soft); }
    .ui .lcm-tools-dot { border-color: var(--canvas); }

    /* La pestaña activa se «levanta» del carril hundido con el color de la
       página y una sombra propia — la del sistema es `none` en teléfono, así que
       acá se declara a mano por ser el único indicador que queda. */
    .ui .seg { background: var(--sunken); padding: 4px; border-radius: var(--r-m); }
    .ui .seg button.on {
        background: var(--canvas); color: var(--ink);
        box-shadow: 0 1px 3px rgba(22, 24, 29, .10);
    }
    /* La pastilla encendida no necesita nada acá: `.ui .pill.on` le gana por
       especificidad al `background: var(--canvas)` de la lista de arriba, así
       que su relleno sólido sobrevive a la inversión de controles. */

    /* Un campo tiene que verse como un hueco donde se escribe: sobre bloque
       gris le queda un filete propio, porque `--line` es transparente. */
    .ui .input { border-color: var(--line-soft); }
    .ui .input:focus { border-color: var(--verde); }

    /* ── Aire de teléfono, no de escritorio ───────────────────────────────
     *
     * Los rellenos de 18 y 22 px son de una pantalla de 1500: en 390 px se comen
     * el ancho del contenido. Bajan un escalón, no dos — el bloque tiene que
     * seguir respirando o vuelve a leerse como una planilla. */
    .ui .card.pad { padding: 13px; }
    .ui .card.pad-l { padding: 15px; }
    .ui .card-h { padding: 12px 14px; }
    .ui .card-b { padding: 13px 14px 14px; gap: 11px; }
    .ui .card-f { padding: 10px 14px 12px; }
    .ui .li { padding: var(--li-py) 14px; gap: 10px; }
    /* Los dos renglones de metadatos envuelven en tres o cuatro lineas dentro de
       390 px, y `gap: 12px` los separaba como párrafos: doce píxeles entre
       «Coord. …» y «Creada …» dentro de una MISMA fila. El aire entre columnas se
       queda; el de entre renglones baja a cuatro. */
    .ui .li-m { gap: 4px 12px; margin-top: 4px; }
    .ui .li-top { gap: 3px 7px; }
    /* El filete va DE CANTO A CANTO en teléfono.
     *
     * En escritorio se sangra 18 px a cada lado y ahí funciona: la fila es ancha,
     * el filete se lee como un separador y el aire de los extremos lo despega del
     * borde de la tarjeta. En 430 px ese mismo sangrado deja un segmento con
     * agujeros a los dos lados, y el ojo no lo lee como «separa dos filas» sino
     * como «acá hay algo cortado» — que es exactamente la palabra que usó Silvio.
     * A todo el ancho vuelve a ser una línea y no un trozo de línea. El radio de
     * la tarjeta lo recorta en la primera y la última, que ya tienen `overflow:
     * clip`, así que no asoma por las esquinas. */
    .ui .li::after { left: 0; right: 0; }
    .ui .lista-h { padding: var(--lista-h-py) 14px 7px; }

    /* El banco de indicadores va de DOS en fondo.
     *
     * A una columna, seis tarjetas de 100 px son 600 px de desplazamiento antes
     * de llegar a la primera orden del día — el técnico abre la app para ver su
     * ruta, no para leer seis números. De dos en fondo entran tres renglones y
     * la ruta queda a la vista casi sin bajar. La cifra baja de 30 a 25 px, que
     * en la mitad del ancho sigue siendo lo más grande del bloque. */
    .ui .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px; }
    .ui .kpi { padding: 12px 13px 11px; gap: 7px; }
    .ui .kpi-v { font-size: 22px; }
    .ui .kpi-v.chica { font-size: 17px; }
    .ui .kpi-i { width: 28px; height: 28px; border-radius: 8px; }
    .ui .kpi-h { gap: 8px; }
    .ui .kpi-l { font-size: 11px; }
    .ui .kpi-f { font-size: 10.5px; }
    /* La nota del pie envuelve en dos renglones dentro de media columna: el chip
       deja de forzar una línea y se ajusta al ancho que le toca. */
    .ui .kpi > .chip { white-space: normal; }

    /* Las tejas de los otros inicios siguen la misma regla. */
    .ui .cifras.tejas { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px; }
    .ui .cifras.tejas > .cifra { padding: 12px 13px 11px; }
    .ui .cifras.tejas > .cifra .v { font-size: 20px; }

    /* La ficha de datos APILA la etiqueta sobre el valor.
     *
     * `.meta` pone la etiqueta a la izquierda y el valor a la derecha, alineado
     * al canto. En 390 px «Granada Centro · S039 · Zona Sur» contra «Tienda»
     * deja el valor partido en tres renglones pegados al borde derecho, y el ojo
     * tiene que saltar de un lado al otro por cada dato. Apilado se lee como una
     * lista de pares, que es lo que es. */
    .ui .meta { display: block; }
    .ui .meta dt { font-size: 11.5px; color: var(--muted); }
    .ui .meta dd { text-align: left; margin-top: 3px; font-size: 13.5px; }
    .ui .meta-list { gap: 14px; }

    /* El reparto por tienda: nombre y cifra en un renglón, la barra debajo a todo
       el ancho. En tres columnas el nombre de la tienda quedaba en 96 px y la
       barra en 60: dos datos ilegibles para dejar entrar un tercero. */
    /* La colocación va EXPLÍCITA. `.rank-b` es el segundo hijo, así que con
       colocación automática y `grid-column: 1 / -1` se baja de renglón y empuja
       la cifra a un tercero. Con fila y columna dichas a mano, los tres caen
       donde deben sin depender del orden del marcado. */
    .ui .rank-f {
        grid-template-columns: 1fr auto;
        column-gap: 12px; row-gap: 7px;
        padding: 11px 0;
    }
    .ui .rank-n { grid-column: 1; grid-row: 1; }
    .ui .rank-v { grid-column: 2; grid-row: 1; }
    .ui .rank-b { grid-column: 1 / -1; grid-row: 2; }

    /* La barra de pestañas va superpuesta al pie: el aviso se aparta. */
    .ui .pwa { flex-wrap: wrap; bottom: 82px; margin-bottom: 90px; }
    .ui .pwa-c { flex: 1 1 100%; order: 2; }
    .ui .pwa .btn { order: 3; flex: 1; }
    .ui .pwa-x { order: 1; margin-left: auto; }

    /* ── UNA escala para el teléfono, y la misma en los cinco roles ───────
     *
     * La app se diseñó en un monitor y bajó al teléfono con la tipografía de
     * escritorio: el titular de la pantalla en 24 px, la cifra de una teja en
     * 25, la descripción de una OT en 15 y el monto en 21. Cada bloque medía
     * bien por su cuenta y la pantalla entera medía mal — en 390 px una sola
     * tarjeta de firma llenaba el alto útil, y para leer cinco había que
     * recorrer cinco pantallas.
     *
     * Los números de acá no son un gusto: es un escalón menos en TODO lo que
     * está por encima del cuerpo de texto (14 px), que es lo que un teléfono
     * puede sostener sin que un bloque se coma el turno del siguiente.
     * Va en un solo lugar y por eso vale para los cinco roles: lo que se
     * arreglaba pantalla por pantalla volvía a nacer torcido en la siguiente. */
    .ui .h1 { font-size: 21px; }
    .ui .h2 { font-size: 17px; }
    .ui .h3 { font-size: 13.5px; }
    .ui .card-h h3, .ui .banda-h h3 { font-size: 13px; }
    .ui .banda-h { margin-bottom: 10px; }
    .ui .li-t { font-size: 13.5px; line-height: 1.45; }
    .ui .cifra .v { font-size: 22px; }
    .ui .cifra .v.chica { font-size: 17px; }
    .ui .cifras:not(.tejas) > .cifra.ancha .v { font-size: 22px; }
    .ui .toca { padding: 11px 12px; gap: 11px; }
    .ui .toca-t { font-size: 13.5px; }
    .ui .toca-n, .ui .toca-i { width: 34px; height: 34px; border-radius: 10px; font-size: 15px; }

    /* La tarjeta de la cola de firma. Es el caso más caro: descripción de la
     * OT en mayúsculas y de tres renglones, monto en 21 px, proveedor, vence,
     * criticidad y dos botones. Con la escala de escritorio medía 330 px de
     * alto por orden. */
    .ui .otc { padding: 11px 12px 12px; }
    .ui .otc-t { margin-top: 7px; font-size: 13.5px; line-height: 1.3; }
    .ui .otc-s { margin-top: 2px; font-size: 11.5px; }
    .ui .otc-sep { margin: 9px 0 8px; }
    .ui .otc-monto { font-size: 17px; }
    .ui .otc-prov { margin-top: 7px; font-size: 11.5px; }
    .ui .otc-meta { font-size: 11px; }
    .ui .otc-acts { margin-top: 10px; }
    .ui .otc-ico { width: 28px; height: 28px; border-radius: 8px; }
    .ui .otcs { gap: 9px; }

    /* Sube un bloque al tope, solo en móvil. */
    .ui .m-arriba { order: -1; }
}

@container (min-width: 700px) {
    /* !important obligado en toda la familia: el tramo de teléfono también lo
       lleva —para ganarle a bootstrap— y sin él acá perdería contra sí mismo. */
    .ui .m-only { display: none !important; }
    .ui .d-block { display: block !important; }
    .ui .d-flex  { display: flex !important; }
    .ui .d-grid  { display: grid !important; }

    .ui-pad { padding: 22px 26px 40px; gap: 18px; }
    .ui-mtop { padding: 22px 26px 4px; }
    .ui .h1 { font-size: 23px; }
    .ui .evi { grid-template-columns: repeat(5, 1fr); }
    .ui .turno { flex-direction: row; align-items: center; gap: 22px; }
    .ui .turno-h { flex: 0 0 210px; flex-direction: column; align-items: flex-start; gap: 4px; }
    .ui .turno-list { flex: 1; display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 8px; }
    .ui .cifras:not(.tejas) { grid-template-columns: repeat(3, minmax(0,1fr)); }
    .ui .cifras:not(.tejas) > .cifra:nth-child(2n+1) { border-left: 1px solid var(--line); padding-left: 14px; }
    .ui .cifras:not(.tejas) > .cifra:nth-child(3n+1) { border-left: none; padding-left: 0; }
    .ui .cifra .v { font-size: 27px; }
    /* Con tres columnas el monto ya entra en su celda: la cifra ancha vuelve a
       ser una más y la rejilla recupera su paridad de siempre. */
    .ui .cifras:not(.tejas) > .cifra.ancha { grid-column: auto; }
    .ui .cifras:not(.tejas):has(> .cifra.ancha) > .cifra:nth-child(2n),
    .ui .cifras:not(.tejas):has(> .cifra.ancha) > .cifra:nth-child(2n+1):not(.ancha) {
        border-left: 1px solid var(--line); padding-left: 14px;
    }
    .ui .cifras:not(.tejas):has(> .cifra.ancha) > .cifra:nth-child(3n+1) {
        border-left: none; padding-left: 0;
    }
    /* Las tejas no llevan cuenta de columnas por tramo: las reparte `auto-fit`
       contra su ancho mínimo, que es lo único que sigue siendo cierto cuando el
       marco llega al borde de la pantalla. */
    /* Acá se le devolvía a `.lista.sangre` el marco que perdía en teléfono. Ya no
       hace falta: la lista no sangra en ningún tamaño. */
    .ui .bar-acc { padding-bottom: 14px; }
}

@container (min-width: 1080px) {
    .ui-pad { padding: 24px 30px 44px; }
    .ui .g2 { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 16px; align-items: start; }
    .ui .g3 { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 16px; align-items: start; }
    .ui .g-main { display: grid; grid-template-columns: minmax(0,1fr) 320px; gap: 18px; align-items: start; }
    .ui .g-form { display: grid; grid-template-columns: minmax(0,1fr) 300px; gap: 18px; align-items: start; }
    .ui .turno-list { grid-template-columns: repeat(3, minmax(0,1fr)); }
    .ui .cifras:not(.tejas) { grid-template-columns: repeat(6, minmax(0,1fr)); }
    .ui .cifras:not(.tejas) > .cifra:nth-child(3n+1) { border-left: 1px solid var(--line); padding-left: 14px; }
    .ui .cifras:not(.tejas) > .cifra:nth-child(6n+1) { border-left: none; padding-left: 0; }
}

@container (min-width: 1440px) {
    .ui .x-block { display: block !important; }
    .ui .x-flex  { display: flex !important; }
    .ui .x-grid  { display: grid !important; }
    .ui .x-cell  { display: table-cell !important; }
    /* Lo que solo existe mientras el panel de contexto no cabe (la vista
       previa en laptop) se apaga cuando el panel aparece. Gana al `d-block` que
       la enciende porque llega después con la misma fuerza. */
    .ui .hasta-ctx { display: none !important; }
    .ui-ctx { display: flex; }
    .ui-pad { padding: 26px 34px 48px; }
}

/* Monitor ancho. `.ui-wrap` ya no tiene tope —el marco llega al borde— así que
   lo único que crece es el margen de respiración y el número de columnas que
   la rejilla de cifras reparte por su cuenta. */
@container (min-width: 1800px) {
    .ui-pad { padding: 28px 44px 52px; gap: 20px; }
    .ui-mtop { padding: 26px 44px 4px; }
}

/* ═══ El hito de cobertura ═══════════════════════════════════════════
   El 5 de agosto de 2026 terminó la capacitación de las 57 tiendas: es el
   primer día cuyos números hablan de todas. La marca es un ANILLO, no un
   color: las seis tintas del sistema ya están repartidas entre estados,
   tipos y criticidades, y una séptima se leería como un bucket más. El
   anillo es la misma figura en el calendario del mes y al pie de cada
   selector de rango, así que se aprende una vez.

   Vive acá y no en un `.razor.css` porque la marca aparece en cuatro
   pantallas de tres roles distintos; repetida en cada una, la primera
   corrección dejaría cuatro sellos distintos. */

.ui .cobertura {
    grid-column: 1 / -1;
    display: flex; align-items: flex-start; flex-wrap: wrap; gap: 8px 11px;
    margin-top: 12px; padding: 11px 13px;
    background: var(--indigo-l); border: 1px solid var(--indigo-b);
    border-radius: var(--r-l);
    font-size: 12px; line-height: 1.55; color: var(--ink-2);
}
.ui .cobertura-m {
    position: relative; flex-shrink: 0;
    width: 15px; height: 15px; margin-top: 1px;
    border-radius: 999px; box-shadow: inset 0 0 0 2px var(--indigo);
}
.ui .cobertura-m::after {
    content: ""; position: absolute; inset: 5px;
    border-radius: 999px; background: var(--indigo);
}
/* El texto se acomoda entero: `min-width: 0` deja que el párrafo se parta en
   varios renglones en vez de estirar la línea y empujar el botón fuera. */
.ui .cobertura-t { margin: 0; flex: 1 1 220px; min-width: 0; }
.ui .cobertura-t b { font-weight: 600; color: var(--ink); }
.ui .cobertura-b {
    flex-shrink: 0; padding: 7px 13px; border: none; border-radius: 999px;
    /* La tinta del botón es el lienzo, no `#fff`: en tema oscuro el índigo se
       aclara y el blanco literal quedaba blanco sobre casi blanco. Los dos
       tokens se invierten juntos. */
    background: var(--indigo); color: var(--canvas);
    font-family: inherit; font-size: 11.5px; font-weight: 600; line-height: 1.3;
    cursor: pointer;
}
.ui .cobertura-b:hover { filter: brightness(1.08); }

/* En una barra fija el alto es caro: la nota se queda sin marco y en el
   cuerpo de texto de la barra, pegada al rango que explica. */
.ui .cobertura.compacta {
    margin-top: 8px; padding: 0;
    background: none; border: none; border-radius: 0;
    font-size: 11.5px;
}
.ui .cobertura.compacta .cobertura-m { width: 13px; height: 13px; margin-top: 1px; }
.ui .cobertura.compacta .cobertura-m::after { inset: 4.5px; }
.ui .cobertura.compacta .cobertura-b { padding: 5px 11px; font-size: 11px; }

/* ── La barra de mando de los tableros ──────────────────────────────
   Nació en el panel del CMO (p37) y hoy la comparten el panel y la vista de
   Tiempos, así que sube al sistema: rango de fechas en cápsula, segmentado de
   medida, contador de filtros del cajón y el propio cajón. Lo que sigue siendo
   de UNA pantalla (desglose del monto, apiladas, árbol) se queda en su css. */

.ui .barra-fija { display: flex; flex-direction: column; gap: 10px; }
.ui .barra-cmo { row-gap: 10px; }

/* Los dos campos del rango van pegados dentro de una misma cápsula, con la
   flecha en medio: son las dos puntas de una cosa sola, no dos filtros. */
.ui .rango {
    display: flex; align-items: center; gap: 8px;
    padding: 5px 12px; min-width: 0;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: 11px; box-shadow: var(--sh-s);
}
.ui .rango-c { display: flex; flex-direction: column; gap: 1px; min-width: 0; margin: 0; }
.ui .rango-l { font-size: 9.5px; font-weight: 600; color: var(--muted-2); line-height: 1.3; }
.ui .rango-i {
    border: none; background: none; padding: 0; margin: 0;
    font-family: inherit; font-size: 12.5px; font-weight: 600; color: var(--ink);
    line-height: 1.35; min-width: 0; width: 100%;
    font-variant-numeric: tabular-nums;
}
.ui .rango-i:focus { outline: none; color: var(--verde-d); }
.ui .rango-sep { font-size: 12px; color: var(--muted-2); flex-shrink: 0; }

/* El segmentado de la barra no se reparte en mitades: cada botón toma el ancho
   de su texto, que es la única forma de que «Monto C$» no se quiebre. */
.ui .medida { flex: 0 0 auto; }
.ui .seg.medida button { flex: 0 0 auto; }

/* La recarga y su fallo se dicen en una línea bajo la barra, no tapando el
   tablero: con datos viejos en pantalla lo dudoso es su frescura. */
.ui .recarga { margin: 0; }

/* Contador de filtros del cajón sobre la píldora. */
.ui .cuenta {
    font-variant-numeric: tabular-nums;
    background: var(--verde); color: #fff; border-radius: 999px;
    min-width: 17px; height: 17px; padding: 0 5px;
    display: inline-flex; align-items: center; justify-content: center; font-size: 10px;
}
/* En oscuro el verde de marca se aclara y el blanco encima cae a 2,3:1. */
[data-tema="oscuro"] .ui .cuenta { color: #10161b; }

.ui .filtro-g { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.ui .filtro-g .field { margin-bottom: 0; }
@container (min-width: 700px)  { .ui .filtro-g { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@container (min-width: 1080px) { .ui .filtro-g { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
