/* ==========================================================================
   sistema.css — sistema de diseño del rediseño (IGSS Compras)

   Es la ÚNICA hoja de estilos de la app (desde 2026-09-28 todas las
   pantallas usan esta estructura; custom.css y la rama vieja de base.html se
   borraron). base.html pone siempre <body class="ui-v2"> y TODAS las reglas
   de este archivo viven bajo body.ui-v2 (salvo los @font-face y
   @keyframes, que solo declaran). Los nombres de clase viejos (.ui-panel,
   .ui-pildora-*, .ui-tabla, .tb-*) se re-pintan aquí sin tocar su HTML,
   porque varios JS arman ese mismo marcado; lo poco que las
   pantallas todavía tomaban de custom.css está en §21b. Los documentos PDF
   (A-01, Detalle, Listado) tienen su propio CSS y no usan este archivo.
   Clases nuevas: prefijo ds- (componentes) y ds-riel-/ds-barra (estructura).
   Estados forzados (para /estilo): .ds-f-hover, .ds-f-activo, .ds-f-foco
   junto a :hover, :active/seleccionado y :focus-visible; deshabilitado con
   [disabled], .disabled o aria-disabled="true".

   Índice
     0. Fuentes locales (Inter y Plus Jakarta Sans, woff2 variables)
     1. Tokens (color, radios, espacios, sombras, tipografía, medidas)
     2. Base (tipografía, enlaces, foco, cifras tabulares)
     3. Estructura: riel, submenús flotantes, nombre flotante, teléfono,
        barra superior flotante, área de contenido
     4. Encabezado de página
     5. Botones (primario deshabilitado: tinte claro del acento)
     6. Chips y píldoras de filtro: barra de filtros, chips de estado,
        píldoras desplegables, panel de filtro (6d) y panel estándar de filtro y orden (6d-bis), "Quitar filtros",
        contador y conmutador de densidad
     7. Píldoras de estado
     8. Avisos en línea
     9. Tarjetas de indicadores (KPI)
    10. Paneles y tarjetas
    11. Formularios
    12. Pasos y zona de carga
    13. Ícono de información (i)
    14. Bootstrap dentro del ámbito (menús, pestañas, paginación, modal,
        panel lateral, popover, tooltip, insignias, alertas, acordeón)
    15. Tablas: marco 16 px con encabezado fijo, densidades cómoda (52)
        y compacta (40), orden y embudos al pasar el mouse
    16. Menú de acciones "⋯"
    17. Estados vacíos
    18. Aviso flotante (UI.estado y mensajes flash)
    19. Barra flotante de selección
    20. Diálogos pequeños (UI.confirmar y macro dialogo)
    21. Compatibilidad con piezas viejas dentro de ui-v2 (21b: lo que
        todavía se tomaba de custom.css, que ya no se carga)
    22. Movimiento reducido e impresión (22b: tablas y filtros)
    23. Celdas compuestas y detalle: celda de dos líneas, número + estado,
        "+N", etiqueta, ícono de estado, select con anillo de atención,
        popover de detalle, diálogos compactos, barra de selección sobre
        la tabla, columnas fluidas (23j) y tablas parejas (23l)
    24. Componentes de pantalla (fase "todo"): filtros del servidor (GET),
        tarjeta de sección, lista de datos, formularios (grilla, grupos,
        pie fijo, lateral), carga compacta, línea de tiempo, pestañas de
        página, paginación, página de error e inicio de sesión, extras de
        indicadores, avisos con acción, gráficos y utilidades
    25. Piezas de las pantallas migradas (fase "todo", fundidas por el
        integrador): columnas y celdas de tabla, tablas con forma propia,
        filtros, indicadores, píldoras y marcas, tarjetas y plegables,
        formularios, carga de archivos, pie fijo, paneles y diálogos,
        avisos y textos, ficha y Detalle del SIAF, SIAF 182 (índice propio
        al inicio de §25)

   Fase "todo" (2026-09-26), reglas que valen para todo el archivo:
     - Texto que el navegador puede agrandar (Safari con zoom de página bajo
       sube el texto chico a 9 px de pantalla: 13 px -> 18 px al 50 %):
       interlineados SIN unidad, alturas de texto en em o como mínimos,
       topes de ancho en em/ch. Nunca height fija en px alrededor de texto.
     - Ancho del contenido: 125em (~1750 px) en tablas, centrado con la
       barra superior; "detalle" 86em y "formulario" 68em (base.html,
       ui_ancho). Tablas con columnas fluidas (23j), nunca anchos en px.

   Contraste (WCAG 2.x, MEDIDO con los valores de §1; Corrección 2 «Contraste, no color», 2026-10-01, que
     reemplaza al tono del Paso 5). Mínimos: 4.5:1 en todo texto normal; 3:1 en íconos de interfaz, bordes
     de foco, puntos y BORDES de controles y marcos (campos, chips, píldoras de filtro, botón secundario,
     tarjetas y tablas). Fondos, riel y bordes en grises NEUTROS (R = G = B). La misma medida, en vivo, en /estilo §2 «Contraste»
     (estilo.js) y la verifica tests/test_tono_color.py (también que esta
     tabla esté al día). Un solo acento, #1a6fa0: todo relleno con texto o
     marca blanca encima usa --ds-relleno-primario; --ds-acento (bordes,
     anillos, puntos, paso actual) vale lo mismo. El celeste #3aa6dd de la
     primera versión ya no se usa.
     #1d1d1d sobre #ffffff / #f3f3f3 / #e6e6e6 ........... 16.86 / 15.19 / 13.51:1  (texto (blanco / fondo / riel))
     #1d1d1d sobre #ededed / #f0f0f0 / #ececec ........... 14.40 / 14.79 / 14.27:1  (texto (barra / encabezado y chip / hover))
     #595959 sobre #ffffff / #f3f3f3 / #ededed ........... 7.00 / 6.31 / 5.98:1  (secundario (blanco / fondo / barra))
     #595959 sobre #f0f0f0 / #e6e6e6 / #dadada ........... 6.15 / 5.61 / 5.01:1  (encabezado de tabla; riel)
     #595959 sobre #ebebeb / #e8f1f6 ..................... 5.88 / 6.12:1  (sobre gris; fila elegida)
     #454545 sobre #e6e6e6 / #dadada / #ebebeb ........... 7.68 / 6.86 / 8.04:1  (íconos/etiquetas del riel; neutro)
     #1a6fa0 sobre #ffffff / #f3f3f3 / #ededed ........... 5.49 / 4.95 / 4.69:1  (enlaces, lo activo)
     #1a6fa0 sobre #e8f1f6 / #dfebf2 ..................... 4.80 / 4.52:1  (riel activo; tinte al pasar)
     blanco sobre #1a6fa0 / #17628d / #155980 ............ 5.49 / 6.63 / 7.57:1  (primario, hover, presionado; riel activo y barra de selección, Paso 4)
     #1a6fa0 sobre #e6f4fb ............................... 4.89:1  (título de lo flotante en su franja, Paso 4)
     #1d1d1d sobre #e6f4fb / #e8f1f6 / #dfebf2 ........... 15.01 / 14.73 / 13.89:1  (texto en la franja; fila seleccionada; al pasar)
     #595959 sobre #e6f4fb / #dfebf2 ..................... 6.24 / 5.77:1  (secundario en la franja; fila seleccionada al pasar)
     blanco sobre #b02a20 / #991e14 / #841a11 ............ 6.57 / 8.23 / 9.83:1  (peligro lleno)
     #1c6b35 sobre #e7f8eb / #ffffff / #f5fcf7 ........... 5.94 / 6.55 / 6.29:1  (éxito: píldora / celda / fila)
     #7a4b00 sobre #fff3e2 / #ffffff / #fffaf3 ........... 6.76 / 7.41 / 7.14:1  (aviso: píldora / celda / fila)
     #b02a20 sobre #ffe9e8 / #ffffff / #fff5f5 ........... 5.65 / 6.57 / 6.14:1  (error: píldora / celda / fila)
     #155980 sobre #e8f1f6 / #ffffff ..................... 6.62 / 7.57:1  (info: píldora / celda)
     #454545 sobre #e0e0e0 / #d6d6d6 ..................... 7.26 / 6.60:1  (neutro al pasar / presionado)
     #8a8a8a sobre #ffffff / #f3f3f3 / #f0f0f0 ........... 3.45 / 3.11 / 3.03:1  (bordes de controles y marcos (3:1))
     #6b6b6b sobre #ffffff / #e3e3e3 ..................... 5.33 / 4.15:1  (esos bordes al pasar (3:1))
     #767676 sobre #ffffff / #f3f3f3 / #e6e6e6 ........... 4.54 / 4.09 / 3.64:1  (adorno (3:1))
     #1a6fa0 sobre #ffffff / #f3f3f3 / #e6e6e6 ........... 5.49 / 4.95 / 4.40:1  (foco y bordes (3:1))
     #2a9449 sobre #ffffff ............................... 3.87:1  (punto éxito (3:1))
     #a86d00 sobre #ffffff / #e6e6e6 ..................... 4.33 / 3.47:1  (punto aviso (3:1))
     #d63a2f sobre #ffffff ............................... 4.66:1  (punto error (3:1))
       -> --ds-texto-3 SOLO para íconos de adorno, separadores "·" y
          deshabilitado (exento). Todo texto que dice algo ("No aplica",
          "—" de una celda, conteos, "(opcional)", marcadores de los campos
          (placeholder), el rótulo "Admin" del riel) va en --ds-texto-2.
     Deshabilitado (exento): blanco sobre --ds-relleno-primario-apagado y
       --ds-texto-3 sobre --ds-neutro-fondo.
     anillo de foco (--tb-anillo, §6): 2 px blanco + 2 px #1a6fa0.
     Excepción a "ningún color fuera de §1": los íconos SVG en data: URI
     (flecha de los selects en --ds-texto-2 y en acento, círculo blanco del
     interruptor, ✓ blanco y ✓ tenue de la cuadrícula 465); sus colores son
     los de esos tokens y la prueba vigila que no se aparten.
   ========================================================================== */


/* 0. Fuentes locales ====================================================== */
/* static/vendor/fuentes (fontsource, SIL OFL 1.1). Variables: un archivo
   por alfabeto cubre todos los pesos. Solo se descargan si se usan. */
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    src: url("../vendor/fuentes/inter-latin-wght-normal.woff2") format("woff2-variations"),
         url("../vendor/fuentes/inter-latin-wght-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    src: url("../vendor/fuentes/inter-latin-ext-wght-normal.woff2") format("woff2-variations"),
         url("../vendor/fuentes/inter-latin-ext-wght-normal.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: "Plus Jakarta Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 200 800;
    src: url("../vendor/fuentes/plus-jakarta-sans-latin-wght-normal.woff2") format("woff2-variations"),
         url("../vendor/fuentes/plus-jakarta-sans-latin-wght-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Plus Jakarta Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 200 800;
    src: url("../vendor/fuentes/plus-jakarta-sans-latin-ext-wght-normal.woff2") format("woff2-variations"),
         url("../vendor/fuentes/plus-jakarta-sans-latin-ext-wght-normal.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* 1. Tokens =============================================================== */
/* Corrección 2 (2026-10-01), CONTRASTE, NO COLOR (decisión del usuario; REEMPLAZA el «tono de color» del Paso 5,
   que teñía el riel de gris cálido y los bordes de cálido): los módulos no llevan fondo teñido; la jerarquía es
   de GRISES NEUTROS (R = G = B) para que cada objeto se distinga, y el único color es el acento y los estados.
   TODO color del archivo sale de aquí: fuera de §1 no hay hexadecimales ni rgba() sueltos (lo vigila
   tests/test_tono_color.py; las únicas excepciones son los íconos SVG en data: URI, que no pueden leer
   variables, listados al inicio del archivo).
   - Riel (barra lateral, sus submenús y el riel expandido): gris neutro un paso MÁS OSCURO que el contenido,
     con una línea a la derecha; activo = tinte del acento con ícono y etiqueta en el acento.
   - Contenido: gris claro; tarjetas, tablas, diálogos, paneles y campos en BLANCO con borde visible
     (--ds-borde-marco, 3:1 contra el fondo) y sombra mínima.
   - Encabezado de tabla: gris suave con texto gris oscuro; separadores de fila visibles; hover notorio.
   - Controles (campos, chips, píldoras de filtro, botón secundario): borde --ds-borde-fuerte (3:1 contra su
     fondo, criterio WCAG 1.4.11); chips y filtros inactivos con fondo gris claro (--ds-control-fondo).
   - UN solo acento, #1a6fa0, y sus tintes (mezclas con blanco, el % al lado): botón primario, selección,
     chips activos, enlaces y foco.
   - Estados (verde, ámbar, rojo, azul) solo en píldoras, avisos y sus marcas (punto, borde, fila teñida):
     fondo pastel y texto oscuro del mismo tono. Los colores de las series de los gráficos (ui.js) y de los
     productos de la cuadrícula 465 (sabana_465.js) no son acentos y no están aquí. */
body.ui-v2 {
    /* Noche 5 · 1 y 6: blanco de botones/insignias y la paleta del panel del inicio de sesión («Barras que responden») */
    --ds-blanco: #ffffff;
    --ds-login-fondo: #0f3550;
    --ds-login-barra-viva: #7cc4ea;   /* foco del ojo de la contraseña */
    --ds-login-cumbre-1: #7cc4ea;     /* «Cumbre» (2026-10-23): barra baja */
    --ds-login-cumbre-2: #5aa9dc;     /* barra media */
    --ds-login-cumbre-3: #c7466f;     /* barra alta, corinto */
    --ds-login-cumbre-brillo-suave: rgba(199, 70, 111, 0.35);
    --ds-login-cumbre-brillo-fuerte: rgba(199, 70, 111, 0.75);
    /* Acento único #1a6fa0 y sus tintes */
    --ds-acento: #1a6fa0;                 /* bordes, anillos, puntos, barras, paso actual (antes celeste #3aa6dd) */
    --ds-acento-oscuro: #1a6fa0;          /* texto en acento: enlaces, lo activo */
    --ds-acento-claro: #e8f1f6;           /* 10 %: fondo de lo activo (riel, chip-casilla, fila elegida, info) */
    --ds-acento-claro-2: #dfebf2;         /* 14 %: ese fondo al pasar o presionado */
    --ds-acento-seleccion: #cddfea;       /* 22 %: texto seleccionado, rango de la 465 */
    --ds-acento-borde: #afcdde;           /* 35 %: borde de lo teñido de acento */
    --ds-acento-tenue: #f4f8fa;           /* 5 %: columna o fila con foco de la 465, fila info */
    --ds-acento-velo: rgba(26, 111, 160, 0.12);   /* ✕ de una píldora de filtro activa, al pasar */
    /* Relleno con texto blanco encima (botón primario, chip activo, casilla
       marcada, paso hecho): #1a6fa0, blanco 5.49:1. */
    --ds-relleno-primario: #1a6fa0;
    --ds-relleno-primario-hover: #17628d;     /* blanco 6.63:1 */
    --ds-relleno-primario-activo: #155980;    /* blanco 7.57:1 */
    --ds-relleno-primario-apagado: #a3c5d9;   /* 40 %: deshabilitado */
    --ds-texto-sobre-relleno: #fff;           /* texto o marca sobre un relleno lleno (primario, peligro, nombre flotante) */
    --ds-texto-sobre-relleno-2: rgba(255, 255, 255, 0.9);   /* conteo dentro de un chip lleno (4.9:1) */
    --ds-conteo-sobre-relleno: rgba(0, 0, 0, 0.2);          /* fondo del conteo de un botón primario (blanco 7.57:1) */
    --ds-anillo: rgba(26, 111, 160, 0.25);     /* anillo suave de foco de campos (con borde acento) */
    --ds-anillo-fuerte: rgba(26, 111, 160, 0.45);   /* anillo de la celda que se edita */
    /* Noche 2 · Paso 4: el color va SOLO en lo ACTIVO, lo SELECCIONADO y lo FLOTANTE (los módulos y fondos siguen
       en grises neutros). */
    --ds-riel-activo: var(--ds-relleno-primario);             /* ítem activo del riel: relleno #1a6fa0, blanco 5.49:1 */
    --ds-riel-activo-hover: var(--ds-relleno-primario-hover); /* ese ítem al pasar: blanco 6.63:1 */
    --ds-flotante-franja: #e6f4fb;          /* franja o encabezado de lo flotante (submenús, filtros, diálogos, paneles) */
    --ds-flotante-titulo: var(--ds-acento-oscuro);            /* su título: #1a6fa0 sobre la franja, 4.89:1 */
    --ds-flotante-borde: var(--ds-acento-borde);              /* borde azul suave de lo flotante (no es un control) */
    --ds-fila-seleccionada: var(--ds-acento-claro);           /* fila con la casilla marcada (el hover sigue gris) */
    --ds-fila-seleccionada-hover: var(--ds-acento-claro-2);   /* esa fila al pasar */
    --ds-seleccion-fondo: var(--ds-relleno-primario);         /* barra flotante de selección: blanco 5.49:1 */
    --ds-seleccion-hover: var(--ds-relleno-primario-hover);   /* un botón de esa barra al pasar: blanco 6.63:1 */
    --ds-seleccion-separador: rgba(255, 255, 255, 0.45);      /* línea entre el conteo y las acciones */
    --ds-seleccion-apagado: rgba(255, 255, 255, 0.55);        /* botón deshabilitado de la barra (exento) */

    /* Superficies: grises NEUTROS (R = G = B), de más claro a más oscuro */
    --ds-superficie: #fff;                /* tarjetas, tablas, diálogos, paneles, campos */
    --ds-fondo: #f3f3f3;                  /* área de contenido: gris claro */
    --ds-encabezado-tabla: #f0f0f0;       /* encabezado de tabla: gris suave dentro del marco blanco */
    --ds-control-fondo: #f0f0f0;          /* chips y píldoras de filtro INACTIVOS (con borde de control) */
    --ds-barra-fondo: #ededed;            /* barra superior: apenas más oscura que el fondo */
    --ds-hover: #ececec;                  /* fila/elemento al pasar, sobre blanco (notorio) */
    --ds-control-hover: #e3e3e3;          /* chip o píldora de filtro inactivos, al pasar */
    --ds-riel-fondo: #e6e6e6;             /* barra lateral: un paso más oscura que el contenido */
    --ds-riel-hover: #dadada;             /* ítem del riel al pasar */
    --ds-riel-borde: #cccccc;             /* línea entre el riel y el contenido, separador "Admin" */
    --ds-hover-fondo: rgba(0, 0, 0, 0.05);   /* al pasar, sobre el fondo gris */
    --ds-velo: #1d1d1d;                   /* fondo detrás de un diálogo o panel lateral (con su opacidad) */
    /* Bordes y separadores: grises neutros. Los de CONTROLES y MARCOS, 3:1 contra su fondo (WCAG 1.4.11) */
    --ds-borde-marco: #8a8a8a;            /* marco de tarjetas, tablas, paneles e indicadores: 3.11:1 sobre el fondo */
    --ds-borde-fuerte: #8a8a8a;           /* campos, chips, píldoras de filtro, botón secundario: 3.45:1 sobre blanco */
    --ds-borde-hover: #6b6b6b;            /* esos bordes al pasar */
    --ds-borde: #d4d4d4;                  /* separadores internos: encabezado de tabla, menús, secciones */
    --ds-borde-suave: #e2e2e2;            /* líneas entre filas (visibles) */
    /* Texto (gris neutro) */
    --ds-texto: #1d1d1d;
    --ds-texto-2: #595959;                /* secundario: 5.6:1 o más en todas las superficies (un paso más oscuro) */
    --ds-texto-3: #767676;                /* SOLO adorno, deshabilitado, separadores: 3:1 o más */
    --ds-neutro-hover: #e0e0e0;           /* relleno gris al pasar (píldora gris en una fila, "⋯") */
    --ds-neutro-activo: #d6d6d6;          /* relleno gris presionado ("+N") */

    /* Estados: fondo pastel / texto oscuro del mismo tono (tonos del sistema
       de macOS: verde #34c759, naranja #ff9f0a, rojo #ff3b30; azul = acento) */
    --ds-exito-fondo: #e7f8eb;   --ds-exito: #1c6b35;
    --ds-aviso-fondo: #fff3e2;   --ds-aviso: #7a4b00;
    --ds-error-fondo: #ffe9e8;   --ds-error: #b02a20;
    --ds-info-fondo: #e8f1f6;    --ds-info: #155980;
    --ds-neutro-fondo: #ebebeb;  --ds-neutro: #454545;
    /* bordes, fondos de hover, filas teñidas y puntos de cada estado */
    --ds-exito-borde: #c2eecd;   --ds-exito-borde-2: #aee9bd;   --ds-exito-fondo-2: #d6f4de;   --ds-exito-tenue: #f5fcf7;   --ds-exito-punto: #2a9449;
    --ds-aviso-borde: #ffe2b6;   --ds-aviso-borde-2: #ffd99d;   --ds-aviso-fondo-2: #ffeac9;   --ds-aviso-tenue: #fffaf3;   --ds-aviso-punto: #a86d00;
    --ds-error-borde: #ffc4c1;   --ds-error-borde-2: #ffb1ac;   --ds-error-fondo-2: #ffdcda;   --ds-error-tenue: #fff5f5;   --ds-error-punto: #d63a2f;
    --ds-info-borde: var(--ds-acento-borde);                                                  --ds-info-tenue: var(--ds-acento-tenue);
    --ds-error-punto-oscuro: #9e1d17;
    --ds-aviso-anillo: rgba(168, 109, 0, 0.18);
    --ds-error-anillo: rgba(176, 42, 32, 0.16);
    /* botón de peligro lleno (blanco 6.57 / 8.23 / 9.83:1) */
    --ds-peligro: var(--ds-error);
    --ds-peligro-hover: #991e14;
    --ds-peligro-activo: #841a11;

    /* Hoja de papel (acta en vivo y vista previa del Word): imita el
       documento impreso, por eso blanco, negro y el gris del encabezado de
       sus tablas no siguen el tono de la app */
    --ds-hoja: #fff;
    --ds-hoja-tinta: #000;
    --ds-hoja-encabezado: #d9d9d9;
    --ds-hoja-marca: rgba(176, 42, 32, 0.13);   /* marca de agua BORRADOR */

    /* Forma */
    --ds-radio-pildora: 999px;   /* botones, chips, píldoras, buscador */
    --ds-radio-campo: 12px;      /* campos, menús desplegables, avisos */
    --ds-radio-tarjeta: 16px;    /* tarjetas, tablas, paneles */
    --ds-radio-dialogo: 20px;    /* diálogos, panel lateral, barra superior */
    --ds-radio-item: 8px;        /* ítems dentro de menús, nombre flotante */

    /* Espacio: 4/8/12/16/24/32 */
    --ds-e1: 4px;  --ds-e2: 8px;  --ds-e3: 12px;
    --ds-e4: 16px; --ds-e5: 24px; --ds-e6: 32px;
    --ds-margen-pagina: 32px;

    /* Sombras mínimas y neutras (negro con opacidad) */
    --ds-sombra-tarjeta: 0 1px 2px rgba(0, 0, 0, 0.06);
    --ds-sombra-flotante: 0 4px 20px rgba(0, 0, 0, 0.06);
    --ds-sombra-pie: 0 -6px 14px -8px rgba(0, 0, 0, 0.18), 0 -1px 2px -1px rgba(0, 0, 0, 0.08);   /* pies fijos: nada por debajo del borde inferior */
    --ds-sombra-menu: 0 8px 28px rgba(0, 0, 0, 0.10), 0 1px 3px rgba(0, 0, 0, 0.06);
    --ds-sombra-menu-fuerte: 0 8px 28px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.06);   /* menú "+N" */
    --ds-sombra-panel: 0 12px 32px rgba(0, 0, 0, 0.10), 0 2px 6px rgba(0, 0, 0, 0.04);              /* panel de filtro */
    --ds-sombra-dialogo: 0 24px 48px rgba(0, 0, 0, 0.16);                                        /* diálogo, panel lateral */
    --ds-sombra-dialogo-fuerte: 0 24px 48px rgba(0, 0, 0, 0.18);                                 /* diálogo sobre diálogo */
    --ds-sombra-flotante-fuerte: 0 18px 44px rgba(0, 0, 0, 0.20), 0 4px 12px rgba(0, 0, 0, 0.10);  /* lo flotante (Paso 4) */
    --ds-sombra-control: 0 1px 2px rgba(0, 0, 0, 0.08);           /* opción elegida de la densidad */
    --ds-sombra-segmento: 0 1px 2px rgba(0, 0, 0, 0.08);       /* opción elegida de un segmento */
    --ds-sombra-hoja: 0 1px 3px rgba(0, 0, 0, 0.12);           /* hoja de la vista previa del Word */

    --ds-transicion: 150ms ease;

    /* Tipografía */
    --ds-fuente: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --ds-tam-titulo: 26px;       /* título de página, 600 */
    --ds-tam-seccion: 16px;      /* título de sección o panel, 600 */
    --ds-tam-cuerpo: 14px;       /* cuerpo, subtítulo, contador */
    --ds-tam-tabla: 13px;        /* celdas */
    --ds-tam-etiqueta: 12px;     /* etiquetas y píldoras, 500 */

    /* Medidas */
    --ds-riel: max(144px, 10.28em);              /* delgado: ícono 24 px + etiqueta de 12 px; em: crece si Safari agranda la letra (2026-09-28) */
    --ds-riel-expandido: max(240px, 17.2em);   /* 240 px; crece si el navegador agranda el texto (nombres enteros) */
    --ds-ancho-riel: var(--ds-riel);
    --ds-alto-control: 40px;
    --ds-alto-chip: 36px;
    --ds-alto-buscador: 44px;
    --ds-alto-barra: 56px;       /* buscador 44 + 6 arriba y abajo (fase "todo": menos cromo vertical) */
    /* Ancho máximo del contenido (fase "todo"). En em de la letra del cuerpo
       (14 px): 125em = 1750 px en tablas; formularios 68em = 952; detalle
       86em = 1204. En em y no en px: si el navegador agranda el texto (zoom
       de página bajo en Safari), la página aprovecha el ancho con él. */
    --ds-ancho-datos: 125em;
    --ds-ancho-detalle: 86em;
    --ds-ancho-formulario: 68em;
    --ds-fila-comoda: 52px;
    --ds-fila-compacta: 40px;

    /* Alias de compatibilidad (nombres de la primera versión; los usan
       piezas viejas y los fragmentos que aún no se actualizan) */
    --ds-acento-fuerte: var(--ds-acento-oscuro);
    --ds-acento-fuerte-hover: var(--ds-relleno-primario-hover);
    --ds-acento-fuerte-activo: var(--ds-relleno-primario-activo);
    --ds-acento-texto: var(--ds-acento-oscuro);
    --ds-acento-suave: var(--ds-acento-claro);
    --ds-acento-suave-2: var(--ds-acento-claro-2);
    --ds-acento-tinta: var(--ds-acento-oscuro);
    --ds-acento-anillo: var(--ds-anillo);
    --ds-superficie-2: var(--ds-neutro-fondo);
    --ds-superficie-hover: var(--ds-hover);
    --ds-borde-campo: var(--ds-borde-fuerte);
    --ds-tinta-oscura: var(--ds-texto);
    --ds-verde: var(--ds-exito);   --ds-verde-suave: var(--ds-exito-fondo);  --ds-verde-borde: var(--ds-exito-borde);  --ds-verde-punto: var(--ds-exito-punto);
    --ds-ambar: var(--ds-aviso);   --ds-ambar-suave: var(--ds-aviso-fondo);  --ds-ambar-borde: var(--ds-aviso-borde);  --ds-ambar-punto: var(--ds-aviso-punto);
    --ds-rojo: var(--ds-error);    --ds-rojo-suave: var(--ds-error-fondo);   --ds-rojo-borde: var(--ds-error-borde); --ds-rojo-punto: var(--ds-error-punto);
    --ds-rojo-hover: var(--ds-peligro-hover);
    --ds-gris: var(--ds-neutro);   --ds-gris-suave: var(--ds-neutro-fondo);  --ds-gris-borde: var(--ds-borde-fuerte); --ds-gris-punto: var(--ds-texto-3);
    --ds-radio-1: var(--ds-radio-item);
    --ds-radio-2: var(--ds-radio-campo);
    --ds-radio-3: var(--ds-radio-tarjeta);
    --ds-sombra-1: var(--ds-sombra-tarjeta);
    --ds-sombra-2: var(--ds-sombra-menu);
    --ds-texto-xs: var(--ds-tam-etiqueta);
    --ds-texto-sm: var(--ds-tam-tabla);
    --ds-texto-base: var(--ds-tam-cuerpo);
    --ds-texto-md: var(--ds-tam-seccion);
    --ds-texto-lg: var(--ds-tam-titulo);
    --ds-texto-xl: var(--ds-tam-titulo);
    --ds-esp-1: var(--ds-e1); --ds-esp-2: var(--ds-e2); --ds-esp-3: var(--ds-e3);
    --ds-esp-4: var(--ds-e4); --ds-esp-5: var(--ds-e5); --ds-esp-6: var(--ds-e6);
    --ds-esp-7: 48px;
    --ds-riel-delgado: var(--ds-riel);
    --ds-riel-ancho: var(--ds-riel-expandido);

    /* Bootstrap dentro del ámbito */
    --bs-body-font-family: var(--ds-fuente);
    --bs-body-font-size: var(--ds-tam-cuerpo);
    --bs-body-line-height: 1.5;
    --bs-body-color: var(--ds-texto);
    --bs-body-color-rgb: 29, 29, 29;
    --bs-body-bg: var(--ds-fondo);
    --bs-emphasis-color: var(--ds-texto);
    --bs-secondary-color: var(--ds-texto-2);
    --bs-secondary-color-rgb: 89, 89, 89;
    --bs-tertiary-color: var(--ds-texto-3);
    --bs-secondary-bg: var(--ds-neutro-fondo);
    --bs-tertiary-bg: var(--ds-hover);
    --bs-heading-color: var(--ds-texto);
    --bs-primary: var(--ds-acento);
    --bs-primary-rgb: 26, 111, 160;
    --bs-primary-text-emphasis: var(--ds-acento-oscuro);
    --bs-primary-bg-subtle: var(--ds-acento-claro);
    --bs-primary-border-subtle: var(--ds-acento-borde);
    --bs-link-color: var(--ds-acento-oscuro);
    --bs-link-color-rgb: 26, 111, 160;
    --bs-link-hover-color: var(--ds-relleno-primario-activo);
    --bs-link-hover-color-rgb: 21, 89, 128;
    --bs-border-color: var(--ds-borde);
    --bs-border-color-translucent: rgba(0, 0, 0, 0.08);
    --bs-border-radius: var(--ds-radio-campo);
    --bs-border-radius-sm: var(--ds-radio-item);
    --bs-border-radius-lg: var(--ds-radio-tarjeta);
    --bs-border-radius-xl: var(--ds-radio-dialogo);
    --bs-border-radius-xxl: var(--ds-radio-dialogo);
    --bs-border-radius-pill: var(--ds-radio-pildora);
    --bs-focus-ring-color: var(--ds-anillo);
    --bs-box-shadow: var(--ds-sombra-menu);
    --bs-box-shadow-sm: var(--ds-sombra-tarjeta);
    --bs-success-rgb: 28, 107, 53;
    --bs-danger-rgb: 176, 42, 32;
    --bs-warning-rgb: 122, 75, 0;
    --bs-info-rgb: 21, 89, 128;
}
body.ui-v2.ds-riel-expandido { --ds-ancho-riel: var(--ds-riel-expandido); }
/* Compatibilidad: primario oscuro ya es el valor por defecto (sin efecto) */
body.ui-v2.ds-primario-oscuro,
body.ui-v2 .ds-primario-oscuro { --ds-relleno-primario: var(--ds-acento-oscuro); }
/* Vista previa de la otra fuente (/estilo) */
body.ui-v2.ds-fuente-jakarta,
body.ui-v2 .ds-fuente-jakarta {
    --ds-fuente: "Plus Jakarta Sans", "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
    --bs-body-font-family: var(--ds-fuente);
    font-family: var(--ds-fuente);
}
/* y al revés: la muestra de Inter sigue en Inter aunque la página use Jakarta */
body.ui-v2 .ds-fuente-inter {
    --ds-fuente: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --bs-body-font-family: var(--ds-fuente);
    font-family: var(--ds-fuente);
}
@media (max-width: 767.98px) {
    body.ui-v2,
    body.ui-v2.ds-riel-expandido {
        --ds-ancho-riel: 0px;
        --ds-margen-pagina: 16px;
    }
}


/* 2. Base ================================================================= */
body.ui-v2 {
    background-color: var(--ds-fondo);
    color: var(--ds-texto);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}
body.ui-v2 h1, body.ui-v2 h2, body.ui-v2 h3,
body.ui-v2 h4, body.ui-v2 h5, body.ui-v2 h6,
body.ui-v2 .h1, body.ui-v2 .h2, body.ui-v2 .h3,
body.ui-v2 .h4, body.ui-v2 .h5, body.ui-v2 .h6 {
    font-family: var(--ds-fuente);
    font-weight: 600;
    color: var(--ds-texto);
    letter-spacing: -0.011em;
    line-height: 1.3;
    text-transform: none;
}
body.ui-v2 h1, body.ui-v2 .h1 { font-size: var(--ds-tam-titulo); letter-spacing: -0.02em; }
body.ui-v2 h2, body.ui-v2 .h2 { font-size: 18px; }
body.ui-v2 h3, body.ui-v2 .h3 { font-size: var(--ds-tam-seccion); }
body.ui-v2 h4, body.ui-v2 .h4,
body.ui-v2 h5, body.ui-v2 .h5,
body.ui-v2 h6, body.ui-v2 .h6 { font-size: var(--ds-tam-cuerpo); }
body.ui-v2 b, body.ui-v2 strong, body.ui-v2 .fw-bold { font-weight: 600 !important; }
body.ui-v2 small, body.ui-v2 .small { font-size: var(--ds-tam-tabla); }
body.ui-v2 a { color: var(--ds-acento-oscuro); text-underline-offset: 2px; transition: color var(--ds-transicion); }
body.ui-v2 a:hover { color: var(--ds-acento-fuerte-activo); }
body.ui-v2 .text-muted,
body.ui-v2 .text-secondary,
body.ui-v2 .ds-texto-suave { color: var(--ds-texto-2) !important; }
body.ui-v2 .ds-texto-apagado { color: var(--ds-texto-2) !important; }
body.ui-v2 .text-uppercase { text-transform: none !important; }
/* Cifras tabulares en todo lo que se compara en columna */
body.ui-v2 table,
body.ui-v2 input,
body.ui-v2 .ds-num,
body.ui-v2 .ui-col-numerica,
body.ui-v2 .ds-contador,
body.ui-v2 .ds-kpi-valor,
body.ui-v2 .ds-pildora,
body.ui-v2 .badge { font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-num { white-space: nowrap; text-align: right; }

/* Foco: visible solo con teclado */
body.ui-v2 :focus-visible {
    outline: 2px solid var(--ds-acento-oscuro);
    outline-offset: 2px;
}
body.ui-v2 :focus:not(:focus-visible) { outline: none; }
body.ui-v2 ::selection { background: var(--ds-acento-seleccion); color: var(--ds-texto); }

/* Solo visible en un estado del riel (textos del botón que lo alterna) */
body.ui-v2 .ds-solo-expandido { display: none !important; }
body.ui-v2.ds-riel-expandido .ds-solo-expandido { display: inline-block !important; }
body.ui-v2.ds-riel-expandido .ds-solo-contraido { display: none !important; }

/* Saltar al contenido (visible solo con foco) */
body.ui-v2 .ds-saltar {
    position: fixed;
    top: 8px;
    left: 8px;
    z-index: 1090;
    padding: 8px 16px;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-superficie);
    color: var(--ds-acento-oscuro);
    box-shadow: var(--ds-sombra-menu);
    font-weight: 500;
    text-decoration: none;
    transform: translateY(calc(-100% - 48px));   /* oculto del todo: ni su sombra (28 px) asoma arriba */
    transition: transform var(--ds-transicion);
}
body.ui-v2 .ds-saltar:focus { transform: none; }


/* 3. Estructura =========================================================== */
body.ui-v2 .ds-app {
    display: flex;
    min-height: 100vh;
}
body.ui-v2 .ds-principal {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

/* 3a. Riel: 144 px (crece en em con la letra) con ícono de 24 px y
       etiqueta completa de 12 px debajo (áreas de clic de 120×64, radio 12,
       separación 8) sobre el fondo gris; expandido 240 px con
       nombres. Íconos en #4b5563; activo = fondo acento claro con ícono y
       etiqueta en acento oscuro. ----------------------------------------- */
@media (min-width: 768px) {
    body.ui-v2 .ds-riel {
        position: sticky;
        top: 0;
        height: 100vh;
        flex: 0 0 var(--ds-ancho-riel);
        width: var(--ds-ancho-riel);
        z-index: 1030;
        transition: width var(--ds-transicion), flex-basis var(--ds-transicion);
    }
}
body.ui-v2 .ds-riel-interior {
    height: 100%;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 0 12px 16px;
    /* fondo del riel aquí y no en .ds-riel: Bootstrap deja transparente
       .offcanvas-md en escritorio (!important). La línea de la derecha es
       una sombra interior: no ocupa ancho. */
    background: var(--ds-riel-fondo);
    box-shadow: inset -1px 0 0 var(--ds-riel-borde);
    overflow-x: hidden;
    overflow-y: auto;
    scrollbar-width: none;
}
body.ui-v2 .ds-riel-interior::-webkit-scrollbar { display: none; }
/* La cabeza mide lo mismo que la barra superior: el botón de expandir
   queda a la altura de la barra. */
body.ui-v2 .ds-riel-cabeza {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: calc(var(--ds-e3) + var(--ds-alto-barra) + 2px);
    padding-top: var(--ds-e3);
    margin-bottom: var(--ds-e3);
}
body.ui-v2 .ds-riel-lista {
    flex: none;
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
body.ui-v2 .ds-riel-li { position: relative; }
body.ui-v2 .ds-riel-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    height: var(--ds-alto-control);
    padding: 0 12px 0 10px;
    border: 0;
    border-radius: var(--ds-radio-pildora);
    background: transparent;
    color: var(--ds-neutro);
    font: inherit;
    font-size: var(--ds-tam-tabla);
    font-weight: 500;
    text-align: left;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .ds-riel-icono {
    flex: none;
    width: 20px;
    font-size: 20px;
    line-height: 1;
    text-align: center;
}
body.ui-v2 .ds-riel-item:hover,
body.ui-v2 .ds-riel-item.ds-f-hover,
body.ui-v2 .ds-riel-item[data-ds-flyout][aria-expanded="true"] {
    background: var(--ds-riel-hover);
    color: var(--ds-texto);
}
/* activo (Noche 2 · Paso 4): relleno del acento con ícono y etiqueta BLANCOS, en el riel delgado, el expandido y
   el del teléfono (también al pasar o con su submenú abierto) */
body.ui-v2 .ds-riel-item.activo,
body.ui-v2 .ds-riel-item.ds-f-activo {
    background: var(--ds-riel-activo);
    color: var(--ds-texto-sobre-relleno);
}
body.ui-v2 .ds-riel-item.activo:hover,
body.ui-v2 .ds-riel-item.activo[aria-expanded="true"] { background: var(--ds-riel-activo-hover); color: var(--ds-texto-sobre-relleno); }
body.ui-v2 .ds-riel-item.activo .ds-riel-flecha { color: var(--ds-texto-sobre-relleno); }
body.ui-v2 .ds-riel-item.activo .ds-riel-punto { box-shadow: 0 0 0 2px var(--ds-riel-activo); }
/* riel EXPANDIDO y del TELÉFONO con el grupo abierto en línea: el relleno va en el subítem de la página (un solo
   relleno a la vista); el grupo que lo contiene queda en el tinte del acento */
body.ui-v2.ds-riel-expandido .ds-riel-item.activo[data-ds-flyout][aria-expanded="true"] {
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
}
body.ui-v2.ds-riel-expandido .ds-riel-item.activo[data-ds-flyout][aria-expanded="true"] .ds-riel-flecha { color: var(--ds-acento-oscuro); }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-riel-item.activo[data-ds-flyout][aria-expanded="true"] { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
    body.ui-v2 .ds-riel-item.activo[data-ds-flyout][aria-expanded="true"] .ds-riel-flecha { color: var(--ds-acento-oscuro); }
}
body.ui-v2 .ds-riel-item.ds-f-foco { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 2px; }
body.ui-v2 .ds-riel-item.deshabilitado { color: var(--ds-texto-3); cursor: default; }
body.ui-v2 .ds-riel-item.deshabilitado:hover { background: transparent; }
body.ui-v2 .ds-riel-texto {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Etiqueta corta y rótulo "Admin": solo en el riel delgado */
body.ui-v2 .ds-riel-corto,
body.ui-v2 .ds-riel-seccion-corto { display: none; }
body.ui-v2 .ds-riel-flecha {
    flex: none;
    margin-left: -2px;
    font-size: 14px;
    color: var(--ds-texto-3);
    transition: transform var(--ds-transicion);
}
/* Punto de "Próximamente" / "En construcción" */
body.ui-v2 .ds-riel-punto {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    box-shadow: 0 0 0 2px var(--ds-riel-fondo);
}
body.ui-v2 .ds-riel-punto-aviso,
body.ui-v2 .ds-riel-punto-ambar { background: var(--ds-aviso-punto); }
body.ui-v2 .ds-riel-punto-neutro,
body.ui-v2 .ds-riel-punto-gris { background: var(--ds-texto-3); }
body.ui-v2 .ds-riel-seccion {
    flex: none;                /* el riel es una columna flex más alta que la ventana: sin esto se encoge */
    margin: var(--ds-e4) 0 var(--ds-e1);
    padding: 0 12px;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Riel delgado (escritorio, estado por defecto): ícono + etiqueta corta.
   Los nombres completos quedan para lectores de pantalla (ocultos a la
   vista, no con display) y en el nombre flotante. Las mismas reglas valen
   para la muestra de /estilo (.ds-riel-muestra sin -expandido). Alto con
   min-height (no height): si Safari agranda la letra, el ítem crece. */
@media (min-width: 768px) {
    body.ui-v2:not(.ds-riel-expandido) .ds-riel-interior { padding: 0 12px 16px; }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel .ds-riel-texto,
    body.ui-v2 .ds-riel-muestra:not(.ds-riel-muestra-expandido) .ds-riel-texto {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
    }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel .ds-riel-flecha,
    body.ui-v2 .ds-riel-muestra:not(.ds-riel-muestra-expandido) .ds-riel-flecha { display: none; }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel .ds-riel-lista,
    body.ui-v2 .ds-riel-muestra:not(.ds-riel-muestra-expandido) .ds-riel-lista { gap: 8px; }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel .ds-riel-item,
    body.ui-v2 .ds-riel-muestra:not(.ds-riel-muestra-expandido) .ds-riel-item {
        flex-direction: column;
        justify-content: center;
        gap: 4px;
        width: 100%;
        height: auto;
        min-height: 64px;
        margin: 0 auto;
        padding: 8px 2px;
        border-radius: 12px;
        text-align: center;
    }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel .ds-riel-alternar { min-height: 40px; }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel .ds-riel-icono,
    body.ui-v2 .ds-riel-muestra:not(.ds-riel-muestra-expandido) .ds-riel-icono { width: 24px; font-size: 24px; }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel .ds-riel-corto,
    body.ui-v2 .ds-riel-muestra:not(.ds-riel-muestra-expandido) .ds-riel-corto {
        display: block;
        font-size: 12px;
        font-weight: 500;
        line-height: 1.25;
        white-space: nowrap;           /* una línea y nunca "…": caben enteras en el riel (ancho en em) */
    }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel-cabeza { justify-content: center; }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel .ds-riel-punto,
    body.ui-v2 .ds-riel-muestra:not(.ds-riel-muestra-expandido) .ds-riel-punto {
        position: absolute;
        top: 8px;
        right: calc(50% - 22px);
    }
    /* "Administración": separador y rótulo corto "Admin" */
    body.ui-v2:not(.ds-riel-expandido) .ds-riel .ds-riel-seccion,
    body.ui-v2 .ds-riel-muestra:not(.ds-riel-muestra-expandido) .ds-riel-seccion {
        margin: var(--ds-e4) 8px var(--ds-e2);
        padding: var(--ds-e3) 0 var(--ds-e1);
        border-top: 1px solid var(--ds-riel-borde);
        color: var(--ds-texto-2);          /* "Admin" es texto que dice algo: 5:1 sobre el riel */
        font-size: 11px;
        font-weight: 600;
        text-align: center;
    }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel .ds-riel-seccion-largo,
    body.ui-v2 .ds-riel-muestra:not(.ds-riel-muestra-expandido) .ds-riel-seccion-largo { display: none; }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel .ds-riel-seccion-corto,
    body.ui-v2 .ds-riel-muestra:not(.ds-riel-muestra-expandido) .ds-riel-seccion-corto { display: inline; }
}

/* Muestras del riel en /estilo (fuera del riel): la delgada (72 px, las
   reglas de arriba) y la expandida siempre con nombres (240 - 24 px), sin
   importar cómo esté el riel real. */
body.ui-v2 .ds-riel-muestra {
    width: 120px;
    /* el fondo del riel real, pintado 8 px alrededor con una sombra: no cambia la medida de la muestra */
    border-radius: 4px;
    background: var(--ds-riel-fondo);
    box-shadow: 0 0 0 8px var(--ds-riel-fondo);
}
body.ui-v2 .ds-riel-muestra.ds-riel-muestra-expandido { width: calc(var(--ds-riel-expandido, 240px) - 24px); }
body.ui-v2 .ds-riel-muestra.ds-riel-muestra-expandido .ds-riel-item { justify-content: flex-start; padding: 0 12px 0 10px; }
body.ui-v2 .ds-riel-muestra.ds-riel-muestra-expandido .ds-riel-texto {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    clip: auto;
    clip-path: none;
}
body.ui-v2 .ds-riel-muestra.ds-riel-muestra-expandido .ds-riel-flecha { display: inline-block; }
body.ui-v2 .ds-riel-muestra.ds-riel-muestra-expandido .ds-riel-punto { position: static; }
body.ui-v2 .ds-riel-muestra.ds-riel-muestra-expandido .ds-riel-seccion {
    height: auto;
    margin: var(--ds-e4) 0 var(--ds-e1);
    padding: 0 12px;
    background: none;
    color: var(--ds-texto-2);
}

/* /estilo §2 (Corrección 2, contraste no color): la JERARQUÍA de grises en miniatura — riel un paso más oscuro,
   barra superior y encabezado de tabla grises, contenido gris claro y la tarjeta blanca con su marco. Solo la usa
   la página de referencia. */
body.ui-v2 .ds-muestra-ambiente {
    display: grid;
    grid-template-columns: 9em 1fr;
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-tarjeta);
    background: var(--ds-fondo);
    overflow: hidden;
    font-size: var(--ds-tam-etiqueta);
}
body.ui-v2 .ds-muestra-ambiente-riel {
    display: flex;
    flex-direction: column;
    gap: var(--ds-e1);
    padding: var(--ds-e3) var(--ds-e2);
    background: var(--ds-riel-fondo);
    box-shadow: inset -1px 0 0 var(--ds-riel-borde);
}
body.ui-v2 .ds-muestra-ambiente-item {
    display: flex;
    align-items: center;
    gap: var(--ds-e2);
    padding: 6px var(--ds-e2);
    border-radius: var(--ds-radio-item);
    color: var(--ds-neutro);
    font-weight: 500;
}
body.ui-v2 .ds-muestra-ambiente-item.activo { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-muestra-ambiente-rotulo { margin-top: auto; padding: 0 var(--ds-e2); color: var(--ds-texto-2); font-family: var(--bs-font-monospace); }
body.ui-v2 .ds-muestra-ambiente-contenido { display: flex; flex-direction: column; gap: var(--ds-e3); padding: var(--ds-e3) var(--ds-e4); }
body.ui-v2 .ds-muestra-ambiente-barra,
body.ui-v2 .ds-muestra-ambiente-encabezado,
body.ui-v2 .ds-muestra-ambiente-fila {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-e3);
    padding: 6px var(--ds-e3);
    color: var(--ds-texto-2);
}
body.ui-v2 .ds-muestra-ambiente-barra { border: 1px solid var(--ds-borde-suave); border-radius: var(--ds-radio-campo); background: var(--ds-barra-fondo); }
body.ui-v2 .ds-muestra-ambiente-buscar {
    flex: 1 1 auto;
    padding: 2px var(--ds-e3);
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-superficie);
}
body.ui-v2 .ds-muestra-ambiente-tarjeta { border: 1px solid var(--ds-borde-marco); border-radius: var(--ds-radio-campo); background: var(--ds-superficie); overflow: hidden; }
body.ui-v2 .ds-muestra-ambiente-encabezado { background: var(--ds-encabezado-tabla); box-shadow: inset 0 -1px 0 var(--ds-borde); }
body.ui-v2 .ds-muestra-ambiente-fila { color: var(--ds-texto); }
body.ui-v2 .ds-muestra-ambiente-fila + .ds-muestra-ambiente-fila { border-top: 1px solid var(--ds-borde-suave); }
body.ui-v2 .ds-muestra-ambiente-fila > .font-monospace { color: var(--ds-texto-2); }

/* Submenús: panel flotante en el riel delgado, en línea si expandido */
body.ui-v2 .ds-riel-sub { display: none; }
body.ui-v2 .ds-riel-sub.abierto { display: block; }
body.ui-v2 .ds-riel-sub-titulo {
    padding: 6px 12px 8px;
    color: var(--ds-texto);
    font-size: 14px;
    font-weight: 600;
}
body.ui-v2 .ds-riel-sub-lista {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
body.ui-v2 .ds-riel-subitem {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 40px;
    padding: 0 12px;
    border-radius: 10px;
    color: var(--ds-neutro);
    font-size: 14px;
    font-weight: 500;
    text-decoration: none;
    white-space: normal;             /* Noche 5 · 0: el nombre se parte en dos líneas, nunca se corta con «…» */
    line-height: 1.2;
    padding-top: 6px;
    padding-bottom: 6px;
    transition: background-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .ds-riel-subicono { width: 18px; font-size: 18px; line-height: 1; text-align: center; flex: 0 0 auto; }
body.ui-v2 .ds-riel-subitem > span:not(.ds-pildora) { flex: 1 1 auto; min-width: 0; }
body.ui-v2 .ds-riel-subitem > .ds-pildora { flex: 0 0 auto; white-space: nowrap; }
body.ui-v2 a.ds-riel-subitem:hover,
body.ui-v2 .ds-riel-subitem.ds-f-hover { background: var(--ds-riel-hover); color: var(--ds-texto); }
body.ui-v2 .ds-riel-subitem.activo { background: var(--ds-riel-activo); color: var(--ds-texto-sobre-relleno); }
body.ui-v2 a.ds-riel-subitem.activo:hover { background: var(--ds-riel-activo-hover); color: var(--ds-texto-sobre-relleno); }
body.ui-v2 .ds-riel-subitem.deshabilitado { color: var(--ds-texto-3); cursor: default; }

@media (min-width: 768px) {
    body.ui-v2:not(.ds-riel-expandido) .ds-riel-sub.abierto {
        position: fixed;
        left: calc(var(--ds-riel) + 8px);
        top: 72px;                 /* ui.js lo alinea con su botón */
        z-index: 1070;
        width: 240px;
        padding: 8px;
        background: var(--ds-superficie);          /* flotante (Paso 4): blanco con la franja del título y borde azul suave */
        border: 1px solid var(--ds-flotante-borde);
        border-radius: var(--ds-radio-tarjeta);
        box-shadow: var(--ds-sombra-flotante-fuerte);
        animation: ds-aparecer 150ms ease-out;
    }
}
/* Expandido: un poco menos de margen para que quepan los nombres largos */
@media (min-width: 768px) {
    body.ui-v2.ds-riel-expandido .ds-riel-interior { padding-left: 8px; padding-right: 8px; }
}
/* Expandido (escritorio) y teléfono: submenú en línea, sin título */
body.ui-v2.ds-riel-expandido .ds-riel-sub-titulo { display: none; }
body.ui-v2.ds-riel-expandido .ds-riel-sub.abierto { padding: 2px 0 6px 22px; }
body.ui-v2.ds-riel-expandido .ds-riel-subitem:not(.activo):hover { background: var(--ds-riel-hover); }
body.ui-v2.ds-riel-expandido .ds-riel-item[aria-expanded="true"] .ds-riel-flecha { transform: rotate(90deg); }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-riel-sub-titulo { display: none; }
    body.ui-v2 .ds-riel-sub.abierto { padding: 2px 0 6px 22px; }
    body.ui-v2 .ds-riel-item[aria-expanded="true"] .ds-riel-flecha { transform: rotate(90deg); }
}

/* Nombre flotante del riel (lo crea ui.js, un solo elemento en <body>) */
body.ui-v2 .ds-tip {
    position: fixed;
    z-index: 1080;
    max-width: 260px;
    padding: 6px 10px;
    border-radius: var(--ds-radio-item);
    background: var(--ds-texto);
    color: var(--ds-texto-sobre-relleno);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 500;
    line-height: 1.35;
    pointer-events: none;
    box-shadow: var(--ds-sombra-menu);
    opacity: 0;
    transform: translateX(-4px);
    transition: opacity var(--ds-transicion), transform var(--ds-transicion);
}
body.ui-v2 .ds-tip.visible { opacity: 1; transform: none; }

/* 3b. Teléfono: el riel es un offcanvas (clase offcanvas-md) ------------- */
@media (max-width: 767.98px) {
    body.ui-v2 .ds-riel {
        --bs-offcanvas-width: 288px;
        --bs-offcanvas-bg: var(--ds-riel-fondo);
        --bs-offcanvas-border-width: 0;
        box-shadow: var(--ds-sombra-menu);
    }
    body.ui-v2 .ds-riel-interior { padding: 0 16px 16px; }
    body.ui-v2 .ds-riel-cabeza { height: 64px; padding-top: 0; margin-bottom: var(--ds-e2); }
    body.ui-v2 .ds-riel-item:hover { background: var(--ds-riel-hover); }
}

/* Marca del sistema: el logo (tres rombos, app/nombre_sistema.py) y el nombre (barra superior y riel del teléfono) */
body.ui-v2 .ds-marca {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 4px 8px 4px 4px;
    border-radius: var(--ds-radio-pildora);
    color: var(--ds-texto);
    text-decoration: none;
    white-space: nowrap;
}
body.ui-v2 .ds-marca:hover { color: var(--ds-texto); }
body.ui-v2 .ds-marca-simbolo {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 11px;
    background: var(--ds-superficie);
    color: var(--ds-texto);
    font-size: 20px;
    line-height: 1;
}
body.ui-v2 .ds-marca-logo { flex: none; display: block; width: 34px; height: 34px; }
body.ui-v2 .ds-marca-texto {
    font-size: 17px;
    font-weight: 500;
    letter-spacing: -0.02em;
    color: var(--ds-texto);
}
body.ui-v2 .ds-marca-texto b { font-weight: 700 !important; color: var(--ds-texto); letter-spacing: -0.01em; }

/* 3c. Barra superior flotante y redondeada (como Merkaru) --------------- */
body.ui-v2 .ds-barra {
    position: sticky;
    top: var(--ds-e2);
    z-index: 1020;
    display: flex;
    align-items: center;
    gap: var(--ds-e5);
    height: calc(var(--ds-alto-barra) + 2px);
    /* alineada con el contenido: mismo ancho máximo (el de las tablas), centrada */
    margin: var(--ds-e2) max(var(--ds-margen-pagina), calc((100% - var(--ds-ancho-datos)) / 2)) 0;
    padding: 0 8px 0 12px;
    background: var(--ds-barra-fondo);
    border: 1px solid var(--ds-borde-suave);
    border-radius: var(--ds-radio-dialogo);
    /* 2ª sombra = franja del fondo de la app sobre la barra: al desplazar, el
       contenido no asoma entre la barra y el borde de la ventana (va debajo
       de la sombra flotante, que se sigue viendo igual) */
    box-shadow: var(--ds-sombra-flotante), 0 -12px 0 12px var(--ds-fondo);
}
body.ui-v2 .ds-barra-menu { margin-right: calc(-1 * var(--ds-e3)); }
body.ui-v2 .ds-buscar {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;              /* en el teléfono se encoge (antes empujaba el avatar 2 px fuera) */
    max-width: 560px;
    display: flex;
    align-items: center;
}
body.ui-v2 .ds-buscar[hidden] { display: none; }
body.ui-v2 .ds-buscar-icono {
    position: absolute;
    left: 16px;
    color: var(--ds-texto-2);
    font-size: 20px;
    line-height: 1;
    pointer-events: none;
}
body.ui-v2 .ds-buscar-campo {
    width: 100%;
    min-width: 0;
    height: var(--ds-alto-buscador);
    padding: 0 44px 0 46px;
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-superficie);
    color: var(--ds-texto);
    font: inherit;
    font-size: var(--ds-tam-cuerpo);
    transition: background-color var(--ds-transicion), border-color var(--ds-transicion), box-shadow var(--ds-transicion);
}
body.ui-v2 .ds-buscar-campo::placeholder { color: var(--ds-texto-2); opacity: 1; }
body.ui-v2 .ds-buscar-campo::-webkit-search-cancel-button { cursor: pointer; }
body.ui-v2 .ds-buscar-campo:hover,
body.ui-v2 .ds-buscar-campo.ds-f-hover { border-color: var(--ds-borde-fuerte); }
body.ui-v2 .ds-buscar-campo:focus,
body.ui-v2 .ds-buscar-campo.ds-f-foco {
    outline: none;
    background: var(--ds-superficie);
    border-color: var(--ds-acento);
    box-shadow: 0 0 0 3px var(--ds-anillo);
}
body.ui-v2 .ds-buscar-tecla {
    position: absolute;
    right: 14px;
    min-width: 22px;
    padding: 1px 6px;
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: 6px;
    background: var(--ds-superficie);
    color: var(--ds-texto-2);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.5;
    text-align: center;
    box-shadow: none;
}
body.ui-v2 .ds-buscar-campo:focus ~ .ds-buscar-tecla,
body.ui-v2 .ds-buscar-campo:not(:placeholder-shown) ~ .ds-buscar-tecla { display: none !important; }
body.ui-v2 .ds-barra-derecha {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--ds-e4);
    min-width: 0;
}
body.ui-v2 .ds-unidad {
    align-items: center;
    gap: var(--ds-e2);
    min-width: 0;
    max-width: 360px;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
}
body.ui-v2 .ds-unidad > .ti { font-size: 18px; line-height: 1; }
body.ui-v2 .ds-unidad > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.ui-v2 .ds-avatar-boton {
    display: flex;
    align-items: center;
    gap: var(--ds-e2);
    height: var(--ds-alto-control);
    padding: 0 12px 0 3px;
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-superficie);
    color: var(--ds-texto);
    font-weight: 500;
    transition: background-color var(--ds-transicion), border-color var(--ds-transicion);
}
body.ui-v2 .ds-avatar-boton:hover,
body.ui-v2 .ds-avatar-boton.ds-f-hover,
body.ui-v2 .ds-avatar-boton[aria-expanded="true"] { background: var(--ds-hover); border-color: var(--ds-borde-fuerte); }
body.ui-v2 .ds-avatar {
    flex: none;
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 600;
    letter-spacing: 0.02em;
}
body.ui-v2 .ds-avatar-lg { width: 40px; height: 40px; font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-avatar-nombre { max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.ui-v2 .ds-avatar-flecha { font-size: 16px; color: var(--ds-texto-2); }
body.ui-v2 .ds-menu-usuario { min-width: 280px; }
body.ui-v2 .ds-menu-usuario-cabeza { display: flex; gap: var(--ds-e3); align-items: flex-start; padding: 10px 10px 6px; }
body.ui-v2 .ds-menu-usuario-datos { min-width: 0; }
body.ui-v2 .ds-menu-usuario-nombre { font-weight: 600; margin-bottom: 2px; }
body.ui-v2 .ds-menu-usuario-datos .ds-texto-suave { font-size: var(--ds-tam-tabla); line-height: 1.45; }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-barra {
        top: 8px;
        gap: var(--ds-e3);
        margin-top: 8px;
        padding-left: 6px;
        border-radius: var(--ds-radio-tarjeta);
    }
    body.ui-v2 .ds-barra-menu { margin-right: 0; }
    body.ui-v2 .ds-marca { padding-right: 0; }
    body.ui-v2 .ds-avatar-boton { padding-right: 8px; }
    body.ui-v2 .ds-barra-derecha { flex-shrink: 0; }   /* el buscador cede el ancho, no el usuario */
}
body.ui-v2 .ds-barra-derecha > .dropdown { flex: none; }

/* 3d. Contenido --------------------------------------------------------- */
body.ui-v2 .ds-contenido {
    --ds-ancho-max: var(--ds-ancho-datos);
    flex: 1 1 auto;
    min-width: 0;
    /* ancho máximo: tablas 125em (~1750 px), centrado con la barra superior;
       detalle y formularios más angostos, alineados a la izquierda con ella */
    max-width: calc(var(--ds-ancho-max) + 2 * var(--ds-margen-pagina));
    margin-left: max(0px, calc((100% - var(--ds-ancho-datos)) / 2 - var(--ds-margen-pagina)));
    padding: var(--ds-e3) var(--ds-margen-pagina) 48px;
    outline: none;
}
/* Ancho por página: {% set ui_ancho = "detalle" %} (o "formulario", "completo")
   a nivel superior de la plantilla; por defecto "datos". */
body.ui-v2 .ds-contenido.ds-ancho-detalle { --ds-ancho-max: var(--ds-ancho-detalle); }
body.ui-v2 .ds-contenido.ds-ancho-formulario { --ds-ancho-max: var(--ds-ancho-formulario); }
body.ui-v2 .ds-contenido.ds-ancho-completo { max-width: none; margin-left: 0; }
/* lo mismo dentro de una página (un bloque angosto en una página ancha) */
body.ui-v2 .ds-bloque-formulario { max-width: var(--ds-ancho-formulario); }
body.ui-v2 .ds-bloque-detalle { max-width: var(--ds-ancho-detalle); }
body.ui-v2 .ds-bloque-centrado { margin-left: auto; margin-right: auto; }
/* Página cuya tabla llega al borde inferior (altoMaximo "auto"): el margen de
   abajo es el del marco, así la página no se desplaza en vertical. */
body.ui-v2 .ds-contenido:has(.tb-alto-auto) { padding-bottom: var(--tb-alto-auto-margen, 12px); }
body.ui-v2 .ds-contenido:has(.tb-alto-auto) > .ds-encabezado { margin-bottom: var(--ds-e2); }
/* y la barra de filtros de esa tabla, 8 px sobre el marco (densidad: 12 filas a 1440×790) */
body.ui-v2 .tb-alto-auto.tb-v2 > .tb-barra.ds-filtros { margin-bottom: var(--ds-e2); }
body.ui-v2 .ds-mensajes { display: grid; gap: var(--ds-e2); margin: var(--ds-e3) var(--ds-margen-pagina) 0; }


/* 4. Encabezado de página ================================================= */
/* Título 26/600, contador o subtítulo 14 gris debajo (una línea), "?" junto
   al título y acciones a la derecha, centradas con el bloque. */
body.ui-v2 .ds-encabezado {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-e3) var(--ds-e4);
    margin-bottom: var(--ds-e4);
}
/* Encabezado seguido de la barra de filtros de una lista: 8 px, como en la
   sábana y la lista de SIAF (§3d). Antes unas listas dejaban 8 px y otras 16
   (Proveedores, Servicios, Abastecimiento, Catálogo). */
body.ui-v2 .ds-contenido > .ds-encabezado:has(+ .ds-filtros) { margin-bottom: var(--ds-e2); }
/* Fase "todo" (menos cromo vertical): el contador o la línea de ayuda van en
   la MISMA línea que el título, alineados por la base del texto
   ("Sábana de Compras ⓘ   43 SIAF"); bajan a otra línea si no caben. */
body.ui-v2 .ds-encabezado-texto {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: var(--ds-e3);
    min-width: 0;
    flex: 1 1 320px;
}
body.ui-v2 .ds-encabezado-titulo {
    display: flex;
    align-items: center;
    gap: var(--ds-e2);
    min-width: 0;
}
body.ui-v2 .ds-titulo {
    margin: 0;
    color: var(--ds-texto);
    font-size: var(--ds-tam-titulo);
    font-weight: 600;
    line-height: 1.23077;
    letter-spacing: -0.02em;
}
body.ui-v2 .ds-subtitulo {
    display: flex;
    align-items: baseline;
    gap: 6px;
    min-width: 0;
    min-height: 20px;
    margin: 0;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.42858;
    white-space: nowrap;
    overflow: hidden;
}
body.ui-v2 .ds-contador {
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-cuerpo);
    white-space: nowrap;
}
body.ui-v2 .ds-subtitulo-sep { color: var(--ds-texto-3); }
body.ui-v2 .ds-linea-ayuda { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
body.ui-v2 .ds-encabezado-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2);
    margin-left: auto;
}
body.ui-v2 .ds-encabezado-acciones .ds-rotulo-en-linea { color: var(--ds-texto-2); margin-right: var(--ds-e1); }
/* Botón "?" de ayuda */
body.ui-v2 .ds-ayuda {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--ds-texto-3);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    transition: background-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .ds-ayuda:hover,
body.ui-v2 .ds-ayuda.ds-f-hover,
body.ui-v2 .ds-ayuda[aria-expanded="true"] { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-seccion-titulo {
    margin: 0 0 var(--ds-e3);
    font-size: var(--ds-tam-seccion);
    font-weight: 600;
}


/* 5. Botones ============================================================== */
/* Alto 40 px, totalmente redondos. Primario relleno acento y texto blanco
   (máximo UNO por pantalla); secundario con borde; terciario solo texto.
   .ds-btn funciona solo o junto a .btn de Bootstrap. */
body.ui-v2 .ds-btn {
    --ds-btn-alto: var(--ds-alto-control);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ds-e2);
    height: var(--ds-btn-alto);
    padding: 0 18px;
    border: 1px solid transparent;
    border-radius: var(--ds-radio-pildora);
    background: transparent;
    color: var(--ds-texto);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-cuerpo);
    font-weight: 500;
    line-height: 1;
    text-decoration: none;
    white-space: nowrap;
    vertical-align: middle;
    cursor: pointer;
    user-select: none;
    transition: background-color var(--ds-transicion), border-color var(--ds-transicion), color var(--ds-transicion), box-shadow var(--ds-transicion);
}
body.ui-v2 .ds-btn > .ti,
body.ui-v2 .ds-btn > .bi { font-size: 18px; line-height: 1; margin-left: -2px; }
body.ui-v2 .ds-btn:focus-visible,
body.ui-v2 .ds-btn.ds-f-foco { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 2px; box-shadow: none; }

/* Primario */
body.ui-v2 .ds-btn-primario {
    background: var(--ds-relleno-primario);
    border-color: var(--ds-relleno-primario);
    color: var(--ds-texto-sobre-relleno);
}
body.ui-v2 .ds-btn-primario:hover,
body.ui-v2 .ds-btn-primario.ds-f-hover {
    background: var(--ds-relleno-primario-hover);
    border-color: var(--ds-relleno-primario-hover);
    color: var(--ds-texto-sobre-relleno);
}
body.ui-v2 .ds-btn-primario:active,
body.ui-v2 .ds-btn-primario.ds-f-activo {
    background: var(--ds-relleno-primario-activo);
    border-color: var(--ds-relleno-primario-activo);
    color: var(--ds-texto-sobre-relleno);
}
/* Secundario */
body.ui-v2 .ds-btn-secundario { background: var(--ds-superficie); border-color: var(--ds-borde-fuerte); color: var(--ds-texto); }
body.ui-v2 .ds-btn-secundario:hover,
body.ui-v2 .ds-btn-secundario.ds-f-hover { background: var(--ds-hover); border-color: var(--ds-borde-hover); color: var(--ds-texto); }
body.ui-v2 .ds-btn-secundario:active,
body.ui-v2 .ds-btn-secundario.ds-f-activo { background: var(--ds-neutro-fondo); border-color: var(--ds-borde-hover); color: var(--ds-texto); }
/* Terciario: solo texto */
body.ui-v2 .ds-btn-terciario { background: transparent; border-color: transparent; color: var(--ds-acento-oscuro); padding: 0 12px; }
body.ui-v2 .ds-btn-terciario:hover,
body.ui-v2 .ds-btn-terciario.ds-f-hover { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-btn-terciario:active,
body.ui-v2 .ds-btn-terciario.ds-f-activo { background: var(--ds-acento-claro-2); color: var(--ds-acento-oscuro); }
/* Fantasma (neutro, solo texto; nombre de la primera versión) */
body.ui-v2 .ds-btn-fantasma { background: transparent; border-color: transparent; color: var(--ds-texto-2); padding: 0 12px; }
body.ui-v2 .ds-btn-fantasma:hover,
body.ui-v2 .ds-btn-fantasma.ds-f-hover { background: var(--ds-hover); color: var(--ds-texto); }
body.ui-v2 .ds-btn-fantasma:active,
body.ui-v2 .ds-btn-fantasma.ds-f-activo { background: var(--ds-neutro-fondo); color: var(--ds-texto); }
body.ui-v2 .ds-btn-fantasma.ds-btn-acento { color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-btn-fantasma.ds-btn-acento:hover { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
/* Peligro */
body.ui-v2 .ds-btn-peligro { background: var(--ds-peligro); border-color: var(--ds-peligro); color: var(--ds-texto-sobre-relleno); }
body.ui-v2 .ds-btn-peligro:hover,
body.ui-v2 .ds-btn-peligro.ds-f-hover { background: var(--ds-peligro-hover); border-color: var(--ds-peligro-hover); color: var(--ds-texto-sobre-relleno); }
body.ui-v2 .ds-btn-peligro:active,
body.ui-v2 .ds-btn-peligro.ds-f-activo { background: var(--ds-peligro-activo); border-color: var(--ds-peligro-activo); color: var(--ds-texto-sobre-relleno); }
body.ui-v2 .ds-btn-peligro-suave { background: var(--ds-superficie); border-color: var(--ds-error-borde); color: var(--ds-error); }
body.ui-v2 .ds-btn-peligro-suave:hover,
body.ui-v2 .ds-btn-peligro-suave.ds-f-hover { background: var(--ds-error-fondo); border-color: var(--ds-error-borde); color: var(--ds-error); }
body.ui-v2 .ds-btn-peligro-suave:active,
body.ui-v2 .ds-btn-peligro-suave.ds-f-activo { background: var(--ds-error-fondo-2); border-color: var(--ds-error-borde-2); color: var(--ds-error); }
/* Tamaños */
body.ui-v2 .ds-btn-sm { --ds-btn-alto: 32px; padding: 0 14px; gap: 6px; font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-btn-sm > .ti,
body.ui-v2 .ds-btn-sm > .bi { font-size: 16px; }
body.ui-v2 .ds-btn-lg { --ds-btn-alto: 44px; padding: 0 22px; font-size: 15px; }
body.ui-v2 .ds-btn-bloque { display: flex; width: 100%; }
/* Solo ícono (siempre con aria-label): círculo de 40 px */
body.ui-v2 .ds-btn-icono {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: var(--ds-alto-control);
    height: var(--ds-alto-control);
    padding: 0;
    border: 1px solid transparent;
    border-radius: 50%;
    background: transparent;
    color: var(--ds-texto-2);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    transition: background-color var(--ds-transicion), color var(--ds-transicion), border-color var(--ds-transicion);
}
body.ui-v2 .ds-btn-icono:hover,
body.ui-v2 .ds-btn-icono.ds-f-hover,
body.ui-v2 .ds-btn-icono[aria-expanded="true"] { background: var(--ds-hover); color: var(--ds-texto); }
body.ui-v2 .ds-btn-icono:active,
body.ui-v2 .ds-btn-icono.ds-f-activo { background: var(--ds-neutro-fondo); color: var(--ds-texto); }
body.ui-v2 .ds-btn-icono:focus-visible,
body.ui-v2 .ds-btn-icono.ds-f-foco { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 2px; }
body.ui-v2 .ds-btn-icono.ds-btn-sm { width: 32px; height: 32px; font-size: 18px; }
body.ui-v2 .ds-btn-icono.ds-btn-borde { border-color: var(--ds-borde-fuerte); background: var(--ds-superficie); }
/* Deshabilitado */
body.ui-v2 .ds-btn:disabled,
body.ui-v2 .ds-btn.disabled,
body.ui-v2 .ds-btn[aria-disabled="true"] {
    background: var(--ds-neutro-fondo);
    border-color: var(--ds-neutro-fondo);
    color: var(--ds-texto-3);
    cursor: not-allowed;
    pointer-events: none;
    box-shadow: none;
}
/* primario: tinte claro del relleno primario y texto blanco (como "Continuar" de Merkaru) */
body.ui-v2 .ds-btn-primario:disabled,
body.ui-v2 .ds-btn-primario.disabled,
body.ui-v2 .ds-btn-primario[aria-disabled="true"] {
    background: var(--ds-relleno-primario-apagado);
    border-color: var(--ds-relleno-primario-apagado);
    color: var(--ds-texto-sobre-relleno);
}
body.ui-v2 .ds-btn-secundario:disabled,
body.ui-v2 .ds-btn-secundario.disabled,
body.ui-v2 .ds-btn-secundario[aria-disabled="true"],
body.ui-v2 .ds-btn-peligro-suave:disabled,
body.ui-v2 .ds-btn-peligro-suave.disabled { background: var(--ds-superficie); border-color: var(--ds-borde); }
body.ui-v2 .ds-btn-terciario:disabled,
body.ui-v2 .ds-btn-terciario.disabled,
body.ui-v2 .ds-btn-terciario[aria-disabled="true"],
body.ui-v2 .ds-btn-fantasma:disabled,
body.ui-v2 .ds-btn-fantasma.disabled,
body.ui-v2 .ds-btn-icono:disabled,
body.ui-v2 .ds-btn-icono.disabled,
body.ui-v2 .ds-btn-icono[aria-disabled="true"] { background: transparent; border-color: transparent; color: var(--ds-texto-3); cursor: not-allowed; pointer-events: none; }
/* Cargando: UI.cargando(boton, true) */
body.ui-v2 .ds-btn.cargando,
body.ui-v2 .btn.cargando {
    position: relative;
    color: transparent !important;
    pointer-events: none;
}
/* opacity y no visibility: el rótulo sigue siendo el nombre accesible del botón */
body.ui-v2 .ds-btn.cargando > *,
body.ui-v2 .btn.cargando > * { opacity: 0; }
body.ui-v2 .ds-btn.cargando::after,
body.ui-v2 .btn.cargando::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 16px;
    height: 16px;
    margin: -8px 0 0 -8px;
    border: 2px solid var(--ds-texto-2);
    border-right-color: transparent;
    border-radius: 50%;
    animation: ds-girar 700ms linear infinite;
}
body.ui-v2 .ds-btn-primario.cargando::after,
body.ui-v2 .ds-btn-peligro.cargando::after,
body.ui-v2 .btn-primary.cargando::after,
body.ui-v2 .btn-danger.cargando::after { border-color: var(--ds-texto-sobre-relleno); border-right-color: transparent; }
@keyframes ds-girar { to { transform: rotate(360deg); } }
@keyframes ds-aparecer { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
body.ui-v2 .ds-grupo-botones { display: inline-flex; flex-wrap: wrap; gap: var(--ds-e2); align-items: center; }

/* Bootstrap .btn dentro del ámbito: mismas medidas y la misma forma */
body.ui-v2 .btn {
    --bs-btn-font-family: var(--ds-fuente);
    --bs-btn-font-weight: 500;
    --bs-btn-font-size: var(--ds-tam-cuerpo);
    --bs-btn-line-height: 1.42858;   /* 20 px con 14 px; sin unidad: crece si el navegador agranda el texto */
    --bs-btn-padding-x: 18px;
    --bs-btn-padding-y: 9px;
    --bs-btn-border-radius: var(--ds-radio-pildora);
    --bs-btn-focus-box-shadow: 0 0 0 3px var(--ds-anillo);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    transition: background-color var(--ds-transicion), border-color var(--ds-transicion), color var(--ds-transicion), box-shadow var(--ds-transicion);
}
body.ui-v2 .btn-sm,
body.ui-v2 .btn-group-sm > .btn {
    --bs-btn-padding-x: 14px;
    --bs-btn-padding-y: 6px;
    --bs-btn-font-size: var(--ds-tam-tabla);
    --bs-btn-line-height: 1.38462;   /* 18 px con 13 px */
    --bs-btn-border-radius: var(--ds-radio-pildora);
}
body.ui-v2 .btn-lg { --bs-btn-font-size: 15px; --bs-btn-padding-y: 11px; --bs-btn-padding-x: 22px; }
body.ui-v2 .btn-group > .btn { border-radius: 0; }
body.ui-v2 .btn-group > .btn:first-child,
body.ui-v2 .btn-group > .btn-check:first-child + .btn { border-top-left-radius: var(--ds-radio-pildora); border-bottom-left-radius: var(--ds-radio-pildora); }
body.ui-v2 .btn-group > .btn:last-child { border-top-right-radius: var(--ds-radio-pildora); border-bottom-right-radius: var(--ds-radio-pildora); }
body.ui-v2 .btn-primary {
    --bs-btn-color: var(--ds-texto-sobre-relleno);
    --bs-btn-bg: var(--ds-relleno-primario);
    --bs-btn-border-color: var(--ds-relleno-primario);
    --bs-btn-hover-color: var(--ds-texto-sobre-relleno);
    --bs-btn-hover-bg: var(--ds-relleno-primario-hover);
    --bs-btn-hover-border-color: var(--ds-relleno-primario-hover);
    --bs-btn-active-color: var(--ds-texto-sobre-relleno);
    --bs-btn-active-bg: var(--ds-relleno-primario-activo);
    --bs-btn-active-border-color: var(--ds-relleno-primario-activo);
    --bs-btn-disabled-color: var(--ds-texto-sobre-relleno);
    --bs-btn-disabled-bg: var(--ds-relleno-primario-apagado);
    --bs-btn-disabled-border-color: var(--ds-relleno-primario-apagado);
    --bs-btn-disabled-opacity: 1;
    --bs-btn-focus-shadow-rgb: 26, 111, 160;
}
body.ui-v2 .btn-outline-primary {
    --bs-btn-color: var(--ds-acento-oscuro);
    --bs-btn-bg: var(--ds-superficie);
    --bs-btn-border-color: var(--ds-borde-fuerte);
    --bs-btn-hover-color: var(--ds-acento-oscuro);
    --bs-btn-hover-bg: var(--ds-acento-claro);
    --bs-btn-hover-border-color: var(--ds-acento-borde);
    --bs-btn-active-color: var(--ds-acento-oscuro);
    --bs-btn-active-bg: var(--ds-acento-claro-2);
    --bs-btn-active-border-color: var(--ds-acento-borde);
    --bs-btn-disabled-color: var(--ds-texto-3);
    --bs-btn-disabled-bg: var(--ds-superficie);
    --bs-btn-disabled-border-color: var(--ds-borde);
    --bs-btn-disabled-opacity: 1;
    --bs-btn-focus-shadow-rgb: 26, 111, 160;
}
body.ui-v2 .btn-secondary,
body.ui-v2 .btn-outline-secondary,
body.ui-v2 .btn-light,
body.ui-v2 .btn-outline-dark,
body.ui-v2 .btn-dark,
body.ui-v2 .btn-outline-light {
    --bs-btn-color: var(--ds-texto);
    --bs-btn-bg: var(--ds-superficie);
    --bs-btn-border-color: var(--ds-borde-fuerte);
    --bs-btn-hover-color: var(--ds-texto);
    --bs-btn-hover-bg: var(--ds-hover);
    --bs-btn-hover-border-color: var(--ds-borde-hover);
    --bs-btn-active-color: var(--ds-texto);
    --bs-btn-active-bg: var(--ds-neutro-fondo);
    --bs-btn-active-border-color: var(--ds-borde-hover);
    --bs-btn-disabled-color: var(--ds-texto-3);
    --bs-btn-disabled-bg: var(--ds-superficie);
    --bs-btn-disabled-border-color: var(--ds-borde);
    --bs-btn-disabled-opacity: 1;
    --bs-btn-focus-shadow-rgb: 26, 111, 160;
}
body.ui-v2 .btn-danger {
    --bs-btn-bg: var(--ds-error);
    --bs-btn-border-color: var(--ds-error);
    --bs-btn-hover-bg: var(--ds-peligro-hover);
    --bs-btn-hover-border-color: var(--ds-peligro-hover);
    --bs-btn-active-bg: var(--ds-peligro-activo);
    --bs-btn-active-border-color: var(--ds-peligro-activo);
    --bs-btn-disabled-color: var(--ds-texto-3);
    --bs-btn-disabled-bg: var(--ds-neutro-fondo);
    --bs-btn-disabled-border-color: var(--ds-neutro-fondo);
    --bs-btn-disabled-opacity: 1;
}
body.ui-v2 .btn-outline-danger {
    --bs-btn-color: var(--ds-error);
    --bs-btn-bg: var(--ds-superficie);
    --bs-btn-border-color: var(--ds-error-borde);
    --bs-btn-hover-color: var(--ds-error);
    --bs-btn-hover-bg: var(--ds-error-fondo);
    --bs-btn-hover-border-color: var(--ds-error-borde);
    --bs-btn-active-color: var(--ds-error);
    --bs-btn-active-bg: var(--ds-error-fondo-2);
    --bs-btn-active-border-color: var(--ds-error-borde-2);
}
body.ui-v2 .btn-success,
body.ui-v2 .btn-outline-success {
    --bs-btn-color: var(--ds-exito);
    --bs-btn-bg: var(--ds-exito-fondo);
    --bs-btn-border-color: var(--ds-exito-borde);
    --bs-btn-hover-color: var(--ds-exito);
    --bs-btn-hover-bg: var(--ds-exito-fondo-2);
    --bs-btn-hover-border-color: var(--ds-exito-borde-2);
    --bs-btn-active-color: var(--ds-exito);
    --bs-btn-active-bg: var(--ds-exito-borde);
    --bs-btn-active-border-color: var(--ds-exito-borde-2);
}
body.ui-v2 .btn-warning,
body.ui-v2 .btn-outline-warning {
    --bs-btn-color: var(--ds-aviso);
    --bs-btn-bg: var(--ds-aviso-fondo);
    --bs-btn-border-color: var(--ds-aviso-borde);
    --bs-btn-hover-color: var(--ds-aviso);
    --bs-btn-hover-bg: var(--ds-aviso-fondo-2);
    --bs-btn-hover-border-color: var(--ds-aviso-borde-2);
}
body.ui-v2 .btn-link {
    --bs-btn-color: var(--ds-acento-oscuro);
    --bs-btn-hover-color: var(--ds-acento-fuerte-activo);
    --bs-btn-active-color: var(--ds-acento-fuerte-activo);
    text-underline-offset: 2px;
}


/* 6. Chips y píldoras de filtro =========================================== */
body.ui-v2 {
    /* derivados locales de chips, filtros y tablas (no son tokens del contrato) */
    --tb-pildora-fondo: var(--ds-control-fondo);
    --tb-pildora-hover: var(--ds-control-hover);
    --tb-borde-hover: var(--ds-borde-hover);
    /* anillo de foco de chips, píldoras, "⋯", encabezados que ordenan, KPI:
       2 px del color de la superficie + 2 px de acento oscuro (5.5:1 sobre
       blanco; el celeste translúcido de antes daba 1.3:1, bajo el 3:1 de
       WCAG 1.4.11). Los CAMPOS de texto siguen con el anillo suave de §11
       (borde acento + --ds-anillo): tienen cursor y borde que cambian. */
    --tb-anillo: 0 0 0 2px var(--ds-superficie), 0 0 0 4px var(--ds-acento-oscuro);
    --tb-anillo-campo: 0 0 0 3px var(--ds-anillo);
    --tb-sombra-panel: var(--ds-sombra-panel);
    --tb-relleno-hover: var(--ds-relleno-primario-hover);   /* chip activo al pasar */
    --tb-alto-auto-margen: 8px;    /* altoMaximo "auto": aire bajo el marco (tabla.js lo lee) */
}


/* 6a. Barra de filtros ---------------------------------------------------- */
body.ui-v2 .ds-filtros {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2, 8px);
    margin: 0 0 var(--ds-e3, 12px);
}
body.ui-v2 .ds-filtros-separador {
    width: 1px;
    height: 20px;
    margin: 0 var(--ds-e1, 4px);
    background: var(--ds-borde);
}
body.ui-v2 .ds-chips,
body.ui-v2 .ds-pildoras {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2, 8px);
}
/* Barra de TablaDatos: filtros a la izquierda (se acomodan en otra línea si
   no caben) y contador + densidad fijos arriba a la derecha. */
body.ui-v2 .tb-v2 > .tb-barra {
    flex-wrap: nowrap;
    align-items: flex-start;
    gap: var(--ds-e4, 16px);
}
body.ui-v2 .tb-barra-filtros {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2, 8px);
    min-width: 0;
}
body.ui-v2 .tb-barra-filtros > .ds-chips + .ds-pildoras { margin-left: var(--ds-e2, 8px); }
body.ui-v2 .tb-barra-filtros > .ds-pildoras:empty,
body.ui-v2 .tb-barra-filtros > .tb-chips:empty { display: none; }
body.ui-v2 .tb-barra-filtros > .tb-chips { display: flex; flex-wrap: wrap; gap: var(--ds-e1, 4px); }
body.ui-v2 .tb-barra-fin {
    display: flex;
    flex: none;
    align-items: center;
    gap: var(--ds-e3, 12px);
    min-height: var(--ds-alto-chip, 36px);
    margin-left: auto;
}
/* Con selector de orden (opción ordenes): dos líneas fijas. Arriba los chips
   (se acomodan en más líneas solo si no caben) con "Quitar filtros" y la
   densidad a la derecha; abajo las píldoras, "Más filtros" y, a la derecha,
   "Ordenar: …" (como el "Sort" de la fila de píldoras). Cada línea mide su
   propio ancho: la píldora de orden no le quita espacio a los chips.
   .tb-barra-filtros se "abre" (display: contents) para que sus hijos se
   repartan en las dos líneas; ::after es el salto de línea (alto 0). Como el
   salto suma dos separaciones, la primera línea devuelve una (-8 px abajo):
   entre líneas quedan 8 px, también si "Ordenar" baja a otra línea. */
body.ui-v2 .tb-v2 > .tb-barra.tb-barra-con-orden {
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2, 8px);
}
body.ui-v2 .tb-barra-con-orden > .tb-barra-filtros { display: contents; }
body.ui-v2 .tb-barra-con-orden > .tb-barra-filtros > .tb-buscador-caja { order: 1; margin-bottom: calc(-1 * var(--ds-e2, 8px)); }
body.ui-v2 .tb-barra-con-orden > .tb-barra-filtros > .ds-chips { order: 2; flex: 1 1 0; min-width: 0; margin-bottom: calc(-1 * var(--ds-e2, 8px)); }
body.ui-v2 .tb-barra-con-orden > .tb-barra-fin { order: 3; align-self: flex-start; margin-left: var(--ds-e2, 8px); margin-bottom: calc(-1 * var(--ds-e2, 8px)); }
body.ui-v2 .tb-barra-con-orden::after { content: ""; order: 4; flex: 0 0 100%; height: 0; }
body.ui-v2 .tb-barra-con-orden > .tb-barra-filtros > .ds-pildoras { order: 5; margin-left: 0; }
body.ui-v2 .tb-barra-con-orden > .tb-barra-filtros > .ds-mas-filtros { order: 6; }
body.ui-v2 .tb-barra-con-orden > .tb-barra-filtros > .tb-chips { order: 7; }
body.ui-v2 .tb-barra-con-orden > .ds-pildora-orden { order: 8; margin-left: auto; }
/* píldora de orden: ícono de flechas gris; en el panel, la opción elegida con ✓ acento */
body.ui-v2 .ds-pildora-orden .ds-pildora-orden-icono { color: var(--ds-texto-2); font-size: 16px; }
body.ui-v2 .ds-pildora-orden .ds-pildora-filtro-etiqueta { color: var(--ds-neutro); }   /* "Ordenar:" sobre el gris de la píldora: 6.75:1 */
body.ui-v2 .ds-mas-item.ds-orden-item-activo > .ti-check { color: var(--ds-acento-oscuro); }

/* Buscador propio de la tabla (cuando no manda la barra superior) */
body.ui-v2 .tb-buscador-caja {
    position: relative;
    display: inline-flex;
    align-items: center;
    margin: 0;
}
body.ui-v2 .tb-buscador-caja > .ti {
    position: absolute;
    left: 12px;
    color: var(--ds-texto-3);
    font-size: 16px;
    pointer-events: none;
}
body.ui-v2 .tb-v2 .tb-buscador,
body.ui-v2 .tb-buscador-caja > .tb-buscador {
    width: 240px;
    max-width: 100%;
    height: var(--ds-alto-chip, 36px);
    padding: 0 14px 0 36px;
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-pildora, 999px);
    background: var(--ds-superficie);
    color: var(--ds-texto);
    font-family: var(--ds-fuente, "Inter", system-ui, sans-serif);
    font-size: 13px;
    transition: border-color var(--ds-transicion, 150ms ease), box-shadow var(--ds-transicion, 150ms ease);
}
body.ui-v2 .tb-v2 .tb-buscador::placeholder { color: var(--ds-texto-2); }
body.ui-v2 .tb-v2 .tb-buscador:hover { border-color: var(--tb-borde-hover); }
body.ui-v2 .tb-v2 .tb-buscador:focus { border-color: var(--ds-acento); box-shadow: var(--tb-anillo-campo); outline: 0; }
/* tabla vieja (sin v2) dentro de una página ui_v2 */
body.ui-v2 .tb:not(.tb-v2) > .tb-barra { gap: var(--ds-e2, 8px) !important; margin-bottom: var(--ds-e3, 12px) !important; }
body.ui-v2 .tb:not(.tb-v2) .tb-buscador { max-width: 280px; border-radius: var(--ds-radio-campo, 12px); }
/* El buscador de la barra superior reemplaza al de la tabla principal (ui.js) */
body.ui-v2 .tb-buscador.ds-oculto-por-barra { display: none !important; }


/* 6b. Chips de estado ----------------------------------------------------- */
body.ui-v2 .ds-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-e2, 8px);
    height: var(--ds-alto-chip, 36px);
    padding: 0 var(--ds-e4, 16px);
    border: 1px solid var(--ds-borde-fuerte);   /* Corrección 2: borde de control (3:1), fondo gris claro */
    border-radius: var(--ds-radio-pildora, 999px);
    background: var(--ds-control-fondo);
    color: var(--ds-texto);
    font-family: var(--ds-fuente, "Inter", system-ui, sans-serif);
    font-size: 13px;
    font-weight: 500;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    transition: background-color var(--ds-transicion, 150ms ease), border-color var(--ds-transicion, 150ms ease), color var(--ds-transicion, 150ms ease), box-shadow var(--ds-transicion, 150ms ease);
}
body.ui-v2 a.ds-chip { text-decoration: none; }   /* chip como enlace (índice de /estilo): sin subrayado */
body.ui-v2 a.ds-chip:hover { color: var(--ds-texto); }
body.ui-v2 .ds-chip:hover,
body.ui-v2 .ds-chip.ds-f-hover {
    border-color: var(--tb-borde-hover);
    background: var(--ds-control-hover);
}
body.ui-v2 .ds-chip:focus-visible,
body.ui-v2 .ds-chip.ds-f-foco { outline: 0; box-shadow: var(--tb-anillo); border-color: var(--ds-acento); }
/* activo: relleno primario #1a6fa0 y texto blanco (token --ds-relleno-primario;
   el celeste no lleva texto encima) */
body.ui-v2 .ds-chip.ds-chip-activo,
body.ui-v2 .ds-chip.activo,
body.ui-v2 .ds-chip[aria-pressed="true"],
body.ui-v2 .ds-chip.ds-f-activo {
    border-color: var(--ds-relleno-primario);
    background: var(--ds-relleno-primario);
    color: var(--ds-texto-sobre-relleno);
}
body.ui-v2 .ds-chip.ds-chip-activo:hover,
body.ui-v2 .ds-chip.activo:hover,
body.ui-v2 .ds-chip[aria-pressed="true"]:hover,
body.ui-v2 .ds-chip.ds-f-activo.ds-f-hover {
    border-color: var(--tb-relleno-hover);
    background: var(--tb-relleno-hover);
}
body.ui-v2 .ds-chip:disabled,
body.ui-v2 .ds-chip.disabled,
body.ui-v2 .ds-chip[aria-disabled="true"] {
    border-color: var(--ds-borde);
    background: var(--ds-superficie);
    color: var(--ds-texto-3);
    cursor: not-allowed;
    pointer-events: none;
    box-shadow: none;
}
body.ui-v2 .ds-chip-conteo {
    color: var(--ds-texto-2);
    font-size: 12px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .ds-chip-conteo:empty { display: none; }
body.ui-v2 .ds-chip.ds-chip-activo .ds-chip-conteo,
body.ui-v2 .ds-chip.activo .ds-chip-conteo,
body.ui-v2 .ds-chip[aria-pressed="true"] .ds-chip-conteo,
body.ui-v2 .ds-chip.ds-f-activo .ds-chip-conteo { color: var(--ds-texto-sobre-relleno-2); }   /* 4.78:1 sobre #1a6fa0 */
body.ui-v2 .ds-chip:disabled .ds-chip-conteo,
body.ui-v2 .ds-chip[aria-disabled="true"] .ds-chip-conteo { color: var(--ds-texto-3); }


/* 6c. Píldoras de filtro desplegables ------------------------------------- */
/* Dos formas: <button class="ds-pildora-filtro"> suelta ("Más filtros", o
   marcado estático) y <div class="ds-pildora-filtro"> con dos botones
   (.ds-pildora-filtro-boton abre el panel; .ds-pildora-filtro-quitar = ✕,
   fuera del primero). El macro viejo .ds-chip.ds-chip-desplegable se ve igual. */
body.ui-v2 .ds-pildora-filtro,
body.ui-v2 .ds-chip.ds-chip-desplegable {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: var(--ds-alto-chip, 36px);
    padding: 0 12px 0 14px;
    border: 1px solid var(--ds-borde-fuerte);   /* Corrección 2: borde de control (3:1) */
    border-radius: var(--ds-radio-pildora, 999px);
    background: var(--tb-pildora-fondo);
    color: var(--ds-texto);
    font-family: var(--ds-fuente, "Inter", system-ui, sans-serif);
    font-size: 13px;
    font-weight: 500;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    transition: background-color var(--ds-transicion, 150ms ease), color var(--ds-transicion, 150ms ease), border-color var(--ds-transicion, 150ms ease), box-shadow var(--ds-transicion, 150ms ease);
}
body.ui-v2 div.ds-pildora-filtro { gap: 0; padding: 0; cursor: default; }
body.ui-v2 .ds-pildora-filtro:hover,
body.ui-v2 .ds-pildora-filtro.ds-f-hover,
body.ui-v2 .ds-chip.ds-chip-desplegable:hover {
    border-color: var(--tb-borde-hover);
    background: var(--tb-pildora-hover);
}
body.ui-v2 .ds-pildora-filtro-boton,
body.ui-v2 .ds-pildora-filtro-quitar {
    display: inline-flex;
    align-items: center;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
}
body.ui-v2 .ds-pildora-filtro-boton {
    gap: 6px;
    height: 100%;
    padding: 0 12px 0 14px;
    border-radius: var(--ds-radio-pildora, 999px);
}
body.ui-v2 .ds-pildora-filtro-valor { font-weight: 600; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-pildora-filtro-valor:empty { display: none; }
body.ui-v2 .ds-pildora-filtro > .ti,
body.ui-v2 .ds-pildora-filtro-flecha {
    color: var(--ds-texto-2);
    font-size: 16px;
    transition: transform var(--ds-transicion, 150ms ease), color var(--ds-transicion, 150ms ease);
}
body.ui-v2 .ds-pildora-filtro-abierta .ds-pildora-filtro-flecha,
body.ui-v2 .ds-chip-desplegable[aria-expanded="true"]::after { transform: rotate(180deg); }
/* activa: fondo acento claro, texto acento oscuro, valor visible y ✕ */
body.ui-v2 .ds-pildora-filtro.ds-pildora-filtro-activa,
body.ui-v2 .ds-pildora-filtro.ds-f-activo,
body.ui-v2 .ds-chip.ds-chip-desplegable.con-valor {
    border-color: var(--ds-acento);
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
}
body.ui-v2 .ds-pildora-filtro.ds-pildora-filtro-activa:hover,
body.ui-v2 .ds-pildora-filtro.ds-f-activo.ds-f-hover,
body.ui-v2 .ds-chip.ds-chip-desplegable.con-valor:hover { background: var(--ds-acento-claro-2); }
body.ui-v2 .ds-pildora-filtro-activa .ds-pildora-filtro-flecha,
body.ui-v2 .ds-pildora-filtro.ds-f-activo > .ti { color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-pildora-filtro-activa .ds-pildora-filtro-boton { padding-right: 2px; }
body.ui-v2 .ds-pildora-filtro-quitar {
    justify-content: center;
    width: 24px;
    height: 24px;
    margin: 0 6px 0 2px;
    padding: 0;
    border-radius: 50%;
    font-size: 14px;
    transition: background-color var(--ds-transicion, 150ms ease);
}
body.ui-v2 .ds-pildora-filtro-quitar:hover { background: var(--ds-acento-velo); }
/* abierta (su panel está a la vista) */
body.ui-v2 .ds-pildora-filtro.ds-pildora-filtro-abierta:not(.ds-pildora-filtro-activa),
body.ui-v2 .ds-chip.ds-chip-desplegable[aria-expanded="true"]:not(.con-valor) { background: var(--tb-pildora-hover); }
/* foco de teclado en el botón de adentro o en la píldora suelta */
body.ui-v2 .ds-pildora-filtro-boton:focus-visible,
body.ui-v2 .ds-pildora-filtro-quitar:focus-visible,
body.ui-v2 button.ds-pildora-filtro:focus-visible,
body.ui-v2 .ds-pildora-filtro.ds-f-foco,
body.ui-v2 .ds-chip.ds-chip-desplegable:focus-visible { outline: 0; box-shadow: var(--tb-anillo); }
/* deshabilitada */
body.ui-v2 .ds-pildora-filtro:disabled,
body.ui-v2 .ds-pildora-filtro.disabled,
body.ui-v2 .ds-pildora-filtro[aria-disabled="true"] {
    background: var(--tb-pildora-fondo);
    color: var(--ds-texto-3);
    cursor: not-allowed;
    pointer-events: none;
}
body.ui-v2 .ds-pildora-filtro:disabled > .ti,
body.ui-v2 .ds-pildora-filtro.disabled .ti,
body.ui-v2 .ds-pildora-filtro[aria-disabled="true"] .ti { color: var(--ds-texto-3); }
/* "Más filtros" (ícono a la izquierda) */
body.ui-v2 .ds-mas-filtros { padding: 0 14px 0 12px; }
body.ui-v2 .ds-mas-filtros.ds-pildora-filtro-abierta { background: var(--tb-pildora-hover); }
/* macro viejo: .ds-chip.ds-chip-desplegable (valor y "+N") */
body.ui-v2 .ds-chip.ds-chip-desplegable::after {
    content: "";
    width: 6px;
    height: 6px;
    margin: -3px 2px 0 2px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg);
    opacity: 0.7;
    transition: transform var(--ds-transicion, 150ms ease);
}
body.ui-v2 .ds-chip.ds-chip-desplegable[aria-expanded="true"]::after { transform: rotate(225deg); margin-top: 3px; }
body.ui-v2 .ds-chip-valor { font-weight: 600; }
body.ui-v2 .ds-chip-mas { font-weight: 600; opacity: 0.8; }


/* 6d. Panel de filtro (píldora y embudo) ---------------------------------- */
body.ui-v2 .tb-popover,
body.ui-v2 .ds-menu-filtro {
    z-index: 1060;
    min-width: 240px;
    max-width: 320px;
    padding: var(--ds-e3, 12px);
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-tarjeta, 16px);
    background: var(--ds-superficie);
    box-shadow: var(--tb-sombra-panel);
    color: var(--ds-texto);
    font-family: var(--ds-fuente, "Inter", system-ui, sans-serif);
    font-size: 13px;
    line-height: 1.4;
}
body.ui-v2 .ds-menu-filtro { --bs-dropdown-zindex: 1060; max-height: 360px; overflow-y: auto; }
body.ui-v2 .tb-popover.ds-pildora-panel { min-width: 260px; }
body.ui-v2 .tb-popover { position: absolute; }   /* tabla.js le pone top/left (antes lo daba custom.css) */
body.ui-v2 .tb-pop-titulo {
    margin: 0 0 var(--ds-e2, 8px);
    color: var(--ds-texto);
    font-size: 13px;
    font-weight: 600;
}
body.ui-v2 .tb-pop-lista {
    display: flex;
    flex-direction: column;
    gap: 0;
    max-height: 280px;
    margin: 0 -4px;
    overflow-y: auto;
}
body.ui-v2 .tb-pop-item,
body.ui-v2 .ds-menu-filtro .form-check {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 34px;
    margin: 0;
    padding: 6px 8px;
    border-radius: 10px;
    cursor: pointer;
    transition: background-color var(--ds-transicion, 150ms ease);
}
body.ui-v2 .tb-pop-item[hidden] { display: none; }
body.ui-v2 .tb-pop-item:hover,
body.ui-v2 .ds-menu-filtro .form-check:hover { background: var(--ds-hover); }
body.ui-v2 .ds-menu-filtro .form-check .form-check-input { float: none; margin: 0; }
body.ui-v2 .tb-pop-item input[type="checkbox"],
body.ui-v2 .ds-pildora-panel input[type="checkbox"] {
    flex: none;
    width: 16px;
    height: 16px;
    margin: 0;
    accent-color: var(--ds-relleno-primario);
    cursor: pointer;
}
body.ui-v2 .tb-pop-item span:last-child {
    margin-left: auto;
    color: var(--ds-texto-2) !important;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .tb-pop-item em { color: var(--ds-texto-2); }
body.ui-v2 .tb-pop-pie {
    display: flex;
    gap: var(--ds-e4, 16px);
    margin-top: var(--ds-e2, 8px);
    padding-top: var(--ds-e2, 8px);
    border-top: 1px solid var(--ds-borde);
}
body.ui-v2 .tb-pop-pie .btn-link,
body.ui-v2 .tb:not(.tb-v2) .tb-limpiar {
    color: var(--ds-acento-oscuro);
    font-size: 13px;
    font-weight: 500;
    text-decoration: none;
}
body.ui-v2 .tb-pop-pie .btn-link:hover { text-decoration: underline; }
body.ui-v2 .tb-popover .form-control,
body.ui-v2 .ds-menu-filtro .form-control {
    height: var(--ds-alto-chip, 36px);
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-campo, 12px);
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .tb-popover .form-control:focus,
body.ui-v2 .ds-menu-filtro .form-control:focus { border-color: var(--ds-acento); box-shadow: var(--tb-anillo-campo); }
body.ui-v2 .ds-pildora-panel-buscar { margin-bottom: var(--ds-e2, 8px); }
body.ui-v2 .ds-rango { display: grid; grid-template-columns: 1fr 1fr; gap: var(--ds-e2, 8px); }
body.ui-v2 .ds-rango-campo { display: flex; flex-direction: column; gap: var(--ds-e1, 4px); margin: 0; }
body.ui-v2 .ds-rango-campo > span { color: var(--ds-texto-2); font-size: 12px; font-weight: 500; }
/* "Más filtros" */
body.ui-v2 .ds-mas-panel { min-width: 240px; }
body.ui-v2 .ds-mas-lista { display: flex; flex-direction: column; margin: 0 -4px; }
body.ui-v2 .ds-mas-item {
    display: flex;
    align-items: center;
    gap: var(--ds-e2, 8px);
    min-height: 36px;
    padding: 6px 10px;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--ds-texto);
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color var(--ds-transicion, 150ms ease);
}
body.ui-v2 .ds-mas-item:hover,
body.ui-v2 .ds-mas-item:focus-visible { background: var(--ds-hover); outline: 0; }
body.ui-v2 .ds-mas-item > .ti { margin-left: auto; color: var(--ds-texto-3); font-size: 16px; }
body.ui-v2 .ds-mas-valor {
    overflow: hidden;
    max-width: 120px;
    color: var(--ds-acento-oscuro);
    font-size: 12px;
    font-weight: 500;
    text-overflow: ellipsis;
    white-space: nowrap;
}
body.ui-v2 .ds-mas-item-activo .ds-mas-titulo { font-weight: 600; }


/* 6d-bis. Panel ESTÁNDAR de filtro y orden de TablaDatos (Paso 2, 2026-09-30) -----
   Lo abren el embudo del encabezado y las píldoras de la barra (tabla.js, _abrirFiltro):
   div.tb-popover.tb-panel[role=dialog] > .tb-pop-titulo
     · texto, categoría y lista: label.tb-panel-buscar > i.ti-search + input.tb-panel-buscar-campo (píldora) ·
       .tb-panel-acciones (.tb-panel-enlace "Seleccionar todo" / "Limpiar") · .tb-panel-aplicar-texto ·
       p.tb-panel-nota · .tb-panel-lista (role=group) > label.tb-pop-item (casilla · .tb-pop-valor ·
       .tb-pop-conteo; .tb-pop-item-libre = término "contiene") · p.tb-panel-sin
     · número y fecha: .ds-rango.tb-panel-rango + "Limpiar"
     · si ordena: .tb-panel-orden (role=group) > button.tb-panel-orden-op[aria-pressed] (.tb-panel-orden-activo)
   TODO en em sobre la letra de 13 px del panel (sin altos ni interlineados fijos en px: Safari con
   zoom bajo sube el texto a 9 px y la caja tiene que crecer con él). */
body.ui-v2 .tb-popover.tb-panel {
    min-width: 18.5em;
    max-width: min(26em, calc(100vw - 16px));
    padding: 0.9231em;
    font-size: 13px;
    line-height: 1.31;
}
body.ui-v2 .tb-panel .tb-pop-titulo { margin: 0 0 0.6154em; font-size: 1em; line-height: 1.31; }
/* buscador en píldora (38 px con letra de 13) */
body.ui-v2 .tb-panel-buscar {
    position: relative;
    display: flex;
    align-items: center;
    margin: 0 0 0.4615em;
}
body.ui-v2 .tb-panel-buscar > .ti {
    position: absolute;
    left: 0.9231em;
    color: var(--ds-texto-2);
    font-size: 1.2308em;
    pointer-events: none;
}
body.ui-v2 .tb-panel-buscar-campo {
    width: 100%;
    min-height: 2.9231em;
    margin: 0;
    padding: 0.4615em 1.0769em 0.4615em 2.7692em;
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-pildora, 999px);
    background: var(--ds-superficie);
    color: var(--ds-texto);
    font: inherit;
    font-size: 1em;
    line-height: 1.31;
    transition: border-color var(--ds-transicion, 150ms ease), box-shadow var(--ds-transicion, 150ms ease);
}
body.ui-v2 .tb-panel-buscar-campo::placeholder { color: var(--ds-texto-2); }
body.ui-v2 .tb-panel-buscar-campo:focus,
body.ui-v2 .tb-panel-buscar-campo.ds-f-foco { border-color: var(--ds-acento); box-shadow: var(--tb-anillo-campo); outline: 0; }
/* "Seleccionar todo" · "Limpiar" y los demás enlaces del panel (botones con aspecto de enlace) */
body.ui-v2 .tb-panel-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.3077em 1.2308em;
    margin: 0 0 0.3077em;
}
body.ui-v2 .tb-panel-rango + .tb-panel-acciones { margin: 0.6154em 0 0; justify-content: flex-end; }
body.ui-v2 .tb-panel-enlace {
    margin: 0;
    padding: 0.2308em 0.1538em;
    border: 0;
    border-radius: var(--ds-radio-item, 8px);
    background: none;
    color: var(--ds-acento-oscuro);
    font: inherit;
    font-weight: 500;
    line-height: 1.31;
    text-align: left;
    cursor: pointer;
}
body.ui-v2 .tb-panel-enlace:hover,
body.ui-v2 .tb-panel-enlace.ds-f-hover { text-decoration: underline; }
body.ui-v2 .tb-panel-enlace:focus-visible,
body.ui-v2 .tb-panel-enlace.ds-f-foco { outline: 0; box-shadow: var(--tb-anillo); }
body.ui-v2 .tb-panel-aplicar-texto { display: block; max-width: 100%; margin: 0 0 0.3077em; overflow-wrap: anywhere; }
body.ui-v2 .tb-panel-aplicar-texto[hidden] { display: none; }
body.ui-v2 .tb-panel-nota,
body.ui-v2 .tb-panel-sin {
    margin: 0 0 0.3077em;
    color: var(--ds-texto-2);
    font-size: 0.9231em;
    line-height: 1.33;
}
body.ui-v2 :is(.tb-panel-nota, .tb-panel-sin)[hidden] { display: none; }
/* lista de valores con desplazamiento propio */
body.ui-v2 .tb-panel .tb-panel-lista {
    max-height: min(21.5em, 45vh);
    margin: 0 -0.3077em;
    overflow-y: auto;
    overscroll-behavior: contain;
}
body.ui-v2 .tb-panel .tb-pop-item {
    align-items: flex-start;
    gap: 0.7692em;
    min-height: 2.6154em;
    padding: 0.4615em 0.6154em;
    border-radius: 0.7692em;
    line-height: 1.31;
}
body.ui-v2 .tb-panel .tb-pop-item input[type="checkbox"] { width: 1.2308em; height: 1.2308em; margin-top: 0.0385em; }
body.ui-v2 .tb-panel .tb-pop-item input[type="checkbox"]:focus-visible { outline: 0; box-shadow: var(--tb-anillo); }
body.ui-v2 .tb-panel .tb-pop-item:focus-within { background: var(--ds-hover); }
body.ui-v2 .tb-panel .tb-pop-valor { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
body.ui-v2 .tb-panel .tb-pop-item .tb-pop-conteo {
    flex: none;
    margin-left: auto;
    padding-left: 0.3077em;
    font-size: 0.9231em;
    line-height: 1.42;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .tb-panel .tb-pop-item-libre .tb-pop-valor { color: var(--ds-acento-oscuro); font-weight: 500; }
/* rango: campos de 36 px con letra de 13, medidos en em */
body.ui-v2 .tb-panel .form-control { height: auto; min-height: 2.7692em; padding: 0.3846em 0.7692em; font-size: 1em; line-height: 1.31; }
body.ui-v2 .tb-panel .ds-rango-campo > span { font-size: 0.9231em; line-height: 1.33; }
/* orden: Ascendente / Descendente */
body.ui-v2 .tb-panel-orden {
    display: flex;
    flex-direction: column;
    gap: 0.1538em;
    margin: 0.6154em -0.3077em 0;
    padding-top: 0.6154em;
    border-top: 1px solid var(--ds-borde);
}
body.ui-v2 .tb-panel-subtitulo { margin: 0 0.6154em 0.1538em; color: var(--ds-texto-2); font-size: 0.9231em; font-weight: 600; line-height: 1.33; }
body.ui-v2 .tb-panel-orden-op {
    display: flex;
    align-items: center;
    gap: 0.6154em;
    width: 100%;
    min-height: 2.6154em;
    margin: 0;
    padding: 0.3846em 0.6154em;
    border: 0;
    border-radius: 0.7692em;
    background: transparent;
    color: var(--ds-texto);
    font: inherit;
    line-height: 1.31;
    text-align: left;
    cursor: pointer;
    transition: background-color var(--ds-transicion, 150ms ease);
}
body.ui-v2 .tb-panel-orden-op > .ti { flex: none; color: var(--ds-texto-2); font-size: 1.2308em; }
body.ui-v2 .tb-panel-orden-op:hover,
body.ui-v2 .tb-panel-orden-op.ds-f-hover { background: var(--ds-hover); }
body.ui-v2 .tb-panel-orden-op:focus-visible,
body.ui-v2 .tb-panel-orden-op.ds-f-foco { outline: 0; box-shadow: var(--tb-anillo); }
body.ui-v2 .tb-panel-orden-op.tb-panel-orden-activo { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); font-weight: 600; }
body.ui-v2 .tb-panel-orden-op.tb-panel-orden-activo > .ti { color: var(--ds-acento-oscuro); }
body.ui-v2 .tb-panel-orden-marca { margin-left: auto; visibility: hidden; }
body.ui-v2 .tb-panel-orden-activo > .tb-panel-orden-marca { visibility: visible; }
/* /estilo §18: el panel de muestra va dentro de la página, sin flotar */
body.ui-v2 .tb-popover.tb-panel.tb-panel-muestra { position: static; z-index: auto; display: inline-block; vertical-align: top; }


/* 6e. Quitar filtros, contador, densidad ---------------------------------- */
body.ui-v2 .ds-quitar-filtros {
    display: inline-flex;
    align-items: center;
    height: var(--ds-alto-chip, 36px);
    padding: 0 10px;
    border: 0;
    border-radius: var(--ds-radio-pildora, 999px);
    background: transparent;
    color: var(--ds-acento-oscuro);
    font-family: var(--ds-fuente, "Inter", system-ui, sans-serif);
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--ds-transicion, 150ms ease);
}
body.ui-v2 .ds-quitar-filtros:hover,
body.ui-v2 .ds-quitar-filtros.ds-f-hover { background: var(--ds-acento-claro); }
body.ui-v2 .ds-quitar-filtros:focus-visible,
body.ui-v2 .ds-quitar-filtros.ds-f-foco { outline: 0; box-shadow: var(--tb-anillo); }
/* En la barra de TablaDatos el espacio de "Quitar filtros" queda reservado
   (invisible y fuera del teclado) para que la barra no salte al filtrar. */
body.ui-v2 .tb-barra-fin > .ds-quitar-filtros[hidden] { display: inline-flex !important; visibility: hidden; }
body.ui-v2 .ds-quitar-filtros:disabled,
body.ui-v2 .ds-quitar-filtros[aria-disabled="true"] { color: var(--ds-texto-3); background: transparent; cursor: not-allowed; }
body.ui-v2 .tb-contador {
    color: var(--ds-texto-2) !important;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
body.ui-v2 .tb-contador:empty { display: none; }
body.ui-v2 .tb-densidad {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    height: var(--ds-alto-chip, 36px);
    padding: 2px;
    border: 1px solid var(--ds-borde-fuerte);   /* Corrección 2: borde de control (3:1) */
    border-radius: var(--ds-radio-pildora, 999px);
    background: var(--tb-pildora-fondo);
}
body.ui-v2 .tb-densidad-op {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 34px;
    height: 30px;
    padding: 0;
    border: 0;
    border-radius: var(--ds-radio-pildora, 999px);
    background: transparent;
    color: var(--ds-neutro);   /* sobre el gris de la píldora: 6.75:1 (texto-2 daba 4.3:1) */
    font-family: var(--ds-fuente, "Inter", system-ui, sans-serif);
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: background-color var(--ds-transicion, 150ms ease), color var(--ds-transicion, 150ms ease), box-shadow var(--ds-transicion, 150ms ease);
}
body.ui-v2 .tb-densidad-op > .ti { font-size: 16px; }
body.ui-v2 .tb-densidad-op:hover,
body.ui-v2 .tb-densidad-op.ds-f-hover { color: var(--ds-texto); }
body.ui-v2 .tb-densidad-op[aria-pressed="true"],
body.ui-v2 .tb-densidad-op.ds-f-activo {
    background: var(--ds-superficie);
    color: var(--ds-texto);
    box-shadow: var(--ds-sombra-control);
}
body.ui-v2 .tb-densidad-op:focus-visible,
body.ui-v2 .tb-densidad-op.ds-f-foco { outline: 0; box-shadow: var(--tb-anillo); }
/* etiquetas viejas de filtros activos (tablas sin barra; también abastecimiento.js) */
body.ui-v2 .tb-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: 28px;
    padding: 0 8px 0 12px;
    border: 0;
    border-radius: var(--ds-radio-pildora, 999px);
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
    font-size: 12px;
    font-weight: 500;
    line-height: 1;
    transition: background-color var(--ds-transicion, 150ms ease);
}
body.ui-v2 .tb-chip:hover { background: var(--ds-acento-claro-2); }


/* 7. Píldoras de estado =================================================== */
/* Suaves: fondo de estado + texto de estado, 12/500, totalmente redondas.
   Tonos: exito | aviso | error | info | neutro (y los nombres viejos
   verde | ambar | roja | azul | gris).
   UNA sola medida en toda la app (Paso 3, "Tablas parejas", 2026-09-30):
   18 px de alto (1.5em con 12 px: línea de 16 + 1 px arriba y abajo) y 8 px a
   los lados, en em para que crezca si Safari agranda el texto. Ninguna
   variante (-sm, -mini, la del número del NOG, la de una celda de dos líneas)
   cambia el alto ni el relleno: solo el color o el ancho. Cabe en la línea de
   una celda de dos líneas (17 px; la píldora la desborda medio píxel sin
   agrandar la fila). En una SEGUNDA línea gris (16 px) no va una píldora: va
   texto con color (.ds-celda-alerta, §23l). */
body.ui-v2 .ds-pildora,
body.ui-v2 .ui-pildora {
    display: inline-flex;
    align-items: center;
    gap: 0.3334em;
    min-height: 1.5em;           /* mínimo: crece si el navegador agranda el texto */
    padding: 0.0834em 0.6667em;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-neutro-fondo);
    color: var(--ds-neutro);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 500;
    line-height: 1.33334;
    letter-spacing: 0;
    text-transform: none;
    white-space: nowrap;
    vertical-align: middle;
}
body.ui-v2 .ds-pildora > .ti,
body.ui-v2 .ds-pildora > .bi { font-size: 14px; margin-left: -2px; }
body.ui-v2 .ds-pildora.con-punto::before {
    content: "";
    flex: none;
    width: 6px;
    height: 6px;
    margin-left: -1px;
    border-radius: 50%;
    background: currentColor;
}
/* .ds-pildora-sm y .ds-pildora-mini: nombres de antes, hoy la MISMA medida (no se dibujan distinto) */
body.ui-v2 .ds-pildora-exito,  body.ui-v2 .ds-pildora-verde, body.ui-v2 .ui-pildora-verde { background: var(--ds-exito-fondo);  color: var(--ds-exito); }
body.ui-v2 .ds-pildora-aviso,  body.ui-v2 .ds-pildora-ambar, body.ui-v2 .ui-pildora-ambar { background: var(--ds-aviso-fondo);  color: var(--ds-aviso); }
body.ui-v2 .ds-pildora-error,  body.ui-v2 .ds-pildora-roja,  body.ui-v2 .ui-pildora-roja  { background: var(--ds-error-fondo);  color: var(--ds-error); }
body.ui-v2 .ds-pildora-info,   body.ui-v2 .ds-pildora-azul,  body.ui-v2 .ui-pildora-azul  { background: var(--ds-info-fondo);   color: var(--ds-info); }
body.ui-v2 .ds-pildora-neutro, body.ui-v2 .ds-pildora-gris,  body.ui-v2 .ui-pildora-gris  { background: var(--ds-neutro-fondo); color: var(--ds-neutro); }
/* .badge de Bootstrap que arma .ui-pildora: sin mayúsculas ni negrita */
body.ui-v2 .badge.ui-pildora { font-weight: 500; }


/* 8. Avisos en línea ====================================================== */
/* Una línea, fondo de estado suave, ícono del color del estado. Para
   mensajes de éxito use UI.estado (aviso flotante), no una franja. */
body.ui-v2 .ds-aviso {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 0 0 var(--ds-e4);
    padding: 10px 14px;
    border: 0;
    border-radius: var(--ds-radio-campo);
    background: var(--ds-info-fondo);
    color: var(--ds-texto);
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.42858;
}
body.ui-v2 .ds-aviso-icono { flex: none; display: inline-flex; font-size: 20px; line-height: 1; color: var(--ds-info); }
body.ui-v2 .ds-aviso-cuerpo { flex: 1 1 auto; min-width: 0; }
body.ui-v2 .ds-aviso-titulo { margin: 0; font-size: var(--ds-tam-cuerpo); font-weight: 600; }
body.ui-v2 .ds-aviso-cuerpo > :last-child { margin-bottom: 0; }
body.ui-v2 .ds-aviso-exito { background: var(--ds-exito-fondo); }
body.ui-v2 .ds-aviso-exito .ds-aviso-icono { color: var(--ds-exito); }
body.ui-v2 .ds-aviso-aviso,
body.ui-v2 .ds-aviso-alerta { background: var(--ds-aviso-fondo); }
body.ui-v2 .ds-aviso-aviso .ds-aviso-icono,
body.ui-v2 .ds-aviso-alerta .ds-aviso-icono { color: var(--ds-aviso); }
body.ui-v2 .ds-aviso-error,
body.ui-v2 .ds-aviso-peligro { background: var(--ds-error-fondo); }
body.ui-v2 .ds-aviso-error .ds-aviso-icono,
body.ui-v2 .ds-aviso-peligro .ds-aviso-icono { color: var(--ds-error); }
body.ui-v2 .ds-aviso-neutro { background: var(--ds-neutro-fondo); }
body.ui-v2 .ds-aviso-neutro .ds-aviso-icono { color: var(--ds-neutro); }
/* Aviso de <noscript> (mensajes flash sin JavaScript) */
body.ui-v2 p.ds-aviso { margin: 0; }


/* 9. Tarjetas de indicadores (KPI) ======================================== */
/* Superficie blanca, radio 16, borde fino, sombra casi invisible; sin
   bandas de color. El tono solo tiñe el ícono. */
body.ui-v2 .ds-kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: var(--ds-e4);
    margin-bottom: var(--ds-e5);
}
body.ui-v2 .ds-kpi {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
    padding: var(--ds-e4) 20px;
    background: var(--ds-superficie);
    border: 1px solid var(--ds-borde-marco);
    border-radius: var(--ds-radio-tarjeta);
    box-shadow: var(--ds-sombra-tarjeta);
}
body.ui-v2 .ds-kpi-etiqueta {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    font-weight: 500;
}
body.ui-v2 .ds-kpi-icono {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
    font-size: 18px;
    line-height: 1;
}
body.ui-v2 .ds-kpi-valor {
    color: var(--ds-texto);
    font-size: var(--ds-tam-titulo);
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.23077;
    overflow-wrap: anywhere;
}
body.ui-v2 .ds-kpi-detalle { color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-kpi-exito .ds-kpi-icono, body.ui-v2 .ds-kpi-verde .ds-kpi-icono { background: var(--ds-exito-fondo); color: var(--ds-exito); }
body.ui-v2 .ds-kpi-aviso .ds-kpi-icono, body.ui-v2 .ds-kpi-ambar .ds-kpi-icono { background: var(--ds-aviso-fondo); color: var(--ds-aviso); }
body.ui-v2 .ds-kpi-error .ds-kpi-icono, body.ui-v2 .ds-kpi-roja .ds-kpi-icono  { background: var(--ds-error-fondo); color: var(--ds-error); }
body.ui-v2 .ds-kpi-neutro .ds-kpi-icono { background: var(--ds-neutro-fondo); color: var(--ds-neutro); }
body.ui-v2 a.ds-kpi {
    color: inherit;
    text-decoration: none;
    transition: border-color var(--ds-transicion), box-shadow var(--ds-transicion);
}
body.ui-v2 a.ds-kpi:hover,
body.ui-v2 .ds-kpi.ds-f-hover { border-color: var(--ds-borde-fuerte); box-shadow: var(--ds-sombra-flotante); }
body.ui-v2 a.ds-kpi.activo,
body.ui-v2 a.ds-kpi[aria-current],
body.ui-v2 .ds-kpi.ds-f-activo { border-color: var(--ds-acento); box-shadow: 0 0 0 1px var(--ds-acento); }


/* 10. Paneles y tarjetas ================================================== */
/* Filas con línea arriba (.row.border-top, p. ej. las filas de estados de
   /estilo): con medianil vertical (g-3) Bootstrap subía la línea 16 px sobre
   la fila (el texto quedaba pegado a la línea de abajo) y la sacaba 8 px del
   contenido por cada lado. La línea se dibuja con el ancho del contenido y
   el espacio entre columnas que bajan de renglón pasa a row-gap. */
body.ui-v2 .row.border-top {
    margin-top: 0;
    row-gap: var(--bs-gutter-y);
    border-top-color: transparent !important;
    background: linear-gradient(var(--ds-borde), var(--ds-borde)) no-repeat center top / calc(100% - var(--bs-gutter-x)) 1px;
    background-origin: border-box;
}
body.ui-v2 .row.border-top > * { margin-top: 0; }
body.ui-v2 .card {
    --bs-card-border-color: var(--ds-borde);
    --bs-card-border-radius: var(--ds-radio-tarjeta);
    --bs-card-inner-border-radius: calc(var(--ds-radio-tarjeta) - 1px);
    --bs-card-cap-bg: var(--ds-superficie);
    --bs-card-cap-padding-y: 14px;
    --bs-card-cap-padding-x: 20px;
    --bs-card-spacer-y: 20px;
    --bs-card-spacer-x: 20px;
    --bs-card-bg: var(--ds-superficie);
    box-shadow: var(--ds-sombra-tarjeta);
}
body.ui-v2 .card-header { font-weight: 600; }
body.ui-v2 .ds-panel,
body.ui-v2 .ui-panel {
    margin-bottom: var(--ds-e5);
    background: var(--ds-superficie);
    border: 1px solid var(--ds-borde-marco);
    border-radius: var(--ds-radio-tarjeta);
    box-shadow: var(--ds-sombra-tarjeta);
}
body.ui-v2 .ds-panel-cuerpo { padding: 20px; }
body.ui-v2 .ui-panel-borde-falta { border-color: var(--ds-aviso-borde); box-shadow: var(--ds-sombra-tarjeta); }
body.ui-v2 .ui-panel-borde-ok { border-color: var(--ds-exito-borde); }
/* La banda deja de ser azul marino: cabecera clara con línea fina */
body.ui-v2 .ds-panel-cabeza,
body.ui-v2 .ui-panel-banda,
body.ui-v2 .ui-panel-banda-navy,
body.ui-v2 .ui-panel-banda-navy-claro {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 56px;
    padding: 12px 20px;
    background: var(--ds-superficie);
    color: var(--ds-texto);
    border-bottom: 1px solid var(--ds-borde);
    border-radius: calc(var(--ds-radio-tarjeta) - 1px) calc(var(--ds-radio-tarjeta) - 1px) 0 0;
}
body.ui-v2 .ui-panel-numero {
    display: inline-grid;
    place-items: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 600;
}
body.ui-v2 .ui-panel-icono { color: var(--ds-texto-2); }
body.ui-v2 .ds-panel-titulo,
body.ui-v2 .ui-panel-titulo {
    margin: 0;
    color: var(--ds-texto);
    font-size: var(--ds-tam-seccion);
    font-weight: 600;
    letter-spacing: -0.006em;
}
/* Etiqueta de estado de la banda: ahora sobre fondo claro */
body.ui-v2 .ui-etiqueta {
    display: inline-flex;
    align-items: center;
    min-height: 22px;
    padding: 0 10px;
    border-radius: var(--ds-radio-pildora);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 500;
    line-height: 1;
}
body.ui-v2 .ui-etiqueta-neutra { background: var(--ds-neutro-fondo); color: var(--ds-neutro); }
body.ui-v2 .ui-etiqueta-ok { background: var(--ds-exito-fondo); color: var(--ds-exito); font-weight: 500; }
body.ui-v2 .ui-etiqueta-falta { background: var(--ds-aviso-fondo); color: var(--ds-aviso); font-weight: 500; }


/* 11. Formularios ========================================================= */
/* Campos de 40 px, radio 12, borde gris claro; foco con borde acento y
   anillo suave. Rótulos 12/500. */
body.ui-v2 .form-label,
body.ui-v2 .ui-rotulo,
body.ui-v2 .ds-rotulo {
    display: block;
    margin-bottom: 6px;
    color: var(--ds-texto);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 500;
    line-height: 1.33334;
    text-transform: none;
    letter-spacing: 0;
}
body.ui-v2 .ds-rotulo-opcional { color: var(--ds-texto-2); font-weight: 400; }
body.ui-v2 .ds-campo { margin-bottom: var(--ds-e4); }
body.ui-v2 .form-control,
body.ui-v2 .form-select,
body.ui-v2 .ds-control {
    min-height: var(--ds-alto-control);
    padding: 9px 14px;
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-campo);
    background-color: var(--ds-superficie);
    color: var(--ds-texto);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.42858;
    transition: border-color var(--ds-transicion), box-shadow var(--ds-transicion), background-color var(--ds-transicion);
}
body.ui-v2 textarea.form-control { min-height: 88px; }
body.ui-v2 .form-select { padding-right: 40px; background-position: right 14px center; }
body.ui-v2 .form-control-sm,
body.ui-v2 .form-select-sm {
    min-height: 32px;
    padding-top: 5px;
    padding-bottom: 5px;
    font-size: var(--ds-tam-tabla);
    line-height: 1.53847;
    border-radius: 10px;
}
body.ui-v2 .form-control-lg,
body.ui-v2 .form-select-lg { min-height: 44px; font-size: 15px; border-radius: var(--ds-radio-campo); }
body.ui-v2 .form-control::placeholder { color: var(--ds-texto-2); opacity: 1; }
body.ui-v2 .form-control:hover:not(:disabled):not(:focus):not([readonly]),
body.ui-v2 .form-select:hover:not(:disabled):not(:focus),
body.ui-v2 .form-control.ds-f-hover,
body.ui-v2 .form-select.ds-f-hover { border-color: var(--ds-borde-hover); }
body.ui-v2 .form-control:focus,
body.ui-v2 .form-select:focus,
body.ui-v2 .ui-campo:focus,
body.ui-v2 .form-control.ds-f-foco,
body.ui-v2 .form-select.ds-f-foco {
    outline: none;
    border-color: var(--ds-acento);
    box-shadow: 0 0 0 3px var(--ds-anillo);
}
body.ui-v2 .form-control:disabled,
body.ui-v2 .form-select:disabled {
    background-color: var(--ds-neutro-fondo);
    border-color: var(--ds-borde);
    color: var(--ds-texto-3);
    cursor: not-allowed;
}
body.ui-v2 .form-control[readonly] { background-color: var(--ds-fondo); border-color: var(--ds-borde); color: var(--ds-texto-2); }
body.ui-v2 .form-control-plaintext { min-height: var(--ds-alto-control); padding: 9px 0; line-height: 1.42858; color: var(--ds-texto); }
body.ui-v2 .form-text,
body.ui-v2 .ds-ayuda-texto { margin-top: 6px; color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); line-height: 1.33334; }
/* Error */
body.ui-v2 .form-control.is-invalid,
body.ui-v2 .form-select.is-invalid,
body.ui-v2 .ds-campo-error .form-control,
body.ui-v2 .ds-campo-error .form-select { border-color: var(--ds-error); background-image: none; padding-right: 14px; }
body.ui-v2 .form-select.is-invalid { padding-right: 40px; }
body.ui-v2 .form-control.is-invalid:focus,
body.ui-v2 .form-select.is-invalid:focus,
body.ui-v2 .ds-campo-error .form-control:focus { box-shadow: 0 0 0 3px var(--ds-error-anillo); }
body.ui-v2 .invalid-feedback,
body.ui-v2 .ds-error-texto {
    margin-top: 6px;
    color: var(--ds-error);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.33334;
}
body.ui-v2 .ds-error-texto::before { content: "\ea05"; font-family: "tabler-icons-outline"; margin-right: 4px; vertical-align: -2px; font-size: 14px; }
/* Campo "falta" viejo: ámbar suave */
body.ui-v2 .ui-campo-falta { border-color: var(--ds-aviso-borde-2); background-color: var(--ds-aviso-tenue); }
body.ui-v2 .ui-campo-falta:focus { border-color: var(--ds-aviso-punto); box-shadow: 0 0 0 3px var(--ds-aviso-anillo); }
/* Casilla, radio e interruptor */
body.ui-v2 .form-check { min-height: 20px; }
body.ui-v2 .form-check-input {
    width: 18px;
    height: 18px;
    margin-top: 1px;
    border: 1.5px solid var(--ds-borde-hover);
    background-color: var(--ds-superficie);
    cursor: pointer;
    transition: background-color var(--ds-transicion), border-color var(--ds-transicion), box-shadow var(--ds-transicion);
}
body.ui-v2 .form-check .form-check-input { margin-left: -1.6em; }
body.ui-v2 .form-check-input[type="checkbox"] { border-radius: 6px; }
body.ui-v2 .form-check-input:hover:not(:disabled):not(:checked),
body.ui-v2 .form-check-input.ds-f-hover { border-color: var(--ds-acento); }
body.ui-v2 .form-check-input:checked,
body.ui-v2 .form-check-input[type="checkbox"]:indeterminate {
    background-color: var(--ds-relleno-primario);
    border-color: var(--ds-relleno-primario);
}
body.ui-v2 .form-check-input:focus,
body.ui-v2 .form-check-input.ds-f-foco {
    border-color: var(--ds-acento);
    box-shadow: 0 0 0 3px var(--ds-anillo);
}
body.ui-v2 .form-check-input:disabled { background-color: var(--ds-neutro-fondo); border-color: var(--ds-borde-fuerte); opacity: 1; cursor: not-allowed; }
body.ui-v2 .form-check-input:disabled:checked { background-color: var(--ds-borde-hover); border-color: var(--ds-borde-hover); }
body.ui-v2 .form-switch .form-check-input {
    width: 34px;
    height: 20px;
    margin-top: 0;
    border-radius: var(--ds-radio-pildora);
    background-color: var(--ds-borde-fuerte);
    border-color: var(--ds-borde-fuerte);
    --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
}
body.ui-v2 .form-switch .form-check-input:focus { --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e"); }
body.ui-v2 .form-switch .form-check-input:checked { background-color: var(--ds-relleno-primario); border-color: var(--ds-relleno-primario); }
body.ui-v2 .form-switch { padding-left: 2.9em; }
body.ui-v2 .form-switch .form-check-input { margin-left: -2.9em; }
body.ui-v2 .form-check-label { color: var(--ds-texto); cursor: pointer; }
body.ui-v2 .form-check-input:disabled ~ .form-check-label { color: var(--ds-texto-3); opacity: 1; cursor: not-allowed; }
body.ui-v2 .input-group-text {
    border-color: var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-campo);
    background: var(--ds-neutro-fondo);
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
}
body.ui-v2 .input-group > .form-control:not(:last-child),
body.ui-v2 .input-group > .form-select:not(:last-child),
body.ui-v2 .input-group > .input-group-text:not(:last-child) { border-top-right-radius: 0; border-bottom-right-radius: 0; }
body.ui-v2 .input-group > :not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; }
body.ui-v2 .input-group > .btn { border-radius: var(--ds-radio-campo); }
body.ui-v2 .input-group > .btn:not(:last-child) { border-top-right-radius: 0; border-bottom-right-radius: 0; }
body.ui-v2 .input-group > .btn:not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; }
/* Grupo de opciones segmentadas (reemplaza .ab-segmento; p. ej. Cómoda /
   Compacta). Contenedor en píldora gris; la opción activa en blanco. */
body.ui-v2 .ds-segmento {
    display: inline-flex;
    align-items: center;
    height: var(--ds-alto-chip);
    padding: 2px;
    gap: 2px;
    border: 1px solid var(--ds-borde-fuerte);   /* Corrección 2: borde de control (3:1) */
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-control-fondo);
}
body.ui-v2 .ds-segmento > button,
body.ui-v2 .ds-segmento > a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 30px;
    padding: 0 14px;
    border: 0;
    border-radius: var(--ds-radio-pildora);
    background: transparent;
    color: var(--ds-neutro);                 /* sobre el gris del contenedor: 6.75:1 */
    font-size: var(--ds-tam-tabla);
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--ds-transicion), color var(--ds-transicion), box-shadow var(--ds-transicion);
}
body.ui-v2 .ds-segmento > button > .ti,
body.ui-v2 .ds-segmento > a > .ti { font-size: 16px; }
body.ui-v2 .ds-segmento > :hover,
body.ui-v2 .ds-segmento > .ds-f-hover { color: var(--ds-texto); }
body.ui-v2 .ds-segmento > .activo,
body.ui-v2 .ds-segmento > .ds-f-activo,
body.ui-v2 .ds-segmento > [aria-pressed="true"],
body.ui-v2 .ds-segmento > [aria-current="page"] {
    background: var(--ds-superficie);
    color: var(--ds-texto);
    box-shadow: var(--ds-sombra-segmento);
}
body.ui-v2 .ds-segmento > :disabled { color: var(--ds-texto-3); cursor: not-allowed; }

/* <select> (también la píldora select de §24a) con una opción elegida más
   larga que el campo: en WebKit el texto se salía de la caja y ensanchaba la
   PÁGINA (teléfono, 390 px: 262 px de desborde en "Editar precio"). Recortado
   dentro del campo, con "…". */
body.ui-v2 :is(.form-select, .ds-pildora-select) { overflow: hidden; text-overflow: ellipsis; }


/* 12. Pasos y zona de carga =============================================== */
/* Formularios de varios pasos (como Merkaru "Vendé tu celular"): círculos
   de 32 px con el número; hecho = relleno acento con ✓ (ti-check), actual =
   contorno acento y número acento oscuro, pendiente = gris neutro. Rótulos
   14 px. Macro: ds.pasos(["Datos", "Renglones", …], actual) — actual es el
   paso en curso, contado desde 1. */
body.ui-v2 .ds-pasos {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e3) var(--ds-e5);
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: none;
}
body.ui-v2 .ds-paso {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    color: var(--ds-texto-2);
    font-size: 14px;
    line-height: 1.42858;
    white-space: nowrap;
}
body.ui-v2 .ds-paso-marca {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 1.5px solid transparent;
    border-radius: 50%;
    background: var(--ds-neutro-fondo);
    color: var(--ds-neutro);            /* número del paso pendiente sobre gris: 6.75:1 */
    font-size: 13px;
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    transition: background-color var(--ds-transicion), border-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .ds-paso-marca > .ti { font-size: 18px; }
body.ui-v2 .ds-paso-hecho,
body.ui-v2 .ds-paso-actual { color: var(--ds-texto); }
body.ui-v2 .ds-paso-actual { font-weight: 500; }
body.ui-v2 .ds-paso-hecho .ds-paso-marca {
    border-color: var(--ds-relleno-primario);
    background: var(--ds-relleno-primario);
    color: var(--ds-texto-sobre-relleno);
}
body.ui-v2 .ds-paso-actual .ds-paso-marca {
    border-color: var(--ds-acento);
    background: var(--ds-superficie);
    color: var(--ds-acento-oscuro);
}
/* Teléfono: solo el paso actual conserva su rótulo a la vista (los demás
   quedan para lectores de pantalla) */
@media (max-width: 575.98px) {
    body.ui-v2 .ds-pasos { gap: var(--ds-e2) var(--ds-e3); }
    body.ui-v2 .ds-paso:not(.ds-paso-actual) .ds-paso-texto {
        position: absolute !important;
        width: 1px !important;
        height: 1px !important;
        padding: 0 !important;
        margin: -1px !important;
        overflow: hidden !important;
        clip: rect(0, 0, 0, 0) !important;
        white-space: nowrap !important;
        border: 0 !important;
    }
}

/* Zona de carga: mosaico de borde punteado, radio 16, ícono de línea +
   "Agregar". Es un <label> con el <input type="file"> adentro (oculto a la
   vista pero enfocable): clic, Enter o Espacio abren el selector. Al pasar
   el mouse, tinte del acento. Macro: ds.zona_carga("Agregar",
   icono="ti-photo-plus", id="…"). JS puede poner .ds-carga-sobre mientras
   se arrastra un archivo encima (se ve como activo). */
body.ui-v2 .ds-carga {
    position: relative;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 152px;
    min-height: 152px;
    max-width: 100%;
    margin: 0;
    padding: var(--ds-e4);
    border: 1.5px dashed var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-tarjeta);
    background: var(--ds-superficie);
    color: var(--ds-texto-2);
    font-size: 13px;
    font-weight: 500;
    line-height: 1.38462;
    text-align: center;
    cursor: pointer;
    user-select: none;
    transition: background-color var(--ds-transicion), border-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .ds-carga-ancha { width: 100%; min-height: 120px; }
body.ui-v2 .ds-carga-icono { display: inline-flex; font-size: 24px; line-height: 1; }
body.ui-v2 .ds-carga-texto { max-width: 100%; overflow-wrap: anywhere; }
body.ui-v2 .ds-carga-input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
    opacity: 0;
}
body.ui-v2 .ds-carga:hover,
body.ui-v2 .ds-carga.ds-f-hover {
    border-color: var(--ds-acento);
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
}
body.ui-v2 .ds-carga:active,
body.ui-v2 .ds-carga.ds-carga-sobre,
body.ui-v2 .ds-carga.ds-f-activo {
    border-style: solid;
    border-color: var(--ds-acento);
    background: color-mix(in srgb, var(--ds-acento) 16%, var(--ds-superficie));
    color: var(--ds-acento-oscuro);
}
body.ui-v2 .ds-carga:has(> .ds-carga-input:focus-visible),
body.ui-v2 .ds-carga.ds-f-foco {
    border-color: var(--ds-acento);
    outline: 2px solid var(--ds-acento-oscuro);
    outline-offset: 2px;
}
body.ui-v2 .ds-carga.disabled,
body.ui-v2 .ds-carga[aria-disabled="true"],
body.ui-v2 .ds-carga:has(> .ds-carga-input:disabled) {
    border-style: dashed;
    border-color: var(--ds-borde);
    background: var(--ds-neutro-fondo);
    color: var(--ds-texto-3);
    cursor: not-allowed;
    outline: 0;
}


/* 13. Ícono de información (i) ============================================ */
/* Junto a un rótulo (fila de tabla, KPI, campo): ti-info-circle de 16 px
   que muestra una ayuda corta en un tooltip al pasar el mouse o al llegar
   con el teclado (Bootstrap Tooltip; sin JS queda el title nativo).
   Macro: ds.icono_info("Texto corto."). */
body.ui-v2 .ds-info {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin: -3px 0 -3px 2px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--ds-texto-2);
    font-size: 16px;
    line-height: 1;
    vertical-align: middle;
    cursor: help;
    transition: background-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .ds-info > .ti { font-size: 16px; line-height: 1; }
body.ui-v2 .ds-info:hover,
body.ui-v2 .ds-info.ds-f-hover,
body.ui-v2 .ds-info[aria-describedby] {
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
}
body.ui-v2 .ds-info:focus-visible,
body.ui-v2 .ds-info.ds-f-foco {
    outline: 2px solid var(--ds-acento-oscuro);
    outline-offset: 1px;
    color: var(--ds-acento-oscuro);
}


/* 14. Bootstrap dentro del ámbito ========================================= */
/* Menús desplegables */
body.ui-v2 .dropdown-menu {
    --bs-dropdown-font-size: var(--ds-tam-cuerpo);
    --bs-dropdown-color: var(--ds-texto);
    --bs-dropdown-bg: var(--ds-superficie);
    --bs-dropdown-border-color: var(--ds-borde);
    --bs-dropdown-border-radius: var(--ds-radio-campo);
    --bs-dropdown-inner-border-radius: calc(var(--ds-radio-campo) - 1px);
    --bs-dropdown-box-shadow: var(--ds-sombra-menu);
    --bs-dropdown-min-width: 200px;
    --bs-dropdown-padding-x: 6px;
    --bs-dropdown-padding-y: 6px;
    --bs-dropdown-spacer: 6px;
    --bs-dropdown-item-padding-x: 10px;
    --bs-dropdown-item-padding-y: 8px;
    --bs-dropdown-item-border-radius: var(--ds-radio-item);
    --bs-dropdown-link-color: var(--ds-texto);
    --bs-dropdown-link-hover-color: var(--ds-texto);
    --bs-dropdown-link-hover-bg: var(--ds-hover);
    --bs-dropdown-link-active-color: var(--ds-acento-oscuro);
    --bs-dropdown-link-active-bg: var(--ds-acento-claro);
    --bs-dropdown-link-disabled-color: var(--ds-texto-3);
    --bs-dropdown-header-color: var(--ds-texto-2);
    --bs-dropdown-header-padding-x: 10px;
    --bs-dropdown-header-padding-y: 6px;
    --bs-dropdown-divider-bg: var(--ds-borde);
    --bs-dropdown-divider-margin-y: 6px;
    box-shadow: var(--bs-dropdown-box-shadow);
}
body.ui-v2 .dropdown-menu.show { animation: ds-aparecer 150ms ease-out; }
body.ui-v2 .dropdown-item {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 36px;
    border-radius: var(--ds-radio-item);
    line-height: 1.42858;
    transition: background-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .dropdown-item > .ti,
body.ui-v2 .dropdown-item > .bi { flex: none; width: 18px; font-size: 18px; line-height: 1; color: var(--ds-texto-2); text-align: center; }
body.ui-v2 .dropdown-item.ds-f-hover { background: var(--ds-hover); }
body.ui-v2 .dropdown-item.active,
body.ui-v2 .dropdown-item.ds-f-activo { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); font-weight: 500; }
body.ui-v2 .dropdown-item.active > .ti,
body.ui-v2 .dropdown-item.active > .bi { color: var(--ds-acento-oscuro); }
body.ui-v2 .dropdown-item:focus-visible { outline: 2px solid var(--ds-acento-oscuro); outline-offset: -2px; }
body.ui-v2 .dropdown-item.disabled,
body.ui-v2 .dropdown-item:disabled { color: var(--ds-texto-3); }
body.ui-v2 .dropdown-item.disabled > .ti,
body.ui-v2 .dropdown-item:disabled > .ti { color: var(--ds-texto-3); }
body.ui-v2 .dropdown-header { font-size: var(--ds-tam-etiqueta); font-weight: 500; text-transform: none; }
body.ui-v2 .dropdown-item.ds-item-peligro,
body.ui-v2 .dropdown-item.ds-item-peligro > .ti,
body.ui-v2 .dropdown-item.ds-item-peligro > .bi,
body.ui-v2 .dropdown-item.text-danger > .bi,
body.ui-v2 .dropdown-item.text-danger > .ti { color: var(--ds-error); }
body.ui-v2 .dropdown-item.ds-item-peligro:hover,
body.ui-v2 .dropdown-item.ds-item-peligro:focus { background: var(--ds-error-fondo); color: var(--ds-error); }
body.ui-v2 .dropdown-toggle::after {
    content: "\ea5f";
    width: auto;
    height: auto;
    margin-left: 2px;
    border: 0;
    font-family: "tabler-icons-outline";
    font-size: 16px;
    line-height: 1;
    vertical-align: -3px;
}
body.ui-v2 .dropdown-toggle.ds-sin-flecha::after { display: none; }
/* Pestañas: subrayado del acento */
body.ui-v2 .nav-tabs {
    --bs-nav-tabs-border-color: var(--ds-borde);
    --bs-nav-tabs-border-width: 1px;
    --bs-nav-tabs-border-radius: 0;
    --bs-nav-tabs-link-hover-border-color: transparent;
    --bs-nav-tabs-link-active-color: var(--ds-acento-oscuro);
    --bs-nav-tabs-link-active-bg: transparent;
    --bs-nav-tabs-link-active-border-color: transparent;
    gap: var(--ds-e5);
    margin-bottom: var(--ds-e4);
}
body.ui-v2 .nav-tabs .nav-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 10px 2px;
    border: 0;
    border-bottom: 2px solid transparent;
    color: var(--ds-texto-2);
    font-weight: 500;
    margin-bottom: -1px;
    transition: color var(--ds-transicion), border-color var(--ds-transicion);
}
body.ui-v2 .nav-tabs .nav-link:hover,
body.ui-v2 .nav-tabs .nav-link.ds-f-hover { color: var(--ds-texto); border-bottom-color: var(--ds-borde-fuerte); }
body.ui-v2 .nav-tabs .nav-link.active,
body.ui-v2 .nav-tabs .nav-link.ds-f-activo,
body.ui-v2 .nav-tabs .nav-item.show .nav-link {
    color: var(--ds-acento-oscuro);
    border-bottom-color: var(--ds-acento);
    background: transparent;
}
body.ui-v2 .nav-tabs .nav-link.disabled,
body.ui-v2 .nav-tabs .nav-link:disabled { color: var(--ds-texto-3); }
/* Píldoras de navegación */
body.ui-v2 .nav-pills {
    --bs-nav-pills-border-radius: var(--ds-radio-pildora);
    --bs-nav-pills-link-active-color: var(--ds-acento-oscuro);
    --bs-nav-pills-link-active-bg: var(--ds-acento-claro);
    gap: 4px;
}
body.ui-v2 .nav-pills .nav-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: var(--ds-alto-chip);
    padding: 0 16px;
    color: var(--ds-texto-2);
    font-weight: 500;
    transition: background-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .nav-pills .nav-link:hover,
body.ui-v2 .nav-pills .nav-link.ds-f-hover { color: var(--ds-texto); background: var(--ds-hover); }
body.ui-v2 .nav-pills .nav-link.active,
body.ui-v2 .nav-pills .nav-link.ds-f-activo { color: var(--ds-acento-oscuro); background: var(--ds-acento-claro); }
/* Paginación: círculos; la página actual en acento claro */
body.ui-v2 .pagination {
    --bs-pagination-padding-x: 0;
    --bs-pagination-padding-y: 0;
    --bs-pagination-font-size: var(--ds-tam-tabla);
    --bs-pagination-color: var(--ds-texto);
    --bs-pagination-bg: transparent;
    --bs-pagination-border-width: 0;
    --bs-pagination-border-radius: var(--ds-radio-pildora);
    --bs-pagination-hover-color: var(--ds-texto);
    --bs-pagination-hover-bg: var(--ds-hover);
    --bs-pagination-focus-color: var(--ds-texto);
    --bs-pagination-focus-bg: var(--ds-hover);
    --bs-pagination-focus-box-shadow: 0 0 0 3px var(--ds-anillo);
    --bs-pagination-active-color: var(--ds-acento-oscuro);
    --bs-pagination-active-bg: var(--ds-acento-claro);
    --bs-pagination-active-border-color: var(--ds-acento-claro);
    --bs-pagination-disabled-color: var(--ds-texto-3);
    --bs-pagination-disabled-bg: transparent;
    gap: 4px;
    margin: 0;
}
body.ui-v2 .page-link {
    display: inline-grid;
    place-items: center;
    min-width: 32px;
    height: 32px;
    padding: 0 8px;
    border-radius: var(--ds-radio-pildora) !important;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    transition: background-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .page-item.active .page-link { font-weight: 600; }
/* Modal: radio 20; las confirmaciones usan el tamaño pequeño (§20) */
body.ui-v2 .modal,
body.ui-v2 .ds-dialogo:not(.modal) {   /* vista fija de /estilo: mismo aspecto sin abrir el modal */
    --bs-modal-bg: var(--ds-superficie);   /* Bootstrap usa --bs-body-bg (aquí el gris de la app) */
    --bs-modal-border-color: transparent;
    --bs-modal-border-radius: var(--ds-radio-dialogo);
    --bs-modal-inner-border-radius: var(--ds-radio-dialogo);
    --bs-modal-box-shadow: var(--ds-sombra-dialogo);
    --bs-modal-padding: 24px;
    --bs-modal-header-padding: 20px 24px 4px;
    --bs-modal-header-border-width: 0;
    --bs-modal-footer-border-width: 0;
    --bs-modal-footer-gap: 8px;
    --bs-modal-title-line-height: 1.35;
    --bs-modal-sm: 420px;
}
body.ui-v2 .modal-content { box-shadow: var(--bs-modal-box-shadow); }
body.ui-v2 .modal-title { font-size: 18px; font-weight: 600; letter-spacing: -0.01em; }
body.ui-v2 .modal-body { padding-top: 12px; }
/* sin el margen de Bootstrap en los hijos, los botones se separan con gap
   (8 px): "Cancelar" y "Registrar" quedaban pegados */
body.ui-v2 .modal-footer { padding: 8px 24px 20px; gap: var(--bs-modal-footer-gap, 8px); }
body.ui-v2 .modal-footer > * { margin: 0; }
body.ui-v2 .modal-backdrop { --bs-backdrop-bg: var(--ds-velo); --bs-backdrop-opacity: 0.32; }
body.ui-v2 .modal-header.bg-dark,
body.ui-v2 .modal-header.bg-primary { background: var(--ds-superficie) !important; color: var(--ds-texto) !important; }
body.ui-v2 .btn-close {
    width: 32px;
    height: 32px;
    padding: 0;
    margin: -4px -6px -4px auto;
    border-radius: 50%;
    background-size: 12px;
    opacity: 0.55;
    transition: background-color var(--ds-transicion), opacity var(--ds-transicion);
}
body.ui-v2 .btn-close:hover { background-color: var(--ds-hover); opacity: 0.9; }
body.ui-v2 .btn-close:focus { box-shadow: 0 0 0 3px var(--ds-anillo); opacity: 0.9; }
/* Panel lateral (offcanvas a la derecha): formularios largos. Flotante,
   separado 12 px del borde, radio 20; pie fijo con los botones. */
body.ui-v2 .offcanvas {
    --bs-offcanvas-bg: var(--ds-superficie);   /* blanco, no el gris de --bs-body-bg */
    --bs-offcanvas-border-color: var(--ds-borde);
    --bs-offcanvas-box-shadow: var(--ds-sombra-menu);
    --bs-offcanvas-padding-x: 24px;
    --bs-offcanvas-padding-y: 20px;
    --bs-offcanvas-title-line-height: 1.35;
}
body.ui-v2 .offcanvas.offcanvas-end {
    --bs-offcanvas-width: 480px;
    top: 12px;
    right: 12px;
    bottom: 12px;
    height: auto;
    max-width: calc(100vw - 24px);
    border: 0;
    border-radius: var(--ds-radio-dialogo);
    box-shadow: var(--ds-sombra-dialogo);
    transform: translateX(calc(100% + 24px));
}
body.ui-v2 .offcanvas.offcanvas-end.showing,
body.ui-v2 .offcanvas.offcanvas-end.show:not(.hiding) { transform: none; }
body.ui-v2 .offcanvas.offcanvas-end.ds-panel-lateral-ancho { --bs-offcanvas-width: 640px; }
body.ui-v2 .offcanvas-header {
    align-items: flex-start;
    gap: var(--ds-e3);
    padding-bottom: 12px;
    background: var(--ds-superficie);
    color: var(--ds-texto);
    border-radius: var(--ds-radio-dialogo) var(--ds-radio-dialogo) 0 0;
}
body.ui-v2 .offcanvas-title { font-size: 18px; font-weight: 600; letter-spacing: -0.01em; }
body.ui-v2 .ds-panel-lateral-titulos { min-width: 0; }
body.ui-v2 .ds-panel-lateral-linea { margin: 2px 0 0; color: var(--ds-texto-2); font-size: var(--ds-tam-cuerpo); }
body.ui-v2 .offcanvas-body { padding-top: 4px; }
body.ui-v2 .ds-panel-lateral-pie {
    flex: none;
    display: flex;
    justify-content: flex-end;
    gap: var(--ds-e2);
    padding: 16px 24px;
    border-top: 1px solid var(--ds-borde);
}
body.ui-v2 .offcanvas-backdrop { --bs-backdrop-bg: var(--ds-velo); --bs-backdrop-opacity: 0.24; }
@media (max-width: 575.98px) {
    body.ui-v2 .offcanvas.offcanvas-end { top: 8px; right: 8px; bottom: 8px; max-width: calc(100vw - 16px); }
}
/* Popover (ayuda "?") */
body.ui-v2 .popover {
    --bs-popover-font-size: var(--ds-tam-tabla);
    --bs-popover-bg: var(--ds-superficie);
    --bs-popover-border-color: var(--ds-borde);
    --bs-popover-border-radius: var(--ds-radio-tarjeta);
    --bs-popover-inner-border-radius: calc(var(--ds-radio-tarjeta) - 1px);
    --bs-popover-box-shadow: var(--ds-sombra-menu);
    --bs-popover-max-width: 340px;
    --bs-popover-header-bg: var(--ds-superficie);
    --bs-popover-header-color: var(--ds-texto);
    --bs-popover-header-font-size: var(--ds-tam-cuerpo);
    --bs-popover-header-padding-x: 16px;
    --bs-popover-header-padding-y: 14px;
    --bs-popover-body-padding-x: 16px;
    --bs-popover-body-padding-y: 12px;
    --bs-popover-body-color: var(--ds-texto-2);
    font-family: var(--ds-fuente);
    line-height: 1.5;
    box-shadow: var(--bs-popover-box-shadow);
}
body.ui-v2 .popover-header { border-bottom: 0; padding-bottom: 0; font-weight: 600; }
body.ui-v2 .popover-body > :last-child,
body.ui-v2 .popover-body p:last-child { margin-bottom: 0; }
body.ui-v2 .popover-body p { margin-bottom: 8px; }
body.ui-v2 .popover-body ul { padding-left: 18px; margin-bottom: 8px; }
/* Tooltip */
body.ui-v2 .tooltip {
    --bs-tooltip-bg: var(--ds-texto);
    --bs-tooltip-color: var(--ds-texto-sobre-relleno);
    --bs-tooltip-font-size: var(--ds-tam-etiqueta);
    --bs-tooltip-border-radius: var(--ds-radio-item);
    --bs-tooltip-padding-x: 10px;
    --bs-tooltip-padding-y: 6px;
    --bs-tooltip-opacity: 1;
    font-family: var(--ds-fuente);
    font-weight: 500;
}
/* Insignias → píldoras suaves */
body.ui-v2 .badge {
    --bs-badge-font-weight: 500;
    --bs-badge-font-size: var(--ds-tam-etiqueta);
    --bs-badge-padding-x: 10px;
    --bs-badge-padding-y: 4px;
    --bs-badge-border-radius: var(--ds-radio-pildora);
    --bs-badge-color: var(--ds-neutro);
    line-height: 1.16667;
}
body.ui-v2 .badge.text-bg-secondary, body.ui-v2 .badge.bg-secondary, body.ui-v2 .badge.text-bg-light, body.ui-v2 .badge.bg-light, body.ui-v2 .badge.text-bg-dark, body.ui-v2 .badge.bg-dark
    { background: var(--ds-neutro-fondo) !important; color: var(--ds-neutro) !important; }
body.ui-v2 .badge.text-bg-warning, body.ui-v2 .badge.bg-warning
    { background: var(--ds-aviso-fondo) !important; color: var(--ds-aviso) !important; }
body.ui-v2 .badge.text-bg-success, body.ui-v2 .badge.bg-success
    { background: var(--ds-exito-fondo) !important; color: var(--ds-exito) !important; }
body.ui-v2 .badge.text-bg-danger, body.ui-v2 .badge.bg-danger
    { background: var(--ds-error-fondo) !important; color: var(--ds-error) !important; }
body.ui-v2 .badge.text-bg-primary, body.ui-v2 .badge.bg-primary, body.ui-v2 .badge.text-bg-info, body.ui-v2 .badge.bg-info
    { background: var(--ds-info-fondo) !important; color: var(--ds-info) !important; }
/* Alertas de Bootstrap en tono suave (dentro de pantallas; los mensajes
   flash ya no son franjas: ver §18) */
body.ui-v2 .alert {
    --bs-alert-border-radius: var(--ds-radio-campo);
    --bs-alert-padding-x: 14px;
    --bs-alert-padding-y: 10px;
    --bs-alert-border-color: transparent;
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.42858;
}
body.ui-v2 .alert-success { --bs-alert-bg: var(--ds-exito-fondo); --bs-alert-color: var(--ds-exito); --bs-alert-link-color: var(--ds-exito); }
body.ui-v2 .alert-warning { --bs-alert-bg: var(--ds-aviso-fondo); --bs-alert-color: var(--ds-aviso); --bs-alert-link-color: var(--ds-aviso); }
body.ui-v2 .alert-danger  { --bs-alert-bg: var(--ds-error-fondo); --bs-alert-color: var(--ds-error); --bs-alert-link-color: var(--ds-error); }
body.ui-v2 .alert-info,
body.ui-v2 .alert-primary { --bs-alert-bg: var(--ds-info-fondo); --bs-alert-color: var(--ds-info); --bs-alert-link-color: var(--ds-info); }
body.ui-v2 .alert-secondary,
body.ui-v2 .alert-light,
body.ui-v2 .alert-dark   { --bs-alert-bg: var(--ds-neutro-fondo); --bs-alert-color: var(--ds-neutro); --bs-alert-link-color: var(--ds-neutro); }
/* Barra de progreso */
body.ui-v2 .progress,
body.ui-v2 .progress-stacked { --bs-progress-bg: var(--ds-neutro-fondo); --bs-progress-bar-bg: var(--ds-acento); --bs-progress-border-radius: var(--ds-radio-pildora); --bs-progress-height: 8px; }
/* Grupos de lista */
body.ui-v2 .list-group {
    --bs-list-group-bg: var(--ds-superficie);
    --bs-list-group-border-color: var(--ds-borde);
    --bs-list-group-border-radius: var(--ds-radio-tarjeta);
    --bs-list-group-item-padding-x: 16px;
    --bs-list-group-item-padding-y: 12px;
    --bs-list-group-action-hover-bg: var(--ds-hover);
    --bs-list-group-active-bg: var(--ds-acento-claro);
    --bs-list-group-active-color: var(--ds-acento-oscuro);
    --bs-list-group-active-border-color: var(--ds-borde);
}
/* Acordeón: tarjetas sueltas y suaves (como las preguntas de Aeropost) */
body.ui-v2 .accordion {
    --bs-accordion-border-color: var(--ds-borde);
    --bs-accordion-border-radius: var(--ds-radio-tarjeta);
    --bs-accordion-inner-border-radius: calc(var(--ds-radio-tarjeta) - 1px);
    --bs-accordion-btn-padding-x: 20px;
    --bs-accordion-btn-padding-y: 16px;
    --bs-accordion-btn-color: var(--ds-texto);
    --bs-accordion-btn-focus-box-shadow: 0 0 0 3px var(--ds-anillo);
    --bs-accordion-active-color: var(--ds-texto);
    --bs-accordion-active-bg: var(--ds-superficie);
    --bs-accordion-bg: var(--ds-superficie);
    --bs-accordion-body-padding-x: 20px;
    display: grid;
    gap: var(--ds-e3);
}
body.ui-v2 .accordion-item {
    border: 1px solid var(--ds-borde-marco) !important;
    border-radius: var(--ds-radio-tarjeta) !important;
    box-shadow: var(--ds-sombra-tarjeta);
    overflow: hidden;
}
body.ui-v2 .accordion-button { font-weight: 500; border-radius: var(--ds-radio-tarjeta) !important; }
body.ui-v2 .accordion-button:not(.collapsed) { box-shadow: none; }
body.ui-v2 .accordion-body { padding: 0 20px 16px; color: var(--ds-texto-2); }
/* Utilidades oscuras que no deben aparecer como bloques */
body.ui-v2 .table-dark,
body.ui-v2 thead.table-dark { --bs-table-bg: var(--ds-encabezado-tabla); --bs-table-color: var(--ds-texto-2); --bs-table-border-color: var(--ds-borde); }
/* Bootstrap: primario y foco de campos */
body.ui-v2 .text-primary { color: var(--ds-acento-oscuro) !important; }
body.ui-v2 .bg-primary { background-color: var(--ds-acento-claro) !important; color: var(--ds-acento-oscuro) !important; }
body.ui-v2 .text-bg-primary:not(.badge) { background-color: var(--ds-acento-claro) !important; color: var(--ds-acento-oscuro) !important; }
body.ui-v2 .border-primary { border-color: var(--ds-acento) !important; }
body.ui-v2 .rounded { border-radius: var(--ds-radio-campo) !important; }
body.ui-v2 .rounded-3 { border-radius: var(--ds-radio-tarjeta) !important; }
body.ui-v2 .shadow-sm { box-shadow: var(--ds-sombra-tarjeta) !important; }
body.ui-v2 .shadow { box-shadow: var(--ds-sombra-flotante) !important; }


/* 15. Tablas ============================================================== */
/* 15a. Marco, filas, densidades, hover, selección y vacío --------------- */
body.ui-v2 .table {
    --bs-table-color: var(--ds-texto);
    --bs-table-bg: var(--ds-superficie);
    --bs-table-border-color: var(--ds-borde);
    --bs-table-hover-bg: var(--ds-hover);
    --bs-table-hover-color: var(--ds-texto);
    --bs-table-striped-bg: var(--ds-hover);
    --bs-table-active-bg: var(--ds-acento-claro);
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .ui-tabla,
body.ui-v2 .ds-tabla {
    --bs-table-bg: var(--ds-superficie);
    --bs-table-hover-bg: var(--ds-hover);
    margin-bottom: 0;
    border-collapse: separate;   /* el encabezado fijo conserva su línea */
    border-spacing: 0;
    color: var(--ds-texto);
    font-size: 13px;
}
/* sin líneas verticales; una línea horizontal fina */
body.ui-v2 .ui-tabla > thead > tr > th,
body.ui-v2 .ds-tabla > thead > tr > th {
    height: 40px;
    padding: 0 12px;
    border: 0;
    background: var(--ds-encabezado-tabla);
    box-shadow: inset 0 -1px 0 var(--ds-borde);
    color: var(--ds-texto-2);
    font-size: 12px;
    font-weight: 500;
    line-height: 1.33334;
    letter-spacing: 0;
    text-transform: none;
    white-space: nowrap;
    vertical-align: middle;
}
body.ui-v2 .ui-tabla > tbody > tr > td,
body.ui-v2 .ds-tabla > tbody > tr > td {
    height: var(--ds-fila-comoda, 52px);
    padding: 6px 12px;
    border: 0;
    border-bottom: 1px solid var(--ds-borde-suave);
    font-size: 13px;
    line-height: 1.53847;
    vertical-align: middle;
}
body.ui-v2 .ui-tabla > thead > tr > th:first-child,
body.ui-v2 .ui-tabla > tbody > tr > td:first-child,
body.ui-v2 .ds-tabla > thead > tr > th:first-child,
body.ui-v2 .ds-tabla > tbody > tr > td:first-child { padding-left: var(--ds-e4, 16px); }
body.ui-v2 .ui-tabla > thead > tr > th:last-child,
body.ui-v2 .ui-tabla > tbody > tr > td:last-child,
body.ui-v2 .ds-tabla > thead > tr > th:last-child,
body.ui-v2 .ds-tabla > tbody > tr > td:last-child { padding-right: var(--ds-e4, 16px); }
body.ui-v2 .ui-tabla > tbody > tr:last-child > td,
body.ui-v2 .ds-tabla > tbody > tr:last-child > td { border-bottom: 0; }
/* densidad: compacta, mínimo 40px (tabla 13px). .ds-tabla-compacta = lo mismo para tablas estáticas.
   Fase "todo" (queja del usuario: "se ve amontonado"): relleno de 5px arriba y abajo. Una fila
   de texto mide 40 (mínimo); con un botón o select de 32px, 32 + 10 + 1 = 43; con una celda de
   dos líneas (§23a: 17 + 16), 33 + 10 + 1 = 44. Las alturas son mínimos: si el navegador
   agranda el texto (Safari con zoom bajo sube el texto chico a 9 px de pantalla) la fila crece
   con él en vez de encimar las líneas. */
body.ui-v2 .tb-densidad-compacta .ui-tabla > tbody > tr > td,
body.ui-v2 .ds-tabla-compacta > tbody > tr > td {
    height: var(--ds-fila-compacta, 40px);
    /* 5 px con la letra de 13 (0.3847em): si Safari agranda el texto (zoom de
       página bajo: 13 -> 18 px) el relleno crece con él y la fila conserva sus
       proporciones (antes las dos líneas de una celda casi tocaban los bordes) */
    padding-top: 0.3847em;
    padding-bottom: 0.3847em;
}
body.ui-v2 .tb-densidad-compacta .ui-tabla > thead > tr > th,
body.ui-v2 .ds-tabla-compacta > thead > tr > th { height: 34px; }
/* hover gris muy claro (Bootstrap pinta la celda con --bs-table-bg-state) */
body.ui-v2 .ui-tabla > tbody > tr.ds-f-hover > *,
body.ui-v2 .ds-tabla > tbody > tr.ds-f-hover > * { --bs-table-bg-state: var(--ds-hover); }
/* fila seleccionada (casilla de TablaDatos, .table-active o clase propia) */
body.ui-v2 .ui-tabla > tbody > tr:has(> td > .tb-sel:checked) > *,
body.ui-v2 .ui-tabla > tbody > tr.table-active > *,
body.ui-v2 .ui-tabla > tbody > tr.ds-f-activo > *,
body.ui-v2 .ds-tabla > tbody > tr.ds-fila-seleccionada > * { --bs-table-bg-state: var(--ds-fila-seleccionada); }
/* números a la derecha, cifras tabulares */
body.ui-v2 .ui-tabla .ui-col-numerica,
body.ui-v2 .ds-tabla .ui-col-numerica,
body.ui-v2 .ds-num { text-align: right; font-variant-numeric: tabular-nums; }
/* en campos, cifras tabulares pero alineados a la izquierda (NOG, NIT, fechas);
   montos y cantidades llevan text-end */
body.ui-v2 .form-control.ds-num { text-align: left; }
/* celdas */
body.ui-v2 .ds-celda-acciones {
    width: 1%;
    text-align: right;
    white-space: nowrap;
}
body.ui-v2 .ds-celda-acciones > * { vertical-align: middle; }
body.ui-v2 .ds-acciones-fila { display: inline-flex; align-items: center; justify-content: flex-end; gap: var(--ds-e1, 4px); }
body.ui-v2 .ds-celda-acciones .ds-menu-acciones { margin-left: 2px; }
body.ui-v2 .ds-celda-secundaria { display: block; color: var(--ds-texto-2); font-size: 12px; line-height: 1.33334; }
body.ui-v2 .ds-celda-apagada { color: var(--ds-texto-2); }
body.ui-v2 .ui-tabla .tb-sel,
body.ui-v2 .ui-tabla .tb-sel-todos { margin: 0; vertical-align: middle; }
/* Marco: tarjeta de 16px con encabezado fijo. TablaDatos v2 lo arma
   (.tb-marco); para tablas estáticas: <div class="ds-tabla-marco"> */
body.ui-v2 .ds-tabla-marco,
body.ui-v2 .tb-v2 > .tb-marco {
    border: 1px solid var(--ds-borde-marco);
    border-radius: var(--ds-radio-tarjeta, 16px);
    background: var(--ds-superficie);
    box-shadow: var(--ds-sombra-tarjeta);
    overflow: hidden;
}
body.ui-v2 .ds-tabla-marco > .table-responsive { border-radius: inherit; }
/* Marco con desplazamiento posicionado: lo absoluto dentro de la tabla (el
   <span class="visually-hidden"> de un encabezado "Acciones") se recorta con
   el marco; sin esto tomaba la ventana como referencia y en el teléfono
   agrandaba la PÁGINA (446 px medidos). Y el encabezado que lo lleva lo
   contiene, salvo que ya sea fijo (:where no le gana a sticky). */
body.ui-v2 .table-responsive { position: relative; }
body.ui-v2 :where(.ui-tabla, .ds-tabla) > thead > tr > th:where(:has(> .visually-hidden)) { position: relative; }
body.ui-v2 .tb-v2 > .tb-marco {
    /* por defecto cabe en la ventana; altoMaximo lo cambia (JS escribe --tb-alto-max) */
    max-height: var(--tb-alto-max, calc(100vh - 160px));
    overflow: auto;
    scrollbar-width: thin;
}
body.ui-v2 .tb-marco > .ui-tabla > thead > tr > th,
body.ui-v2 .ds-tabla-marco .ds-tabla-fija > thead > tr > th {
    position: sticky;
    top: 0;
    z-index: 2;
}
/* Columna de acciones fija a la derecha (si es la última): con muchas
   columnas, como la sábana, la acción principal y el "⋯" siguen a la vista al
   desplazar la tabla de lado. Sin z-index en la celda: el menú "⋯" abierto
   queda por encima de las filas de abajo. Solo desde tableta. */
@media (min-width: 768px) {
    body.ui-v2 .tb-marco > .ui-tabla > tbody > tr > td.ds-celda-acciones:last-child {
        position: sticky;
        right: 0;
    }
    /* sticky crea su propio apilamiento: con el menú "⋯" abierto la celda sube
       para que el menú quede sobre las celdas fijas de las filas de abajo */
    body.ui-v2 .tb-marco > .ui-tabla > tbody > tr > td.ds-celda-acciones:last-child:has(.show) { z-index: 4; }
    body.ui-v2 .tb-marco > .ui-tabla:has(> tbody > tr > td.ds-celda-acciones:last-child) > thead > tr > th:last-child {
        right: 0;
        z-index: 3;
    }
    /* borde izquierdo difuminado (no es una línea): lo que pasa por debajo se
       desvanece hacia el color de la celda (blanco, hover o seleccionada) */
    body.ui-v2 .tb-marco > .ui-tabla > tbody > tr > td.ds-celda-acciones:last-child::before,
    body.ui-v2 .tb-marco > .ui-tabla:has(> tbody > tr > td.ds-celda-acciones:last-child) > thead > tr > th:last-child::before {
        content: "";
        position: absolute;
        top: 0;
        bottom: 0;
        left: -12px;
        width: 12px;
        background: linear-gradient(to right, transparent, var(--bs-table-bg-state, var(--ds-superficie)));
        pointer-events: none;
    }
    body.ui-v2 .tb-marco > .ui-tabla:has(> tbody > tr > td.ds-celda-acciones:last-child) > thead > tr > th:last-child::before {
        bottom: 1px;
        background: linear-gradient(to right, transparent, var(--ds-encabezado-tabla));
    }
}
/* estado vacío dentro de la tabla: ícono + una frase (sin hover) */
body.ui-v2 .ui-tabla > tbody > tr.tb-fila-vacia > td {
    height: auto;
    padding: var(--ds-e6, 32px) var(--ds-e4, 16px);
    border-bottom: 0;
    --bs-table-bg-state: transparent;
    text-align: center;
    white-space: normal;
}
body.ui-v2 .tb-fila-vacia .ds-vacio { padding: var(--ds-e5, 24px) var(--ds-e4, 16px); }
body.ui-v2 td > .ds-vacio { padding: var(--ds-e6, 32px) var(--ds-e4, 16px); }


/* 15b. Encabezado de TablaDatos: orden y embudos -------------------------- */
body.ui-v2 .tb-th { white-space: nowrap; }
body.ui-v2 .ui-tabla th.ui-col-numerica { text-align: right; }
body.ui-v2 .tb-titulo {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
    border-radius: 6px;
    transition: color var(--ds-transicion, 150ms ease);
}
body.ui-v2 .tb-titulo.tb-ordenable { cursor: pointer; user-select: none; }
body.ui-v2 .tb-titulo.tb-ordenable:hover,
body.ui-v2 th.ds-f-hover .tb-titulo { color: var(--ds-texto); }
body.ui-v2 .tb-titulo:focus-visible { outline: 0; box-shadow: var(--tb-anillo); }
body.ui-v2 th[aria-sort="ascending"] .tb-titulo,
body.ui-v2 th[aria-sort="descending"] .tb-titulo { color: var(--ds-texto); }
body.ui-v2 .tb-orden { margin-left: 4px; color: var(--ds-acento-oscuro); font-size: 14px; }
body.ui-v2 .tb-orden.ti:not([class*="ti-"]),
body.ui-v2 .tb-orden.bi:not([class*="bi-"]) { display: none; }
body.ui-v2 .tb-embudo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    margin-left: 2px;
    padding: 0;
    border: 0;
    border-radius: var(--ds-radio-pildora, 999px);
    background: transparent;
    color: var(--ds-texto-3);
    font-size: 14px;
    line-height: 1;
    vertical-align: middle;
    cursor: pointer;
    transition: opacity var(--ds-transicion, 150ms ease), background-color var(--ds-transicion, 150ms ease), color var(--ds-transicion, 150ms ease);
}
body.ui-v2 .tb-embudo:hover,
body.ui-v2 .tb-embudo.ds-f-hover,
body.ui-v2 .tb-embudo.tb-abierto { background: var(--ds-hover); color: var(--ds-texto); }
body.ui-v2 .tb-embudo.tb-activo,
body.ui-v2 .tb-embudo.ds-f-activo { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
body.ui-v2 .tb-embudo:focus-visible,
body.ui-v2 .tb-embudo.ds-f-foco { outline: 0; box-shadow: var(--tb-anillo); }
/* TablaDatos SOBRE una tabla que dibujó el servidor (Corrección 1, 2026-10-01: `tabla:` en tabla.js, modos
   cliente y servidor). El título del <th> conserva su forma (se parte en líneas como antes); la fila que no
   pasa el filtro se oculta (tr.tb-fuera) sin rearmarse; la barra de filtros de columna va arriba de la tabla
   y solo se ve con un filtro activo. */
body.ui-v2 .tb-th-dom > .tb-titulo { display: inline; }
body.ui-v2 .tb-th-dom > .tb-titulo.tb-ordenable { cursor: pointer; }
body.ui-v2 .tb-tabla-dom > tbody > tr.tb-fuera { display: none; }
body.ui-v2 .tb-dom[hidden] { display: none; }
body.ui-v2 .tb-dom { margin: 0 0 var(--ds-e2, 8px); }
body.ui-v2 .tb-dom > .tb-barra { margin: 0; }
body.ui-v2 .tb-tabla-dom > tbody > tr.tb-fila-vacia > td { height: auto; padding: var(--ds-e5, 24px) var(--ds-e4, 16px); text-align: center; white-space: normal; }
/* Embudos solo al pasar el mouse (embudosAlPasar): se ocultan con opacidad
   (siguen en el orden del teclado). Siempre visibles: con filtro activo,
   con su panel abierto, con foco dentro del encabezado y en pantallas
   táctiles (hover: none). */
@media (hover: hover) {
    body.ui-v2 .tb-embudos-al-pasar .tb-embudo { opacity: 0; }
    body.ui-v2 .tb-embudos-al-pasar th:hover .tb-embudo,
    body.ui-v2 .tb-embudos-al-pasar th:focus-within .tb-embudo,
    body.ui-v2 .tb-embudos-al-pasar th.ds-f-hover .tb-embudo,
    body.ui-v2 .tb-embudos-al-pasar .tb-embudo.tb-activo,
    body.ui-v2 .tb-embudos-al-pasar .tb-embudo.tb-abierto,
    body.ui-v2 .tb-embudos-al-pasar .tb-embudo.ds-f-hover,
    body.ui-v2 .tb-embudos-al-pasar .tb-embudo.ds-f-activo,
    body.ui-v2 .tb-embudos-al-pasar .tb-embudo:focus-visible { opacity: 1; }
}
@media (hover: none) {
    body.ui-v2 .tb-embudos-al-pasar .tb-embudo { opacity: 1; }
}


/* 16. Menú de acciones "⋯" ================================================ */
/* Acción principal visible en la fila; el resto en "⋯" (UI.htmlMenuAcciones
   o el macro menu_acciones). Ítems con ícono; peligro en rojo y al final. */
body.ui-v2 .ds-menu-acciones { display: inline-block; position: relative; vertical-align: middle; }
body.ui-v2 .ds-menu-acciones > [data-bs-toggle="dropdown"] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    min-width: 32px;
    min-height: 0;
    padding: 0;
    border: 0;
    border-radius: var(--ds-radio-pildora, 999px);
    background: transparent;
    color: var(--ds-texto-2);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    transition: background-color var(--ds-transicion, 150ms ease), color var(--ds-transicion, 150ms ease);
}
body.ui-v2 .ds-menu-acciones > [data-bs-toggle="dropdown"] > i { font-size: 18px; }
body.ui-v2 .ds-menu-acciones > [data-bs-toggle="dropdown"]:hover,
body.ui-v2 .ds-menu-acciones > [data-bs-toggle="dropdown"].ds-f-hover { background: var(--ds-hover); color: var(--ds-texto); }
body.ui-v2 .ui-tabla > tbody > tr:hover .ds-menu-acciones > [data-bs-toggle="dropdown"]:hover { background: var(--ds-neutro-hover); }
body.ui-v2 .ds-menu-acciones > [data-bs-toggle="dropdown"][aria-expanded="true"],
body.ui-v2 .ds-menu-acciones > [data-bs-toggle="dropdown"].ds-f-activo { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-menu-acciones > [data-bs-toggle="dropdown"]:focus-visible,
body.ui-v2 .ds-menu-acciones > [data-bs-toggle="dropdown"].ds-f-foco { outline: 0; box-shadow: var(--tb-anillo); }
body.ui-v2 .ds-menu-acciones > [data-bs-toggle="dropdown"]:disabled,
body.ui-v2 .ds-menu-acciones > [data-bs-toggle="dropdown"][aria-disabled="true"] { color: var(--ds-texto-3); background: transparent; cursor: not-allowed; opacity: 0.6; }
body.ui-v2 .ds-menu {
    --bs-dropdown-zindex: 1040;          /* sobre la barra flotante, bajo modales (1055) y paneles de filtro (1060) */
    --bs-dropdown-link-active-bg: var(--ds-acento-claro);
    --bs-dropdown-link-active-color: var(--ds-acento-oscuro);
    z-index: 1040;
    min-width: 208px;
    padding: 6px;
    border: 1px solid var(--ds-borde);
    border-radius: 14px;
    background: var(--ds-superficie);
    box-shadow: var(--tb-sombra-panel);
    font-family: var(--ds-fuente, "Inter", system-ui, sans-serif);
    font-size: 14px;
}
body.ui-v2 .ds-menu .dropdown-item {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 36px;
    padding: 6px 10px;
    border-radius: 10px;
    color: var(--ds-texto);
    font-size: 14px;
    font-weight: 400;
    white-space: nowrap;
    transition: background-color var(--ds-transicion, 150ms ease), color var(--ds-transicion, 150ms ease);
}
body.ui-v2 .ds-menu .dropdown-item > i {
    flex: none;
    width: 18px;
    color: var(--ds-texto-2);
    font-size: 18px;
    text-align: center;
}
body.ui-v2 .ds-menu .dropdown-item:hover,
body.ui-v2 .ds-menu .dropdown-item:focus-visible,
body.ui-v2 .ds-menu .dropdown-item.ds-f-hover { background: var(--ds-hover); color: var(--ds-texto); outline: 0; }
body.ui-v2 .ds-menu .dropdown-item:active,
body.ui-v2 .ds-menu .dropdown-item.active,
body.ui-v2 .ds-menu .dropdown-item.ds-f-activo { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-menu .dropdown-item:active > i,
body.ui-v2 .ds-menu .dropdown-item.active > i,
body.ui-v2 .ds-menu .dropdown-item.ds-f-activo > i { color: inherit; }
body.ui-v2 .ds-menu .ds-item-peligro,
body.ui-v2 .ds-menu .ds-item-peligro > i { color: var(--ds-error); }
body.ui-v2 .ds-menu .ds-item-peligro:hover,
body.ui-v2 .ds-menu .ds-item-peligro:focus-visible,
body.ui-v2 .ds-menu .ds-item-peligro.ds-f-hover,
body.ui-v2 .ds-menu .ds-item-peligro:active { background: var(--ds-error-fondo); color: var(--ds-error); }
body.ui-v2 .ds-menu .dropdown-item.disabled,
body.ui-v2 .ds-menu .dropdown-item:disabled,
body.ui-v2 .ds-menu .dropdown-item[aria-disabled="true"] { background: transparent; color: var(--ds-texto-3); }
body.ui-v2 .ds-menu .dropdown-item.disabled > i,
body.ui-v2 .ds-menu .dropdown-item:disabled > i { color: var(--ds-texto-3); }
body.ui-v2 .ds-menu .dropdown-divider { margin: 6px 4px; border-top: 1px solid var(--ds-borde); opacity: 1; }
body.ui-v2 .ds-menu .dropdown-header { padding: 6px 10px 4px; color: var(--ds-texto-2); font-size: 12px; font-weight: 500; }
/* en /estilo, un menú mostrado abierto sin Bootstrap (.ds-menu.show estático) */
body.ui-v2 .ds-menu.ds-menu-estatico { position: static; display: block; }


/* 17. Estados vacíos ====================================================== */
/* Como Merkaru: ícono de línea + una frase corta, centrados. Con
   .ds-vacio-marco va dentro de una tarjeta de borde fino (fuera de tablas). */
body.ui-v2 .ds-vacio {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--ds-e3);
    padding: 56px 24px;
    text-align: center;
}
body.ui-v2 .ds-vacio-marco {
    min-height: 240px;
    background: var(--ds-superficie);
    border: 1px solid var(--ds-borde-marco);
    border-radius: var(--ds-radio-tarjeta);
}
body.ui-v2 .ds-vacio-icono {
    display: inline-flex;
    color: var(--ds-texto-2);
    font-size: 32px;
    line-height: 1;
}
body.ui-v2 .ds-vacio-sin-permiso .ds-vacio-icono { color: var(--ds-texto-3); }
body.ui-v2 .ds-vacio-titulo {
    max-width: 440px;
    margin: 0;
    color: var(--ds-texto-2);
    font-size: 14px;
    font-weight: 400;
    line-height: 1.42858;
}
body.ui-v2 .ds-vacio-texto { max-width: 440px; margin: -4px 0 0; color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-vacio-acciones { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--ds-e2); margin-top: var(--ds-e1); }
body.ui-v2 td > .ds-vacio { padding: 40px 16px; }


/* 18. Aviso flotante (UI.estado y mensajes flash) ========================= */
/* Abajo a la derecha, tarjeta blanca redonda con el ícono del estado en un
   círculo suave. Éxito e info desaparecen solos (ui.js); aviso y error
   quedan con su botón de cerrar. Sirve para el marcado propio (.ds-estado)
   y para .toast de Bootstrap. */
body.ui-v2 .ds-estados,
body.ui-v2 .toast-container.ds-toasts {
    position: fixed;
    right: 24px;
    bottom: 24px;
    z-index: 1090;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--ds-e2);
    max-width: min(420px, calc(100vw - 32px));
    pointer-events: none;
}
body.ui-v2 .ds-estados-region {
    display: flex;
    flex-direction: column;
    align-items: inherit;
    gap: var(--ds-e2);
}
body.ui-v2 .ds-estados-region:empty { display: none; }
body.ui-v2 .ds-estado,
body.ui-v2 .toast {
    --bs-toast-max-width: 420px;
    --bs-toast-bg: var(--ds-superficie);
    --bs-toast-border-color: var(--ds-borde);
    --bs-toast-border-radius: var(--ds-radio-tarjeta);
    --bs-toast-box-shadow: var(--ds-sombra-menu);
    --bs-toast-font-size: var(--ds-tam-cuerpo);
    --bs-toast-color: var(--ds-texto);
    --bs-toast-padding-x: 14px;
    --bs-toast-padding-y: 12px;
}
body.ui-v2 .ds-estado {
    display: flex;
    align-items: center;
    gap: var(--ds-e3);
    min-width: 280px;
    max-width: 420px;
    padding: 10px 10px 10px 12px;
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-tarjeta);
    background: var(--ds-superficie);
    color: var(--ds-texto);
    box-shadow: var(--ds-sombra-menu);
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.42858;
    pointer-events: auto;
    animation: ds-entrar 150ms ease-out;
}
body.ui-v2 .ds-estado-icono {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--ds-info-fondo);
    color: var(--ds-info);
    font-size: 18px;
    line-height: 1;
}
body.ui-v2 .ds-estado-texto { flex: 1 1 auto; min-width: 0; padding: 6px 0; }
body.ui-v2 .ds-estado-exito .ds-estado-icono { background: var(--ds-exito-fondo); color: var(--ds-exito); }
body.ui-v2 .ds-estado-aviso .ds-estado-icono,
body.ui-v2 .ds-estado-alerta .ds-estado-icono { background: var(--ds-aviso-fondo); color: var(--ds-aviso); }
body.ui-v2 .ds-estado-error .ds-estado-icono { background: var(--ds-error-fondo); color: var(--ds-error); }
body.ui-v2 .ds-estado-info .ds-estado-icono { background: var(--ds-info-fondo); color: var(--ds-info); }
body.ui-v2 .ds-estado-cerrar {
    flex: none;
    align-self: flex-start;
    width: 32px;
    height: 32px;
    font-size: 16px;
}
body.ui-v2 .ds-estado.saliendo { opacity: 0; transform: translateY(6px); transition: opacity var(--ds-transicion), transform var(--ds-transicion); }
@keyframes ds-entrar { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
body.ui-v2 .toast { pointer-events: auto; }
body.ui-v2 .toast-header { border-bottom: 0; background: transparent; color: var(--ds-texto); font-weight: 600; }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-estados,
    body.ui-v2 .toast-container.ds-toasts { right: 16px; left: 16px; bottom: 16px; align-items: stretch; max-width: none; }
    body.ui-v2 .ds-estado { min-width: 0; max-width: none; }
}


/* 19. Barra flotante de selección ========================================= */
/* Píldora blanca abajo al centro: "3 seleccionados · acciones · ✕". */
body.ui-v2 .ds-barra-seleccion {
    position: fixed;
    left: var(--ds-ancho-riel);
    right: 0;
    bottom: 24px;
    z-index: 1040;
    display: flex;
    justify-content: center;
    padding: 0 16px;
    pointer-events: none;
}
body.ui-v2 .ds-barra-seleccion[hidden] { display: none; }
body.ui-v2 .ds-barra-seleccion-interior {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2);
    min-height: 52px;
    padding: 6px 6px 6px 20px;
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-superficie);
    box-shadow: var(--ds-sombra-menu-fuerte);
    pointer-events: auto;
    animation: ds-entrar 150ms ease-out;
}
body.ui-v2 .ds-barra-seleccion-conteo { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
body.ui-v2 .ds-barra-seleccion-sep { width: 1px; height: 24px; margin: 0 var(--ds-e1); background: var(--ds-borde); }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-barra-seleccion { bottom: 16px; }
    body.ui-v2 .ds-barra-seleccion-interior { border-radius: var(--ds-radio-tarjeta); }
}


/* 20. Diálogos pequeños (UI.confirmar y macro dialogo) ==================== */
/* Confirmaciones: 420 px, radio 20, ícono del estado en círculo suave,
   botones a la derecha. */
body.ui-v2 .ds-dialogo .modal-dialog { max-width: 420px; }
body.ui-v2 .ds-dialogo.ds-dialogo-ancho .modal-dialog { max-width: 640px; }
body.ui-v2 .ds-dialogo .modal-header { align-items: center; gap: var(--ds-e3); padding-top: 22px; }
body.ui-v2 .ds-dialogo-icono {
    flex: none;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
    font-size: 20px;
    line-height: 1;
}
body.ui-v2 .ds-dialogo-peligro .ds-dialogo-icono { background: var(--ds-error-fondo); color: var(--ds-error); }
body.ui-v2 .ds-dialogo-aviso .ds-dialogo-icono { background: var(--ds-aviso-fondo); color: var(--ds-aviso); }
body.ui-v2 .ds-dialogo .modal-title { flex: 1 1 auto; min-width: 0; }
body.ui-v2 .ds-dialogo .modal-body { color: var(--ds-texto-2); }
body.ui-v2 .ds-dialogo .modal-body > :last-child { margin-bottom: 0; }
body.ui-v2 .ds-dialogo .modal-footer { padding-top: 16px; }


/* 21. Compatibilidad con piezas viejas dentro de ui-v2 ==================== */
/* Bloques oscuros de Bootstrap (.bg-dark) que alguna pantalla o JS todavía
   pone: gris suave, sin azul oscuro. (Las clases de la estructura vieja
   —.ui-cabecera-modulo, .ui-pie-acciones, .ui-btn-*…— se quitaron el
   2026-09-28: ninguna plantilla ni JS las usa.) */
body.ui-v2 .bg-dark { background-color: var(--ds-neutro-fondo) !important; color: var(--ds-texto) !important; }
body.ui-v2 .offcanvas-header.bg-dark .btn-close-white,
body.ui-v2 .bg-dark .btn-close-white { filter: none; }
body.ui-v2 .text-white.bg-dark,
body.ui-v2 .bg-dark .text-white { color: var(--ds-texto) !important; }


/* 21b. Lo que se tomaba de custom.css ------------------------------------- */
/* custom.css era la hoja de las pantallas viejas; desde 2026-09-28 todas son
   v2 y ya no se carga. Estas son las únicas reglas suyas que todavía se veían
   (o hacían algo) en las pantallas v2, medidas elemento por elemento con y sin
   custom.css (estilo calculado, 2026-09-28). Van con :where() para quedar con la
   especificidad más baja de este archivo: como custom.css se cargaba antes,
   cualquier regla de aquí sigue ganándoles. El resto de custom.css (estructura
   vieja, azul marino, clases que ya no usa nadie o que este archivo re-pinta
   por completo) no se trae. */
/* clases que el JS pone para ocultar o animar (static/js/detalle_siaf.js,
   compras.js, sabana_465.js y solicitud_form.js) */
body.ui-v2 :where(.det-oculta) { display: none; }
body.ui-v2 :where(.ca-pulso) { animation: ds-latido 1.8s ease-in-out infinite; }   /* contrato abierto: mismo latido que .ds-latido (§25f) */
@keyframes ds-girar { to { transform: rotate(360deg); } }
body.ui-v2 :where(.cs-girando) { display: inline-block; animation: ds-girar 1s linear infinite; }   /* ícono mientras se consulta Guatecompras */
@media (prefers-reduced-motion: reduce) {
    body.ui-v2 :where(.ca-pulso, .cs-girando) { animation: none; }
}
/* celdas de la cuadrícula 465: ancla del tirador y del cuadro de "varias
   coincidencias" (§25n) */
body.ui-v2 :where(.s465-tabla td) { position: relative; }
/* punto de la asignación conservada en el Detalle (§25m pone tamaño y color) */
body.ui-v2 :where(.det-punto) { display: inline-block; border-radius: 50%; vertical-align: middle; }
body.ui-v2 :where(.det-tabla td.det-conservada) { position: relative; }
/* TablaDatos: flecha del orden centrada con el título y ancho preferido de la
   columna de encabezado propio (acciones) */
body.ui-v2 :where(.tb-orden) { vertical-align: middle; }
body.ui-v2 :where(.tb-th-propio) { width: 2rem; }
/* impresión: lo marcado .no-print no sale en papel */
@media print {
    body.ui-v2 .no-print { display: none !important; }
}


/* 22. Movimiento reducido e impresión ===================================== */
@media (prefers-reduced-motion: reduce) {
    body.ui-v2 *,
    body.ui-v2 *::before,
    body.ui-v2 *::after {
        animation-duration: 1ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 1ms !important;
        scroll-behavior: auto !important;
    }
}
@media print {
    body.ui-v2 { background: var(--ds-hoja); }
    body.ui-v2 .ds-riel,
    body.ui-v2 .ds-barra,
    body.ui-v2 .ds-estados,
    body.ui-v2 .ds-barra-seleccion,
    body.ui-v2 .ds-saltar { display: none !important; }
    body.ui-v2 .ds-contenido { padding: 0; }
    body.ui-v2 .ds-panel,
    body.ui-v2 .ui-panel,
    body.ui-v2 .card,
    body.ui-v2 .ds-kpi { box-shadow: none; }
}


/* 22b. Tablas y filtros: teléfono, movimiento reducido e impresión ------ */
@media (max-width: 767.98px) {
    body.ui-v2 .tb-v2 > .tb-barra { flex-wrap: wrap; }
    body.ui-v2 .tb-barra-con-orden::after { display: none; }
    body.ui-v2 .tb-barra-con-orden > .tb-barra-filtros > .tb-buscador-caja,
    body.ui-v2 .tb-barra-con-orden > .tb-barra-filtros > .ds-chips { flex: 0 1 100%; margin-bottom: 0; }
    body.ui-v2 .tb-barra-con-orden > .tb-barra-fin { flex: 1 1 100%; margin: 0; }
    /* las píldoras (en su propia línea) se acomodan una a una junto a "Más filtros" y "Ordenar" */
    body.ui-v2 .tb-barra-con-orden > .tb-barra-filtros > .ds-pildoras { display: contents; }
    body.ui-v2 .tb-barra-con-orden > .tb-barra-filtros > .ds-pildoras > * { order: 5; }
    body.ui-v2 .tb-barra-con-orden > .ds-pildora-orden { flex: 0 1 auto; min-width: 0; max-width: 100%; margin-left: auto; }
    body.ui-v2 .ds-pildora-orden .tb-orden-boton { min-width: 0; max-width: 100%; }
    body.ui-v2 .ds-pildora-orden .ds-pildora-filtro-etiqueta { display: none; }   /* el texto completo sigue en title y aria-label */
    body.ui-v2 .ds-pildora-orden .ds-pildora-filtro-valor { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
    body.ui-v2 .tb-barra-filtros > .ds-chips {
        flex-wrap: nowrap;
        max-width: 100%;
        overflow-x: auto;
        scrollbar-width: none;
    }
    body.ui-v2 .tb-barra-filtros > .ds-chips::-webkit-scrollbar { display: none; }
    body.ui-v2 .tb-barra-filtros > .ds-chips + .ds-pildoras { margin-left: 0; }
    body.ui-v2 .tb-v2 .tb-buscador,
    body.ui-v2 .tb-buscador-caja { width: 100%; }
    body.ui-v2 .tb-buscador-caja > .tb-buscador { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
    body.ui-v2 .ds-chip,
    body.ui-v2 .ds-pildora-filtro,
    body.ui-v2 .ds-pildora-filtro-flecha,
    body.ui-v2 .tb-embudo,
    body.ui-v2 .tb-densidad-op,
    body.ui-v2 .ds-menu .dropdown-item { transition: none; }
}
@media print {
    body.ui-v2 .tb-v2 > .tb-marco { max-height: none; overflow: visible; box-shadow: none; }
    body.ui-v2 .tb-marco > .ui-tabla > thead > tr > th { position: static; }
    body.ui-v2 .tb-v2 > .tb-barra,
    body.ui-v2 .tb-embudo,
    body.ui-v2 .ds-menu-acciones { display: none !important; }
    /* En papel no sirven los botones de la fila ni las casillas de selección
       (tabla.js mete la columna de casillas primero; :not([colspan]) deja el
       estado vacío). Sin esto la sábana medía 1117 px y en Carta (816) se
       cortaban Estado y Acciones. */
    body.ui-v2 .tb-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody, tfoot) > tr > :is(th, td).ds-col-acciones { display: none; }
    body.ui-v2 .tb-v2 :is(.ui-tabla, .ds-tabla):has(> thead > tr > th > .tb-sel-todos) > :is(thead, tbody) > tr > :first-child:not([colspan]) { display: none; }
    /* .ds-impresion-reducida (en el contenedor de TablaDatos, que recibe
       .tb-v2): la tabla sale al 75 % para caber en el ancho de la hoja
       (0 px fuera en Carta y A4 con márgenes de 0.5 in); el papel mide menos
       de 768 px y la consulta de teléfono subiría el piso del nombre a 13em. */
    body.ui-v2 .tb-v2.ds-impresion-reducida > .tb-marco { zoom: 0.75; }
    body.ui-v2 .tb-v2.ds-impresion-reducida :is(.ui-tabla, .ds-tabla) { --ds-col-nombre-min: 6em; }
}


/* 23. Celdas compuestas y detalle ========================================
   Componentes genéricos para tablas densas (primer uso: sábana de Compras).
   Marcado de referencia: comentarios de cada subsección. Relleno con texto
   blanco: siempre var(--ds-relleno-primario) (#1a6fa0); el celeste
   (--ds-acento) solo en anillos, bordes y puntos.
     23a. Celda de dos líneas (.ds-celda) y línea de una fila (.ds-linea)
     23b. Número + estado (.ds-numero) y botón mini (.ds-btn-mini)
     23c. Disparador "+N" (.ds-mas)
     23d. Etiqueta de contorno (.ds-etiqueta: FR, 182, CA)
     23e. Ícono de estado (.ds-icono-estado) e ícono enlace (.ds-icono-enlace)
     23f. Select dentro de la celda (.ds-select-celda) y anillo de atención
          (.ds-atencion)
     23g. Popover: contenedor (.ds-popover, .ds-popover-flotante) y detalle
          (.ds-popover-detalle)
     23h. Diálogos compactos (.ds-modal-compacto, -medio, -amplio) y lista de
          eventos (.ds-lista-eventos)
     23i. Barra de selección sobre la tabla (.ds-tabla-con-seleccion)
     23j. Anchos de columna (.ds-col-*) para que 7 columnas quepan en 1440
     23k. Movimiento reducido e impresión

   Alto de fila en densidad compacta (mínimo 40 px, §15a; fase "todo"):
     una línea ..... texto 20 + relleno 5+5 + línea 1 = 31 -> 40 (mínimo);
                     con botón o select de 32: 32 + 10 + 1 = 43
     dos líneas .... 17 (13 px, interlineado 1.31) + 16 (12 px, 1.33) = 33
                     + relleno 5+5 + línea 1 = 44. Las píldoras dentro de la
                     primera línea miden 18 px y en la segunda 16 px.
   Robustez (Safari con zoom de página bajo sube el texto chico a 9 px de
   pantalla, p. ej. 13 px -> 18 px al 50 %): alturas de línea en em e
   interlineados sin unidad, así cada línea crece con su texto y la fila
   con ellas; nada de alturas fijas en px alrededor de texto.
   Anchos (23j, columnas fluidas): cada columna mide lo que pide su
   contenido (sin "…" en rótulos cortos) con un piso por clase, y el ancho
   que sobra se reparte entre todas; la columna flexible (.ds-col-flex)
   toma una parte fija (porcentaje) y recorta su texto largo.
   ========================================================================== */


/* 23a. Celda de dos líneas ------------------------------------------------ */
/* <div class="ds-celda">
     <div class="ds-celda-principal">…13 px…</div>
     <div class="ds-celda-secundaria">…12 px gris…</div>
   </div>
   Cada línea en una sola fila con "…" al final; el texto completo va en
   title. .ds-celda-texto = pieza que se recorta dentro de una línea. */
body.ui-v2 .ds-celda {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-width: 0;
    max-width: 100%;
    text-align: left;
}
body.ui-v2 .ds-celda-principal,
body.ui-v2 .ds-linea {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    max-width: 100%;
    white-space: nowrap;
}
body.ui-v2 .ds-celda-principal {
    /* alto de UNA línea de su propio texto (17 px con 13 px): los íconos de
       20 px no la agrandan; en em, crece si el navegador agranda el texto */
    height: 1.3077em;
    color: var(--ds-texto);
    font-size: var(--ds-tam-tabla);
    line-height: 1.3077;
}
body.ui-v2 .ds-linea { min-height: 1.54em; }
body.ui-v2 .ds-celda-principal > *,
body.ui-v2 .ds-linea > * { flex: none; }
/* la segunda línea (la clase ya existe en §15a: 12 px gris; aquí se recorta) */
body.ui-v2 .ds-celda > .ds-celda-secundaria {
    display: block;
    height: 1.33334em;            /* una línea de 12 px = 16 px; en em por la misma razón */
    overflow: hidden;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.33334;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
/* con una pieza recortable (.ds-celda-texto), la línea se arma en fila: solo
   esa pieza se recorta y lo demás (p. ej. la fecha al final) siempre se ve.
   Todo el texto de la línea va entonces dentro de <span>. */
body.ui-v2 .ds-celda > .ds-celda-secundaria:has(> .ds-celda-texto) {
    display: flex;
    align-items: center;
    min-width: 0;
}
body.ui-v2 .ds-celda > .ds-celda-secundaria:has(> .ds-celda-texto) > * { flex: none; }
body.ui-v2 .ds-celda > .ds-celda-secundaria:has(> .ds-celda-texto) > .ds-celda-texto { flex: 0 1 auto; min-width: 16px; }
body.ui-v2 .ds-celda-secundaria > .ti,
body.ui-v2 .ds-celda-secundaria > .bi {
    margin-right: 2px;
    font-size: 14px;
    line-height: 1.14286;
    vertical-align: top;
}
/* pieza que se recorta con "…" (nombre del proveedor, renglones largos) */
body.ui-v2 .ds-celda-principal > .ds-celda-texto,
body.ui-v2 .ds-linea > .ds-celda-texto,
body.ui-v2 .ds-celda-texto {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
body.ui-v2 .ds-celda-fuerte { font-weight: 600; }
body.ui-v2 .ds-celda-sep { margin: 0 4px; color: var(--ds-texto-3); }
body.ui-v2 .ds-celda-cifra { font-variant-numeric: tabular-nums; white-space: nowrap; }
/* píldoras dentro de la celda de dos líneas: la medida única de §7 (18 px; la
   línea de arriba mide 17 y la píldora la desborda medio píxel sin agrandar la
   fila). En la línea gris de abajo no va una píldora (Paso 3): .ds-celda-alerta. */
/* (fase "todo": la celda de dos líneas ya no baja su relleno; usa los 5 px
   de la densidad compacta y la fila mide 44) */
/* Píldoras sobre filas con fondo: en la fila seleccionada (celeste claro)
   lo "info" se perdía (mismo fondo) y al pasar el mouse (gris muy claro) lo
   "neutro" también; se ven sobre blanco o un gris un poco más oscuro. */
body.ui-v2 .ui-tabla > tbody > tr:has(> td > .tb-sel:checked) :is(.ds-pildora-info, .ds-pildora-azul),
body.ui-v2 .ui-tabla > tbody > tr.ds-f-activo :is(.ds-pildora-info, .ds-pildora-azul) { background: var(--ds-superficie); }
body.ui-v2 .ui-tabla > tbody > tr:has(> td > .tb-sel:checked) .ds-icono-estado-info,
body.ui-v2 .ui-tabla > tbody > tr.ds-f-activo .ds-icono-estado-info { --ds-ie-fondo: var(--ds-superficie); }
@media (hover: hover) {
    body.ui-v2 .ui-tabla > tbody > tr:hover :is(.ds-pildora-neutro, .ds-pildora-gris, span.ds-mas),
    body.ui-v2 .ui-tabla > tbody > tr.ds-f-hover :is(.ds-pildora-neutro, .ds-pildora-gris, span.ds-mas),
    body.ui-v2 .ui-tabla > tbody > tr:hover button.ds-mas:not(:hover):not([aria-expanded="true"]):not(.ds-f-hover):not(.ds-f-activo) { background: var(--ds-neutro-hover); }
    body.ui-v2 .ui-tabla > tbody > tr:hover .ds-icono-estado-neutro,
    body.ui-v2 .ui-tabla > tbody > tr.ds-f-hover .ds-icono-estado-neutro { --ds-ie-fondo: var(--ds-neutro-hover); }
}
/* "Solo lectura", "Desde SIGES", "No aplica": texto apagado con ícono */
body.ui-v2 .ds-celda-apagada > .ti { margin-right: 4px; font-size: 14px; vertical-align: -2px; }


/* 23b. Número + estado ---------------------------------------------------- */
/* <span class="ds-numero">
     <button type="button" class="ds-numero-valor">24582220<i class="ti ti-link ds-numero-marca"></i></button>
     <span class="ds-pildora ds-pildora-exito ds-numero-estado">Adjudicado</span>
     <button type="button" class="ds-mas">+1</button>
     <button type="button" class="ds-icono-estado ds-icono-estado-info">…</button>
   </span>
   Una línea; si no cabe, la píldora del estado se recorta primero. */
body.ui-v2 .ds-numero {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    max-width: 100%;
    white-space: nowrap;
    vertical-align: middle;
}
body.ui-v2 .ds-numero > * { flex: none; }
body.ui-v2 .ds-numero-valor {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin: 0 -3px;
    padding: 0 3px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--ds-texto);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-tabla);
    font-weight: 500;
    line-height: 1.53847;
    font-variant-numeric: tabular-nums;
    text-decoration: none;
    white-space: nowrap;
    transition: color var(--ds-transicion), background-color var(--ds-transicion);
}
body.ui-v2 button.ds-numero-valor,
body.ui-v2 a.ds-numero-valor { cursor: pointer; }
body.ui-v2 button.ds-numero-valor:hover,
body.ui-v2 a.ds-numero-valor:hover,
body.ui-v2 .ds-numero-valor.ds-f-hover {
    color: var(--ds-acento-oscuro);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
}
body.ui-v2 .ds-numero-valor:focus-visible,
body.ui-v2 .ds-numero-valor.ds-f-foco { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 1px; }
body.ui-v2 .ds-numero-valor[aria-expanded="true"],
body.ui-v2 .ds-numero-valor.ds-f-activo { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
/* marca de "compartido" (ti-link) junto al número */
body.ui-v2 .ds-numero-marca {
    flex: none;
    color: var(--ds-texto-3);
    font-size: 14px;
    line-height: 1;
}
body.ui-v2 .ds-numero-valor:hover .ds-numero-marca { color: inherit; }
/* píldora del estado: tamaño sm (20 px). Fase "todo": entera (los estados son
   rótulos cortos: "Adjudicado", "No adjudicado", "Pendiente en OCDS"); el tope
   en em solo corta un texto anómalo, y crece si el navegador agranda el texto. */
body.ui-v2 .ds-pildora.ds-numero-estado {
    display: inline-block;          /* para el "…"; alto y relleno, los de §7 */
    flex: 0 1 auto;
    min-width: 4em;
    max-width: var(--ds-numero-estado-max, 16em);
    overflow: hidden;
    text-overflow: ellipsis;
}
/* números anteriores (NOG u OC que ya no es el vigente): atenuados */
body.ui-v2 .ds-numero-anterior { opacity: 0.66; }
/* botón mini (24 px): "+ NOG", "+ OC" dentro de la celda.
   <button class="ds-btn ds-btn-fantasma ds-btn-acento ds-btn-mini"><i class="ti ti-plus"></i>NOG</button> */
body.ui-v2 .ds-btn.ds-btn-mini {
    --ds-btn-alto: 24px;
    gap: 3px;
    padding: 0 8px;
    font-size: var(--ds-tam-etiqueta);
}
body.ui-v2 .ds-btn.ds-btn-mini > .ti,
body.ui-v2 .ds-btn.ds-btn-mini > .bi { margin-left: -2px; font-size: 14px; }
/* en la celda de acciones: acción principal un poco más angosta */
body.ui-v2 .ds-celda-acciones .ds-btn.ds-btn-sm:not(.ds-btn-icono) { padding: 0 12px; }


/* 23c. Disparador "+N" ---------------------------------------------------- */
/* <button type="button" class="ds-mas" aria-haspopup="dialog" aria-expanded="false"
           aria-label="2 NOG anteriores">+2</button>
   Abre un popover con el resto (23g). Sin acción: <span class="ds-mas">. */
body.ui-v2 .ds-mas {
    position: relative;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    min-height: 20px;
    padding: 2px 6px;
    border: 0;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-neutro-fondo);
    color: var(--ds-neutro);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 500;
    line-height: 1.33334;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    vertical-align: middle;
    cursor: default;
    transition: background-color var(--ds-transicion), color var(--ds-transicion);
}
/* área de toque de 24 px sin cambiar lo que se ve */
body.ui-v2 button.ds-mas::after {
    content: "";
    position: absolute;
    inset: -2px -1px;
    border-radius: inherit;
}
body.ui-v2 button.ds-mas { cursor: pointer; }
body.ui-v2 button.ds-mas:hover,
body.ui-v2 .ds-mas.ds-f-hover { background: var(--ds-neutro-activo); color: var(--ds-texto); }
body.ui-v2 .ds-mas[aria-expanded="true"],
body.ui-v2 .ds-mas.ds-f-activo { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-mas:focus-visible,
body.ui-v2 .ds-mas.ds-f-foco { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 1px; }
body.ui-v2 .ds-mas:disabled,
body.ui-v2 .ds-mas[aria-disabled="true"] { background: var(--ds-neutro-fondo); color: var(--ds-texto-3); cursor: not-allowed; }


/* 23d. Etiqueta de contorno (FR, 182, CA) --------------------------------- */
/* Pequeña, solo borde: marca un atributo, no un estado (los estados son
   píldoras llenas). <span class="ds-etiqueta ds-etiqueta-aviso" title="Fondo rotativo">FR</span> */
body.ui-v2 .ds-etiqueta {
    flex: none;
    display: inline-flex;
    align-items: center;
    min-height: 18px;
    padding: 0 6px;
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-pildora);
    background: transparent;
    color: var(--ds-texto-2);
    font-family: var(--ds-fuente);
    font-size: 11px;
    font-weight: 600;
    line-height: 1.45455;
    letter-spacing: 0.02em;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    vertical-align: middle;
}
body.ui-v2 .ds-etiqueta-info   { border-color: var(--ds-acento-borde); color: var(--ds-info); }
body.ui-v2 .ds-etiqueta-aviso  { border-color: var(--ds-aviso-borde-2); color: var(--ds-aviso); }
body.ui-v2 .ds-etiqueta-exito  { border-color: var(--ds-exito-borde-2); color: var(--ds-exito); }
body.ui-v2 .ds-etiqueta-error  { border-color: var(--ds-error-borde-2); color: var(--ds-error); }
body.ui-v2 .ds-etiqueta-neutro { border-color: var(--ds-borde-fuerte); color: var(--ds-texto-2); }


/* 23e. Ícono de estado e ícono enlace ------------------------------------- */
/* Ícono Tabler de 14 px en un círculo suave de 20 px del color del estado
   (área de toque 24). Como botón abre algo (un diálogo, un detalle);
   siempre con title y aria-label con el texto del estado.
   <button type="button" class="ds-icono-estado ds-icono-estado-aviso" title="Documento: Pendiente"
           aria-label="Documento: Pendiente"><i class="ti ti-file-alert" aria-hidden="true"></i></button>
   Tonos: -aviso (pendiente) · -info (en curso) · -exito (listo) ·
          -neutro (no aplica) · -error */
body.ui-v2 .ds-icono-estado {
    --ds-ie-fondo: var(--ds-neutro-fondo);
    --ds-ie-color: var(--ds-texto-2);
    position: relative;
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--ds-ie-fondo);
    color: var(--ds-ie-color);
    font-size: 14px;
    line-height: 1;
    text-decoration: none;
    vertical-align: middle;
    transition: background-color var(--ds-transicion), box-shadow var(--ds-transicion);
}
body.ui-v2 .ds-icono-estado > .ti,
body.ui-v2 .ds-icono-estado > .bi { font-size: 14px; line-height: 1; }
body.ui-v2 button.ds-icono-estado,
body.ui-v2 a.ds-icono-estado { cursor: pointer; }
body.ui-v2 button.ds-icono-estado::after,
body.ui-v2 a.ds-icono-estado::after {
    content: "";
    position: absolute;
    inset: -2px;
    border-radius: 50%;
}
body.ui-v2 button.ds-icono-estado:hover,
body.ui-v2 a.ds-icono-estado:hover,
body.ui-v2 .ds-icono-estado.ds-f-hover {
    background: color-mix(in srgb, var(--ds-ie-fondo) 82%, var(--ds-ie-color));
    color: var(--ds-ie-color);
}
body.ui-v2 .ds-icono-estado[aria-expanded="true"],
body.ui-v2 .ds-icono-estado.ds-f-activo { box-shadow: 0 0 0 2px var(--ds-superficie), 0 0 0 3px var(--ds-ie-color); }
body.ui-v2 .ds-icono-estado:focus-visible,
body.ui-v2 .ds-icono-estado.ds-f-foco { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 2px; }
body.ui-v2 .ds-icono-estado:disabled,
body.ui-v2 .ds-icono-estado[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }
body.ui-v2 .ds-icono-estado-aviso  { --ds-ie-fondo: var(--ds-aviso-fondo);  --ds-ie-color: var(--ds-aviso); }
body.ui-v2 .ds-icono-estado-info   { --ds-ie-fondo: var(--ds-info-fondo);   --ds-ie-color: var(--ds-info); }
body.ui-v2 .ds-icono-estado-exito  { --ds-ie-fondo: var(--ds-exito-fondo);  --ds-ie-color: var(--ds-exito); }
body.ui-v2 .ds-icono-estado-error  { --ds-ie-fondo: var(--ds-error-fondo);  --ds-ie-color: var(--ds-error); }
body.ui-v2 .ds-icono-estado-neutro { --ds-ie-fondo: var(--ds-neutro-fondo); --ds-ie-color: var(--ds-texto-2); }

/* Ícono enlace pequeño junto a un dato (p. ej. el PDF del SIAF):
   <a class="ds-icono-enlace" href="…" target="_blank" title="Abrir el PDF" aria-label="…"><i class="ti ti-file-type-pdf"></i></a> */
body.ui-v2 .ds-icono-enlace {
    position: relative;
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--ds-texto-3);
    font-size: 15px;
    line-height: 1;
    text-decoration: none;
    vertical-align: middle;
    cursor: pointer;
    transition: background-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .ds-icono-enlace > .ti,
body.ui-v2 .ds-icono-enlace > .bi { font-size: 15px; line-height: 1; }
body.ui-v2 .ds-icono-enlace::after { content: ""; position: absolute; inset: -2px; border-radius: 8px; }
body.ui-v2 .ds-icono-enlace:hover,
body.ui-v2 .ds-icono-enlace.ds-f-hover { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-icono-enlace:focus-visible,
body.ui-v2 .ds-icono-enlace.ds-f-foco { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 1px; color: var(--ds-acento-oscuro); }


/* 23f. Select en la celda y anillo de atención ---------------------------- */
/* <select class="form-select form-select-sm ds-select-celda" …>: 32 px,
   relleno corto (la flecha a 8 px, el texto a 4 px de ella) y "…" si el
   texto no cabe. Dentro de .ds-linea toma el espacio que queda junto a una
   etiqueta; ahí la etiqueta va más pegada (4 px) y un poco más angosta para
   que "Compra directa" + FR entren enteros en la columna .ds-col-control. */
body.ui-v2 .form-select.ds-select-celda {
    /* fase "todo": ancho por su opción más larga (así la columna nunca corta
       "Compra directa") y llena la celda si sobra; alto mínimo 32, crece con
       el texto */
    width: auto;
    min-width: 100%;
    max-width: 100%;
    height: auto;
    min-height: 32px;
    padding: 5px 24px 5px 10px;
    border-radius: 10px;
    background-position: right 8px center;
    background-size: 12px 9px;
    font-size: var(--ds-tam-tabla);
    line-height: 1.53847;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
body.ui-v2 .ds-linea > .form-select.ds-select-celda { flex: 1 1 auto; width: auto; min-width: auto; }
body.ui-v2 .ds-linea:has(> .form-select.ds-select-celda) { gap: 4px; }
body.ui-v2 .ds-linea > .form-select.ds-select-celda ~ .ds-etiqueta { padding: 0 5px; }
/* opción vacía elegida (p. ej. "Elegir…"): texto gris (solo, con :has; o con .ds-select-vacio) */
body.ui-v2 .form-select.ds-select-celda.ds-select-vacio,
body.ui-v2 .form-select.ds-select-celda:has(> option[value=""]:checked) { color: var(--ds-texto-2); }
body.ui-v2 .ds-select-celda option { color: var(--ds-texto); }
/* Anillo de atención: el control que la fila necesita (p. ej. la modalidad
   aún sin elegir). Fijo, no solo al enfocar; sin animación. Va en el
   control mismo (select, input o botón): <select class="… ds-atencion"> */
body.ui-v2 .ds-atencion,
body.ui-v2 .form-select.ds-atencion,
body.ui-v2 .form-control.ds-atencion {
    border-color: var(--ds-acento);
    box-shadow: 0 0 0 3px var(--ds-anillo);
}
body.ui-v2 .form-select.ds-atencion:hover:not(:disabled):not(:focus),
body.ui-v2 .form-control.ds-atencion:hover:not(:disabled):not(:focus),
body.ui-v2 .ds-atencion.ds-f-hover { border-color: var(--ds-acento-oscuro); }
body.ui-v2 .form-select.ds-atencion:focus,
body.ui-v2 .form-control.ds-atencion:focus,
body.ui-v2 .ds-atencion:focus-visible,
body.ui-v2 .ds-atencion.ds-f-foco {
    outline: none;
    border-color: var(--ds-acento-oscuro);
    box-shadow: 0 0 0 3px var(--ds-anillo-fuerte);
}


/* 23g. Popover ------------------------------------------------------------ */
/* Contenedor: el de Bootstrap con customClass: "ds-popover", o un elemento
   propio .ds-popover-flotante (lo posiciona el JS). Contenido:
   <div class="ds-popover-detalle">
     <div class="ds-popover-detalle-titulo">NOG 24582220 <span class="ds-pildora ds-pildora-sm ds-pildora-exito">Adjudicado</span></div>
     <dl class="ds-popover-detalle-lista"><dt>Datos al</dt><dd>25/09/2026 06:10</dd>…</dl>
     <ul class="ds-popover-detalle-items"><li class="ds-popover-detalle-apagado">…</li></ul>
     <p class="ds-popover-detalle-nota">…</p>
     <p class="ds-popover-detalle-error"><i class="ti ti-alert-triangle"></i>…</p>
   </div> */
body.ui-v2 .popover.ds-popover {
    --bs-popover-max-width: 340px;
    --bs-popover-font-size: var(--ds-tam-tabla);
    --bs-popover-border-radius: 14px;
    --bs-popover-inner-border-radius: 13px;
    --bs-popover-header-padding-x: 14px;
    --bs-popover-header-padding-y: 12px;
    --bs-popover-header-font-size: var(--ds-tam-tabla);
    --bs-popover-body-padding-x: 14px;
    --bs-popover-body-padding-y: 12px;
    --bs-popover-body-color: var(--ds-texto);
}
body.ui-v2 .popover.ds-popover .popover-header { padding-bottom: 0; }
body.ui-v2 .ds-popover-flotante {
    position: absolute;
    z-index: 1070;                 /* sobre menús (1040) y modales (1055), como los popovers de Bootstrap */
    max-width: min(340px, calc(100vw - 16px));
    padding: 12px 14px;
    border: 1px solid var(--ds-borde);
    border-radius: 14px;
    background: var(--ds-superficie);
    box-shadow: var(--ds-sombra-menu);
    color: var(--ds-texto);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    animation: ds-aparecer 150ms ease-out;
}
body.ui-v2 .ds-popover-flotante[hidden] { display: none; }
body.ui-v2 .ds-popover-detalle {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 200px;
    color: var(--ds-texto);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    text-align: left;
}
/* más fuerte que .popover-body p / ul de §14 (margen 8 y sangría 18) */
body.ui-v2 .popover-body .ds-popover-detalle > *,
body.ui-v2 .ds-popover-detalle > * { margin: 0; }
body.ui-v2 .ds-popover-detalle-titulo {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 8px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .ds-popover-detalle-lista {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: 4px 12px;
}
body.ui-v2 .ds-popover-detalle-lista > dt {
    margin: 0;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 400;
    line-height: 1.5;
    white-space: nowrap;
}
body.ui-v2 .ds-popover-detalle-lista > dd {
    margin: 0;
    color: var(--ds-texto);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}
body.ui-v2 .ds-popover-detalle .ds-popover-detalle-items,
body.ui-v2 .ds-popover-detalle-items {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 0;
    padding: 0;
    list-style: none;
}
body.ui-v2 .ds-popover-detalle-items > li {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 20px;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .ds-popover-detalle-items > li > .ds-num,
body.ui-v2 .ds-popover-detalle-items > li > .ds-celda-cifra { margin-left: auto; color: var(--ds-texto-2); }
body.ui-v2 .ds-popover-detalle-apagado { opacity: 0.66; }
/* botón dentro del detalle (p. ej. "Filtrar por este NOG" en pantallas táctiles) */
body.ui-v2 .ds-popover-detalle .ds-popover-detalle-accion { align-self: flex-start; margin-top: 4px; }
body.ui-v2 .ds-popover-detalle-nota {
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.33334;
}
body.ui-v2 .ds-popover-detalle-error {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    color: var(--ds-error);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.33334;
}
body.ui-v2 .ds-popover-detalle-error > .ti,
body.ui-v2 .ds-popover-detalle-error > .bi { flex: none; font-size: 14px; line-height: 1.14286; }
body.ui-v2 .ds-popover-detalle-separador { height: 1px; margin: 0; border: 0; background: var(--ds-borde); opacity: 1; }


/* 23h. Diálogos compactos ------------------------------------------------- */
/* En el .modal: .ds-modal-compacto (460 px: registrar número, motivo),
   .ds-modal-medio (600 px: historial), .ds-modal-amplio (1040 px: un
   formulario + una tabla, p. ej. Bases). Mismo aspecto: título 16/600 con
   ícono acento, relleno 20/24, cuerpo 14 px, avisos de una línea. Sin
   .modal-lg / .modal-xl (el ancho lo pone la clase). */
body.ui-v2 .modal.ds-modal-compacto { --bs-modal-width: 460px; }
body.ui-v2 .modal.ds-modal-medio { --bs-modal-width: 600px; }
body.ui-v2 .modal.ds-modal-amplio { --bs-modal-width: 1040px; }
body.ui-v2 .ds-modal-compacto .modal-dialog,
body.ui-v2 .ds-modal-medio .modal-dialog,
body.ui-v2 .ds-modal-amplio .modal-dialog { --bs-modal-width: inherit; }
body.ui-v2 .modal:is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) {
    --bs-modal-padding: 20px 24px;
    --bs-modal-header-padding: 20px 24px 0;
}
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) .modal-header { align-items: center; gap: var(--ds-e3); }
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) .modal-title {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    font-size: var(--ds-tam-seccion);
    font-weight: 600;
    line-height: 1.5;
}
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) .modal-title > .ti,
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) .modal-title > .bi {
    flex: none;
    margin: 0 !important;
    color: var(--ds-acento-oscuro);
    font-size: 20px;
    line-height: 1;
}
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) .modal-body {
    padding-top: 12px;
    padding-bottom: 8px;
    color: var(--ds-texto);
    font-size: var(--ds-tam-cuerpo);
}
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) .modal-footer { padding: 12px 24px 20px; }
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) .alert {
    margin: 12px 0;
    padding: 8px 12px;
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
/* aviso al inicio del cuerpo (franja de arriba): separado de lo que sigue */
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) .alert:first-child { margin-top: 0; }
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) .alert:last-child { margin-bottom: 0; }
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) .modal-body > .alert:first-child { margin-bottom: 16px; }
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) .alert[hidden] { display: none; }
body.ui-v2 :is(.ds-modal-compacto, .ds-modal-medio, .ds-modal-amplio) hr {
    margin: 16px 0;
    border: 0;
    border-top: 1px solid var(--ds-borde);
    opacity: 1;
}
/* línea de contexto bajo el título: "SIAF: ADM-23-2026, FYB-100-2026" */
body.ui-v2 .ds-modal-meta {
    margin: 0 0 12px;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    overflow-wrap: anywhere;
}
body.ui-v2 .ds-modal-meta strong,
body.ui-v2 .ds-modal-meta b { color: var(--ds-texto); font-weight: 600; }
/* lista corta de observaciones (p. ej. filas que no se pueden registrar) */
body.ui-v2 .ds-modal-lista {
    max-height: 132px;
    margin: 0 0 12px;
    padding: 8px 12px;
    overflow: auto;
    border-radius: var(--ds-radio-campo);
    background: var(--ds-neutro-fondo);
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    list-style: none;
}
body.ui-v2 .ds-modal-lista > li + li { margin-top: 4px; }
/* título de una sección dentro del diálogo ("Versiones", "Subir versión final") */
body.ui-v2 .ds-modal-seccion {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 8px;
    color: var(--ds-texto);
    font-size: var(--ds-tam-tabla);
    font-weight: 600;
    line-height: 1.38462;
}
/* error de una línea bajo el campo */
body.ui-v2 .ds-modal-error { margin: 8px 0 0; color: var(--ds-error); font-size: var(--ds-tam-tabla); line-height: 1.38462; }
/* amplio: formulario a la izquierda y tabla a la derecha */
body.ui-v2 .ds-modal-amplio .modal-body { padding-bottom: 20px; }
body.ui-v2 .ds-modal-amplio .form-text { margin-top: 4px; }
body.ui-v2 .ds-modal-amplio input[type="file"].form-control { padding-top: 6px; padding-bottom: 6px; }
/* el botón del selector de archivo, como un botón secundario del sistema (píldora con borde) en vez
   del gris del navegador */
body.ui-v2 input[type="file"].form-control::file-selector-button {
    height: 26px;
    margin: 0 10px 0 0;
    padding: 0 12px;
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-superficie);
    color: var(--ds-texto);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-tabla);
    font-weight: 500;
    cursor: pointer;
    transition: background-color var(--ds-transicion), border-color var(--ds-transicion);
}
body.ui-v2 input[type="file"].form-control:hover:not(:disabled):not([readonly])::file-selector-button {
    background: var(--ds-hover);
    border-color: var(--ds-borde-hover);
}
body.ui-v2 input[type="file"].form-control:disabled::file-selector-button { color: var(--ds-texto-3); cursor: not-allowed; }
/* tabla dentro del diálogo: marco de 12 px, filas de 36, 13 px, alto limitado */
body.ui-v2 .ds-modal-amplio .tb-v2 > .tb-marco,
body.ui-v2 .ds-modal-amplio .ds-tabla-marco,
body.ui-v2 .ds-modal-amplio .tb-marco {
    max-height: min(52vh, 440px);
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-campo);
    box-shadow: none;
    overflow: auto;
}
body.ui-v2 .ds-modal-amplio .ui-tabla > thead > tr > th { height: 32px; padding: 0 10px; }
body.ui-v2 .ds-modal-amplio .ui-tabla > tbody > tr > td {
    height: 36px;
    padding: 4px 10px;
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
body.ui-v2 .ds-modal-amplio .ui-tabla > thead > tr > th:first-child,
body.ui-v2 .ds-modal-amplio .ui-tabla > tbody > tr > td:first-child { padding-left: 12px; }
body.ui-v2 .ds-modal-amplio .ui-tabla > thead > tr > th:last-child,
body.ui-v2 .ds-modal-amplio .ui-tabla > tbody > tr > td:last-child { padding-right: 12px; }
body.ui-v2 .ds-modal-amplio .tb-v2 .ds-filtros,
body.ui-v2 .ds-modal-amplio .tb-barra { margin-bottom: 8px; }
/* Historial: lista de eventos con punto y línea (más reciente arriba)
   <ol class="ds-lista-eventos"><li>
       <div class="ds-evento-texto">Registró NOG 24582220</div>
       <div class="ds-evento-meta">25/09/2026 14:02 · Brandon Casia</div>
       <div class="ds-evento-detalle">Motivo: …</div></li></ol> */
body.ui-v2 .ds-lista-eventos {
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
body.ui-v2 .ds-lista-eventos > li {
    position: relative;
    padding: 0 0 14px 20px;
}
body.ui-v2 .ds-lista-eventos > li::before {
    content: "";
    position: absolute;
    top: 5px;
    left: 0;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--ds-acento);
}
body.ui-v2 .ds-lista-eventos > li::after {
    content: "";
    position: absolute;
    top: 17px;
    bottom: 1px;
    left: 3.5px;
    width: 1px;
    background: var(--ds-borde);
}
body.ui-v2 .ds-lista-eventos > li:not(:first-child)::before { background: var(--ds-borde-fuerte); }
body.ui-v2 .ds-lista-eventos > li:last-child { padding-bottom: 0; }
body.ui-v2 .ds-lista-eventos > li:last-child::after { display: none; }
body.ui-v2 .ds-evento-texto { color: var(--ds-texto); font-weight: 500; overflow-wrap: anywhere; }
body.ui-v2 .ds-evento-meta {
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.33334;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .ds-evento-detalle {
    margin-top: 2px;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.33334;
    overflow-wrap: anywhere;
}
body.ui-v2 .ds-modal-medio .modal-body:has(> .ds-lista-eventos) { max-height: min(64vh, 560px); overflow: auto; }


/* 23i. Barra de selección sobre la tabla ---------------------------------- */
/* <div class="ds-tabla-con-seleccion">
     <div id="…tabla…"></div>                        (TablaDatos)
     <div class="ds-barra-seleccion" hidden>…</div>  (macro barra_seleccion o igual marcado)
   </div>
   La barra (§19) deja de estar fija a la ventana: flota centrada sobre el
   borde de abajo de la tabla (pegada a la ventana si la tabla sigue más
   abajo). Mientras se ve, el marco de la tabla gana 76 px al final para
   que la última fila se pueda desplazar por encima de la barra. */
body.ui-v2 .ds-tabla-con-seleccion {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
}
body.ui-v2 .ds-tabla-con-seleccion > * {
    grid-area: 1 / 1;
    min-width: 0;
}
body.ui-v2 .ds-tabla-con-seleccion > .ds-barra-seleccion {
    position: sticky;
    right: auto;
    bottom: 16px;
    left: auto;
    z-index: 3;                    /* sobre filas y columnas fijas; bajo un menú "⋯" abierto (celda z 4) */
    align-self: end;
    justify-self: center;
    max-width: calc(100% - 32px);
    margin: 0 0 16px;
    padding: 0;
}
body.ui-v2 .ds-tabla-con-seleccion > .ds-barra-seleccion[hidden] { display: none; }
body.ui-v2 .ds-tabla-con-seleccion:has(> .ds-barra-seleccion:not([hidden])) .tb-marco::after {
    content: "";
    display: block;
    height: 76px;
}


/* 23j. Columnas fluidas (fase "todo") ------------------------------------ */
/* Queja del usuario: "desperdicia espacio horizontal" (una sola columna
   flexible se quedaba con todo el ancho que sobraba mientras las demás, de
   ancho fijo en px, cortaban "Compra dir…", "Pendiente O…"). Modelo nuevo,
   con el reparto automático de la tabla (table-layout: auto; ancho 100 %):
   - Columnas de CONTENIDO (.ds-col-id, -control, -numero, -numero-corto,
     -estado y las genéricas -corta, -media, -larga, -fecha, -monto): su
     contenido no se parte, así la columna mide lo que pide su texto y
     nunca corta un rótulo; un piso en em (--ds-col-min, crece con el
     texto) evita saltos con la tabla vacía o filtrada. El ancho que sobra
     se reparte entre todas en proporción a su ancho.
   - Columna FLEXIBLE (.ds-col-flex): una parte del ancho de la tabla
     (--ds-col-parte, 24 %) con piso (--ds-col-flex-min); su texto largo
     (proveedor) se recorta con "…" y va entero en title/popover. Si no
     cabe su parte, se queda con lo que dejan las demás (nunca menos que
     el piso).
   - Columna de TEXTO libre (.ds-col-texto): como la flexible pero el
     texto se parte en líneas (dos como máximo con .ds-texto-2-lineas).
   - Acciones: .ds-celda-acciones (§15a: lo justo para su contenido, fija a
     la derecha) + .ds-col-acciones (piso de la acción más larga).
   - .ds-col-ajustada: lo justo para su contenido (casillas, íconos).
   En la opción `clase` de la columna de TablaDatos (TablaDatos v2 copia
   las .ds-col-* al <th>) o directamente en <th>/<td> de una tabla hecha a
   mano. No usar `ancho` en px junto con estas clases.
   .ds-solo-ancho: pieza que solo se ve desde 1400 px de ventana.
   Pisos (contenido, sin relleno; 1em = 13 px en la tabla):
     id 12em (156) · control 11em · numero 14em · numero-corto 6em ·
     estado 8em · acciones 11.25em · corta 4em · media 8em · larga 14em ·
     fecha 6.5em · monto 7em · flex 7em (6em bajo 1400) · texto 12em. */
body.ui-v2 :is(.ui-tabla, .ds-tabla) { width: 100%; table-layout: auto; }
body.ui-v2 .ds-col-id { --ds-col-min: 12em; }
body.ui-v2 .ds-col-control { --ds-col-min: 11em; }
body.ui-v2 .ds-col-numero { --ds-col-min: 14em; }
body.ui-v2 .ds-col-numero-corto { --ds-col-min: 6em; }
body.ui-v2 .ds-col-estado { --ds-col-min: 8em; }
body.ui-v2 .ds-col-acciones { --ds-col-min: 11.25em; }
body.ui-v2 .ds-col-corta { --ds-col-min: 4em; }
body.ui-v2 .ds-col-media { --ds-col-min: 8em; }
body.ui-v2 .ds-col-larga { --ds-col-min: 14em; }
body.ui-v2 .ds-col-fecha { --ds-col-min: 6.5em; }
body.ui-v2 .ds-col-monto { --ds-col-min: 7em; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody, tfoot) > tr > :is(th, td):is(.ds-col-id, .ds-col-control, .ds-col-numero, .ds-col-numero-corto, .ds-col-estado, .ds-col-acciones, .ds-col-corta, .ds-col-media, .ds-col-larga, .ds-col-fecha, .ds-col-monto, .ds-col-ajustada) {
    white-space: nowrap;
}
/* piso: bloque de alto 0 con el ancho mínimo (min-width en celdas de tabla no
   lo respetan igual WebKit y Blink; un contenido de ese ancho sí) */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody, tfoot) > tr > :is(th, td):is(.ds-col-id, .ds-col-control, .ds-col-numero, .ds-col-numero-corto, .ds-col-estado, .ds-col-acciones, .ds-col-corta, .ds-col-media, .ds-col-larga, .ds-col-fecha, .ds-col-monto)::after {
    content: "";
    display: block;
    width: var(--ds-col-min);
    height: 0;
}
/* en el encabezado el piso se mide con la letra de la tabla (13 px), no la del th (12 px) */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > thead > tr > th[class*="ds-col-"]::after { font-size: 13px; }
body.ui-v2 .ds-col-monto,
body.ui-v2 :is(.ui-tabla, .ds-tabla) .ds-col-monto { text-align: right; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-col-fecha { font-variant-numeric: tabular-nums; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-ajustada { width: 1%; }
/* texto largo DENTRO de una columna de contenido (p. ej. los renglones en la
   segunda línea del SIAF): tope en ch, se recorta con "…" pasado el tope */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td:not(.ds-col-flex):not(.ds-col-texto) .ds-celda-texto { max-width: var(--ds-texto-max, 16ch); }
/* flexible: una parte fija del ancho; el contenido no empuja (mide 0 y llena la celda) */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-flex { width: var(--ds-col-parte, 24%); }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.ds-col-flex > * {
    width: 0;
    min-width: 100%;
}
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-flex::after {
    content: "";
    display: block;
    width: var(--ds-col-flex-min, 7em);
    height: 0;
}
body.ui-v2 :is(.ui-tabla, .ds-tabla) > thead > tr > th.ds-col-flex::after { font-size: 13px; }
/* texto libre que se parte en líneas (descripción, proveedor en tablas sin prisa) */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-texto { width: var(--ds-col-parte, 30%); }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.ds-col-texto { white-space: normal; overflow-wrap: anywhere; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.ds-col-texto::after {
    content: "";
    display: block;
    width: var(--ds-col-texto-min, 12em);
    height: 0;
}
/* dos líneas como máximo, con "…" al final de la segunda (texto completo en title) */
body.ui-v2 .ds-texto-2-lineas {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    white-space: normal;
    overflow-wrap: anywhere;
}
/* casilla de selección: 4 px a su derecha (no 12) */
body.ui-v2 .ui-tabla > thead > tr > th:has(> .tb-sel-todos),
body.ui-v2 .ui-tabla > tbody > tr > td:has(> .tb-sel) { padding-right: 4px; }
/* Contenido angosto: se mide el ANCHO DEL CONTENIDO (consulta de contenedor
   sobre main.ds-contenido), no la ventana: así también vale con el riel
   expandido (240 px) o con el zoom del navegador. Menos de 1272 px de
   contenido (una ventana de 1280-1399 con el riel delgado): relleno lateral
   de 10 px y pisos menores; menos de 1150: 8 px y los textos largos de las
   columnas de contenido con tope de 10ch. Si aun así no cabe, la tabla se
   desplaza de lado dentro de su marco (acciones fijas a la derecha). */
body.ui-v2 .ds-contenido { container: contenido / inline-size; }
@container contenido (max-width: 1271.98px) {
    body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td):not(:first-child):not(:last-child) { padding-left: 10px; padding-right: 10px; }
    body.ui-v2 :is(.ui-tabla, .ds-tabla) { --ds-col-flex-min: 6em; }
    body.ui-v2 .ds-numero { gap: 4px; }
    body.ui-v2 .ds-solo-ancho { display: none !important; }
}
@container contenido (max-width: 1149.98px) {
    body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td):not(:first-child):not(:last-child) { padding-left: 8px; padding-right: 8px; }
    body.ui-v2 :is(.ui-tabla, .ds-tabla) { --ds-col-flex-min: 5em; --ds-texto-max: 10ch; }
    body.ui-v2 .ds-celda-principal,
    body.ui-v2 .ds-numero { gap: 4px; }
}


/* 23k. Movimiento reducido e impresión ------------------------------------ */
@media (prefers-reduced-motion: reduce) {
    body.ui-v2 .ds-mas,
    body.ui-v2 .ds-numero-valor,
    body.ui-v2 .ds-icono-estado,
    body.ui-v2 .ds-icono-enlace { transition: none; }
    body.ui-v2 .ds-popover-flotante { animation: none; }
}
@media print {
    body.ui-v2 .ds-popover-flotante,
    body.ui-v2 .ds-tabla-con-seleccion > .ds-barra-seleccion { display: none !important; }
    body.ui-v2 .ds-atencion { box-shadow: none; }
}


/* 23l. Tablas parejas (Paso 3, 2026-09-30) ------------------------------- */
/* Pedido del usuario: "tablas parejas" en toda la app. Reglas (CLAUDE.md §4,
   "Tablas parejas"; muestra en /estilo §9, «Tablas parejas»):
   1. FILAS DEL MISMO ALTO dentro de una tabla. Compacta: 40 px de mínimo
      (§15a). Una tabla con SEGUNDA LÍNEA (celda de dos líneas, texto libre que
      se parte en dos, nombre comercial bajo la razón social…) lleva
      .ds-tabla-2-lineas y TODAS sus filas miden lo de dos líneas: 45 px (dos
      líneas de 17 + 10 de relleno + 1 de línea; una celda de dos líneas de 17
      + 16 cabe), en em para que crezca con el texto.
      Ninguna celda pasa de dos líneas: el texto libre va en .ds-texto-2-lineas
      (dos líneas con "…" y el texto entero en title), los nombres y textos
      cortos en una línea con "…" (.ds-celda-texto, title).
   2. ACCIONES: la acción visible de la fila mide lo mismo en todas las filas
      de la tabla (mínimo común en em, texto centrado) y el "⋯" queda alineado;
      una fila sin "⋯" deja su hueco. El ancho lo elige la tabla:
      .ds-acciones-corta ("Ver", "Editar"), sin clase (hasta "Recibir"),
      .ds-acciones-media ("Crear acta", "Continuar" con ícono),
      .ds-acciones-larga ("Registrar NOG"),
      .ds-acciones-agregar ("Agregar" / "En el listado" del catálogo; solo el
      ícono cuando el contenido mide menos de 1272 px) o .ds-acciones-ancha
      ("No pedir descripción"). Sin "⋯" en ninguna fila: .ds-acciones-sin-menu. La
      columna (th .ds-col-acciones) mide eso más el "⋯": ancho fijo en em,
      alineada a la derecha.
   3. NÚMEROS (montos, cantidades, existencias, porcentajes) a la derecha con
      cifras tabulares (.ds-col-monto / alinear "num"); CÓDIGOS (SIAF, NOG,
      OC, NIT) con cifras tabulares, a la izquierda. Toda la tabla usa
      tabular-nums (§15a).
   4. Cada <th> con UNA clase .ds-col-* (§23j) y ningún ancho en px.
   5. Píldoras: una sola medida (§7). En la segunda línea gris de una celda
      no va una píldora sino texto con color: .ds-celda-alerta. */
body.ui-v2 .tb-densidad-compacta :is(.ui-tabla, .ds-tabla).ds-tabla-2-lineas > tbody > tr > td,
body.ui-v2 .ds-tabla-compacta.ds-tabla-2-lineas > tbody > tr > td {
    height: calc(3.3846em + 1px);   /* 45 px con 13 px: dos líneas de 17 + 2 × 5 de relleno + la línea */
}
/* segunda línea que puede llevar una marca de 18 px (píldora de contrato
   abierto, etiqueta "Verificar…"): la fila de dos líneas mide 46 (17 + 18 + 11) */
body.ui-v2 .tb-densidad-compacta :is(.ui-tabla, .ds-tabla).ds-tabla-2-lineas.ds-segunda-con-marca > tbody > tr > td,
body.ui-v2 .ds-tabla-compacta.ds-tabla-2-lineas.ds-segunda-con-marca > tbody > tr > td { height: calc(3.4616em + 1px); }
/* tabla en un panel lateral angosto (Guardados del catálogo, 560 px): el texto libre cede antes */
body.ui-v2 .ds-panel-tabla .ds-tabla { --ds-col-texto-min: 8em; }
body.ui-v2 .ds-celda > .ds-celda-linea-marca {
    display: flex;
    align-items: center;
    gap: 0.5em;
    min-width: 0;
    max-width: 100%;
    height: 1.5em;                  /* 18 px con 12 px: lo de una píldora */
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.33334;
    white-space: nowrap;
}
body.ui-v2 .ds-celda-linea-marca > * { flex: none; }
body.ui-v2 .ds-celda-linea-marca > .ds-celda-texto { flex: 0 1 auto; }
body.ui-v2 .ds-celda-linea-marca > .ds-marca-contrato { display: inline-flex; margin-top: 0; }
/* la celda de texto libre: nunca más de dos líneas */
body.ui-v2 .ds-tabla-2-lineas > tbody > tr > td > .ds-texto-2-lineas { line-height: 1.3077; }
/* acción visible: ancho mínimo común por tabla, texto centrado */
body.ui-v2 :is(.ui-tabla, .ds-tabla) { --ds-accion-ancho: 6.5em; }
body.ui-v2 :is(.ui-tabla, .ds-tabla).ds-acciones-corta { --ds-accion-ancho: 4.5em; }
body.ui-v2 :is(.ui-tabla, .ds-tabla).ds-acciones-media { --ds-accion-ancho: 8.6em; }   /* "Crear acta" con su ícono */
body.ui-v2 :is(.ui-tabla, .ds-tabla).ds-acciones-larga { --ds-accion-ancho: 9em; }
body.ui-v2 :is(.ui-tabla, .ds-tabla).ds-acciones-agregar { --ds-accion-ancho: 10em; }
body.ui-v2 :is(.ui-tabla, .ds-tabla).ds-acciones-ancha { --ds-accion-ancho: 13.5em; }   /* "No pedir descripción" (Renglones) */
@container contenido (max-width: 1271.98px) {
    body.ui-v2 :is(.ui-tabla, .ds-tabla).ds-acciones-agregar { --ds-accion-ancho: 3.4em; }   /* solo el ícono (.ds-solo-ancho) */
}
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.ds-celda-acciones .ds-btn:not(.ds-btn-icono):not(.ds-btn-mini) {
    min-width: var(--ds-accion-ancho);
    justify-content: center;
}
/* dos acciones visibles que son formularios (Renglones): una al lado de la otra, no apiladas (la fila medía 75) */
body.ui-v2 td.ds-celda-acciones > form { display: inline-block; vertical-align: middle; }
body.ui-v2 td.ds-celda-acciones > form + form { margin-left: var(--ds-e1, 4px); }
/* el "⋯" (32 px) o su hueco: en una fila sin más acciones el botón no se corre */
body.ui-v2 td.ds-celda-acciones .ds-acciones-fila:not(:has(> .ds-menu-acciones, > .ds-acciones-hueco))::after {
    content: "";
    flex: none;
    /* + el lugar de Historial / Descargar si otra fila de la tabla los tiene y esta (sin "⋯") no (2026-10-17) */
    width: calc(32px + var(--ds-falta-historial, 0px) + var(--ds-falta-descargar, 0px));
    height: 1px;
    margin-left: 2px;
}
/* columna de acciones: ancho fijo en em = la acción + el "⋯", a la derecha */
body.ui-v2 :is(.ui-tabla, .ds-tabla) { --ds-menu-ancho: 38px; }   /* "⋯" de 32 + 4 de separación + 2 de margen */
body.ui-v2 :is(.ui-tabla, .ds-tabla).ds-acciones-sin-menu { --ds-menu-ancho: 0px; }   /* columna con un solo botón (Detalle) */
body.ui-v2 :is(.ui-tabla, .ds-tabla) .ds-col-acciones { --ds-col-min: calc(var(--ds-accion-ancho) + var(--ds-menu-ancho) + var(--ds-fija-historial) + var(--ds-fija-descargar)); text-align: right; }
/* Historial y Descargar a la vista (2026-10-17; app/acciones_fila.py y UI.htmlMenuAcciones): botón de ícono de 32 px
   junto a la acción visible. El hueco de una clase que la fila no tiene mide lo mismo, pero solo aparece si alguna fila
   de la MISMA tabla la tiene: así la acción, los íconos y el "⋯" quedan alineados; la columna suma 36 px por clase. */
body.ui-v2 .ds-fija-hueco { display: none; flex: none; width: 32px; height: 1px; }
body.ui-v2 :is(.ui-tabla, .ds-tabla):has(.ds-accion-fija.ds-fija-historial) .ds-acciones-fila:not(:has(.ds-fija-historial)) { --ds-falta-historial: 36px; }
body.ui-v2 :is(.ui-tabla, .ds-tabla):has(.ds-accion-fija.ds-fija-descargar) .ds-acciones-fila:not(:has(.ds-fija-descargar)) { --ds-falta-descargar: 36px; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) { --ds-fija-historial: 0px; --ds-fija-descargar: 0px; }
body.ui-v2 :is(.ui-tabla, .ds-tabla):has(.ds-accion-fija.ds-fija-historial) { --ds-fija-historial: 36px; }
body.ui-v2 :is(.ui-tabla, .ds-tabla):has(.ds-accion-fija.ds-fija-descargar) { --ds-fija-descargar: 36px; }
body.ui-v2 :is(.ui-tabla, .ds-tabla):has(.ds-accion-fija.ds-fija-historial) .ds-fija-hueco.ds-fija-historial,
body.ui-v2 :is(.ui-tabla, .ds-tabla):has(.ds-accion-fija.ds-fija-descargar) .ds-fija-hueco.ds-fija-descargar { display: inline-block; }
/* aviso en la SEGUNDA línea de una celda (evento desierto, subproductos no
   habilitados): texto con el color del estado y un punto, del alto de la línea
   (una píldora de 18 px no cabe en la línea gris de 16 y agrandaría la fila) */
body.ui-v2 .ds-celda-alerta {
    display: inline-flex;
    align-items: center;
    gap: 0.3334em;
    max-width: 100%;
    border-radius: var(--ds-radio-item);
    color: var(--ds-error);
    font-weight: 500;
    white-space: nowrap;
}
body.ui-v2 .ds-celda-alerta::before {
    content: "";
    flex: none;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
}
body.ui-v2 .ds-celda-alerta + .ds-celda-alerta { margin-left: 0.6667em; }
body.ui-v2 .ds-celda-alerta-aviso { color: var(--ds-aviso); }
body.ui-v2 .ds-celda-alerta[tabindex]:focus-visible { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 1px; }


/* 24. Componentes de pantalla (fase "todo") ===============================
   Piezas genéricas que piden las pantallas que faltan migrar. Macros en
   templates/_ds.html (ejemplo de uso en su comentario inicial); guía corta
   en todo_componentes.md. Todas las medidas de texto son mínimas o en em
   (crecen si el navegador agranda el texto).
     24a. Barra de filtros del servidor (formularios GET)
     24b. Tarjeta de sección (título + acciones) y panel viejo
     24c. Lista de datos (rótulo / valor)
     24d. Formularios: grilla, grupos, pie fijo, formulario con lateral
     24e. Carga de archivo: compacta, fila de carga, nombre elegido
     24f. Línea de tiempo (historial)
     24g. Pestañas de página (enlaces)
     24h. Paginación del servidor
     24i. Página de error (403/404) e inicio de sesión
     24j. Indicadores: barra de avance, variación, grilla compacta
     24k. Avisos con acción
     24l. Gráficos (contenedor)
     24m. Utilidades de maquetación
     24n. Chips de casilla, filas teñidas, tabla estática en marco, visor,
          "Volver", barra de distribución, código y teclas
   ========================================================================== */


/* 24a. Barra de filtros del servidor -------------------------------------- */
/* Para listas filtradas en el SERVIDOR (lista de SIAF, Órdenes de Compra,
   Proveedores, precios, capturas, administración, historial de
   Actualización): el mismo <form method="get"> de siempre, con los mismos
   nombres de campo, pintado como la barra de TablaDatos. Chips = enlaces con
   la URL actual cambiando un parámetro (sin JS); píldoras = desplegables con
   los campos del formulario adentro y "Aplicar"; su ✕ es un enlace sin esos
   parámetros; "Quitar filtros" = enlace a la lista sin filtros.
   <form class="ds-filtros ds-filtros-get" method="get" role="search">
     <div class="ds-filtros-fila">…chips…</div>
     <div class="ds-filtros-fila">…píldoras, buscador, Quitar filtros…</div>
   </form> */
/* Una sola COLUMNA de filas sin partirse (flex-wrap: nowrap, aunque .ds-filtros
   de §6a parta en líneas): en una columna que se parte, cada fila medía lo que
   pide su contenido y no el ancho del formulario (en el teléfono la fila de
   chips que se desplaza de lado medía 1100 px y agrandaba la página; con un
   select largo, 237 px de más). */
body.ui-v2 .ds-filtros-get {
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: var(--ds-e2);
    margin: 0 0 var(--ds-e3);
}
body.ui-v2 .ds-filtros-fila {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2);
    min-width: 0;
}
body.ui-v2 .ds-filtros-fila > .ds-filtros-fin {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2);
    margin-left: auto;
}
/* chip como enlace: mismo aspecto que el botón */
body.ui-v2 a.ds-chip:focus-visible { outline: 0; box-shadow: var(--tb-anillo); }
body.ui-v2 a.ds-chip.ds-chip-activo,
body.ui-v2 a.ds-chip[aria-current="true"],
body.ui-v2 a.ds-chip[aria-current="page"] {
    border-color: var(--ds-relleno-primario);
    background: var(--ds-relleno-primario);
    color: var(--ds-texto-sobre-relleno);
}
body.ui-v2 a.ds-chip[aria-current="true"] .ds-chip-conteo,
body.ui-v2 a.ds-chip[aria-current="page"] .ds-chip-conteo { color: var(--ds-texto-sobre-relleno-2); }
body.ui-v2 a.ds-chip.ds-chip-activo:hover,
body.ui-v2 a.ds-chip[aria-current="true"]:hover { border-color: var(--tb-relleno-hover); background: var(--tb-relleno-hover); color: var(--ds-texto-sobre-relleno); }
/* ✕ y "Quitar filtros" como enlaces */
body.ui-v2 a.ds-pildora-filtro-quitar,
body.ui-v2 a.ds-quitar-filtros { color: var(--ds-acento-oscuro); text-decoration: none; }
body.ui-v2 a.ds-pildora-filtro-quitar { color: inherit; }
body.ui-v2 a.ds-pildora-filtro-quitar:focus-visible { outline: 0; box-shadow: var(--tb-anillo); }
/* pie del panel de una píldora: "Aplicar" (y "Limpiar" como enlace) */
body.ui-v2 .ds-pildora-panel-pie {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--ds-e2);
    margin-top: var(--ds-e3);
    padding-top: var(--ds-e3);
    border-top: 1px solid var(--ds-borde);
}
body.ui-v2 .ds-pildora-panel-pie > .ds-pildora-panel-limpiar { margin-right: auto; font-size: var(--ds-tam-tabla); font-weight: 500; text-decoration: none; }
body.ui-v2 .ds-pildora-panel .ds-campo { margin-bottom: var(--ds-e3); }
body.ui-v2 .ds-pildora-panel .ds-campo:last-child { margin-bottom: 0; }
body.ui-v2 .ds-menu-filtro.ds-pildora-panel-ancho { min-width: 300px; max-width: 360px; }
/* casillas de un panel (varios valores): lista con desplazamiento */
body.ui-v2 .ds-pildora-panel .ds-casillas {
    display: flex;
    flex-direction: column;
    max-height: 260px;
    margin: 0 -4px;
    overflow-y: auto;
}
body.ui-v2 .ds-pildora-panel .ds-casillas > .form-check,
body.ui-v2 .ds-pildora-panel .ds-casillas > label {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 34px;
    margin: 0;
    padding: 6px 8px;
    border-radius: 10px;
    cursor: pointer;
}
body.ui-v2 .ds-pildora-panel .ds-casillas > :hover { background: var(--ds-hover); }
body.ui-v2 .ds-pildora-panel .ds-casillas .form-check-input { float: none; margin: 0; }
/* select nativo con forma de píldora (un filtro de un solo valor):
   <select class="ds-pildora-select" name="estado" data-ds-enviar-al-cambiar> */
body.ui-v2 .ds-pildora-select {
    min-height: var(--ds-alto-chip);
    max-width: 100%;
    padding: 0 34px 0 14px;
    border: 1px solid var(--ds-borde-fuerte);   /* Corrección 2: borde de control (3:1) */
    border-radius: var(--ds-radio-pildora);
    background: var(--tb-pildora-fondo) url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23595959' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m4 6 4 4 4-4'/%3e%3c/svg%3e") no-repeat right 12px center / 14px 14px;
    color: var(--ds-texto);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-tabla);
    font-weight: 500;
    line-height: 1.38462;
    appearance: none;
    -webkit-appearance: none;
    cursor: pointer;
    transition: background-color var(--ds-transicion), box-shadow var(--ds-transicion);
}
body.ui-v2 .ds-pildora-select:hover,
body.ui-v2 .ds-pildora-select.ds-f-hover { background-color: var(--tb-pildora-hover); border-color: var(--tb-borde-hover); }
body.ui-v2 .ds-pildora-select:focus-visible,
body.ui-v2 .ds-pildora-select.ds-f-foco { outline: 0; box-shadow: var(--tb-anillo); }
body.ui-v2 .ds-pildora-select.ds-pildora-select-activa,
body.ui-v2 .ds-pildora-select.ds-f-activo {
    border-color: var(--ds-acento);
    background-color: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%231a6fa0' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m4 6 4 4 4-4'/%3e%3c/svg%3e");
}
body.ui-v2 .ds-pildora-select:disabled { color: var(--ds-texto-3); cursor: not-allowed; }
/* buscador de la barra (campo de texto del formulario GET) */
body.ui-v2 .ds-buscador-get {
    position: relative;
    display: inline-flex;
    align-items: center;
    flex: 0 1 auto;
    width: 280px;              /* ancho, no flex-basis: con base de 280 la fila se medía en dos líneas */
    min-width: 180px;
    max-width: 100%;
    margin: 0;
}
body.ui-v2 .ds-buscador-get > .ti {
    position: absolute;
    left: 12px;
    color: var(--ds-texto-3);
    font-size: 16px;
    pointer-events: none;
}
body.ui-v2 .ds-buscador-get > input {
    width: 100%;
    min-height: var(--ds-alto-chip);
    padding: 0 14px 0 36px;
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-superficie);
    color: var(--ds-texto);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    transition: border-color var(--ds-transicion), box-shadow var(--ds-transicion);
}
body.ui-v2 .ds-buscador-get > input::placeholder { color: var(--ds-texto-2); opacity: 1; }
body.ui-v2 .ds-buscador-get > input:hover { border-color: var(--tb-borde-hover); }
body.ui-v2 .ds-buscador-get > input:focus { border-color: var(--ds-acento); box-shadow: var(--tb-anillo-campo); outline: 0; }
body.ui-v2 .ds-buscador-get.ds-buscador-activo > input { border-color: var(--ds-acento); background: var(--ds-acento-claro); }
/* botón "Filtrar" del formulario (visible: sirve sin JavaScript) */
body.ui-v2 .ds-filtros-enviar { min-height: var(--ds-alto-chip); }
/* contador de resultados junto a los filtros ("214 SIAF") */
body.ui-v2 .ds-filtros-conteo { color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-filtros-get .ds-filtros-fila:first-child {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
        margin: 0 calc(-1 * var(--ds-margen-pagina));
        padding: 0 var(--ds-margen-pagina) 2px;
    }
    body.ui-v2 .ds-filtros-get .ds-filtros-fila:first-child::-webkit-scrollbar { display: none; }
    /* la primera fila solo se desplaza de lado cuando tiene chips; una de
       píldoras o buscadores (o marcada .ds-filtros-fila-envuelve) se parte en
       líneas como las demás */
    body.ui-v2 .ds-filtros-get .ds-filtros-fila:first-child:not(:has(.ds-chip)),
    body.ui-v2 .ds-filtros-get .ds-filtros-fila.ds-filtros-fila-envuelve {
        flex-wrap: wrap;
        overflow-x: visible;
        margin: 0;
        padding: 0;
    }
    /* fila de chips de estado seguidos de píldoras: los chips en una línea
       que se desplaza de lado (como la barra de TablaDatos, §22b) y las
       píldoras debajo */
    body.ui-v2 .ds-filtros-get .ds-filtros-fila:has(> .ds-pildora-filtro) > .ds-chips:first-child {
        flex: 0 1 100%;
        flex-wrap: nowrap;
        max-width: 100%;
        overflow-x: auto;
        scrollbar-width: none;
    }
    body.ui-v2 .ds-filtros-get .ds-filtros-fila:has(> .ds-pildora-filtro) > .ds-chips:first-child::-webkit-scrollbar { display: none; }
    body.ui-v2 .ds-buscador-get { flex: 1 1 auto; width: 100%; }
    body.ui-v2 .ds-filtros-fila > .ds-filtros-fin { margin-left: 0; }
}


/* 24b. Tarjeta de sección ------------------------------------------------- */
/* Reemplaza las bandas azul marino: superficie blanca, radio 16, título 16/600
   y acciones a la derecha, sin banda de color.
   <section class="ds-tarjeta">
     <header class="ds-tarjeta-cabeza">
       <div class="ds-tarjeta-titulos"><h2 class="ds-tarjeta-titulo">Historial</h2>
         <p class="ds-tarjeta-linea">Una línea, como máximo.</p></div>
       <div class="ds-tarjeta-acciones">…botones…</div>
     </header>
     <div class="ds-tarjeta-cuerpo">…</div>
     <footer class="ds-tarjeta-pie">…</footer>
   </section>
   .ds-tarjeta-plana (cuerpo sin relleno: tabla hasta el borde, con línea
   bajo la cabeza). El panel viejo (_ui_macros.panel) se ve igual (§10). */
body.ui-v2 .ds-tarjeta {
    display: flex;
    flex-direction: column;
    min-width: 0;
    margin-bottom: var(--ds-e5);
    background: var(--ds-superficie);
    border: 1px solid var(--ds-borde-marco);
    border-radius: var(--ds-radio-tarjeta);
    box-shadow: var(--ds-sombra-tarjeta);
}
body.ui-v2 .ds-tarjeta:last-child { margin-bottom: 0; }
body.ui-v2 .ds-pila > .ds-tarjeta,
body.ui-v2 .ds-grilla > .ds-tarjeta { margin-bottom: 0; }
body.ui-v2 .ds-tarjeta-cabeza {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2) var(--ds-e3);
    padding: var(--ds-e4) 20px 0;
}
body.ui-v2 .ds-tarjeta-titulos {
    display: flex;
    flex: 1 1 240px;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: var(--ds-e2);
    min-width: 0;
}
body.ui-v2 .ds-tarjeta-titulo {
    margin: 0;
    color: var(--ds-texto);
    font-size: var(--ds-tam-seccion);
    font-weight: 600;
    line-height: 1.5;
    letter-spacing: -0.006em;
}
body.ui-v2 .ds-tarjeta-linea,
body.ui-v2 .ds-tarjeta-contador {
    min-width: 0;
    margin: 0;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .ds-tarjeta-linea { flex-basis: 100%; }
body.ui-v2 .ds-tarjeta-numero {
    flex: none;
    display: inline-grid;
    place-items: center;
    min-width: 24px;
    height: 24px;
    padding: 0 6px;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 600;
    align-self: center;
}
body.ui-v2 .ds-tarjeta-icono { flex: none; align-self: center; color: var(--ds-texto-2); font-size: 20px; line-height: 1; }
body.ui-v2 .ds-tarjeta-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2);
    margin-left: auto;
}
body.ui-v2 .ds-tarjeta-cuerpo { flex: 1 1 auto; min-width: 0; padding: var(--ds-e4) 20px 20px; }
body.ui-v2 .ds-tarjeta-cuerpo > :last-child { margin-bottom: 0; }
body.ui-v2 .ds-tarjeta-pie {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--ds-e2);
    padding: var(--ds-e3) 20px;
    border-top: 1px solid var(--ds-borde);
}
/* plana: la tabla (o lista) toca los bordes; la cabeza lleva su línea */
body.ui-v2 .ds-tarjeta-plana > .ds-tarjeta-cabeza { padding-bottom: var(--ds-e3); border-bottom: 1px solid var(--ds-borde); }
body.ui-v2 .ds-tarjeta-plana > .ds-tarjeta-cuerpo { padding: 0; }
body.ui-v2 .ds-tarjeta-plana > .ds-tarjeta-cuerpo > .table-responsive,
body.ui-v2 .ds-tarjeta-plana > .ds-tarjeta-cuerpo > .ds-tabla-marco { border: 0; border-radius: 0 0 calc(var(--ds-radio-tarjeta) - 1px) calc(var(--ds-radio-tarjeta) - 1px); box-shadow: none; }
body.ui-v2 .ds-tarjeta-plana > .ds-tarjeta-cuerpo > .ds-vacio { padding: 40px 16px; }
/* sin cabeza: el cuerpo lleva el relleno de arriba */
body.ui-v2 .ds-tarjeta > .ds-tarjeta-cuerpo:first-child { padding-top: 20px; }
body.ui-v2 .ds-tarjeta-plana > .ds-tarjeta-cuerpo:first-child { padding-top: 0; }
/* plana sin cabeza: la tabla es lo de arriba de la tarjeta y redondea también
   las esquinas de arriba (si no, el encabezado de la tabla quedaba en escuadra
   dentro de la tarjeta redonda: Usuarios, Proveedores, Renglones, Unidades) */
body.ui-v2 .ds-tarjeta-plana > .ds-tarjeta-cuerpo:first-child > :is(.table-responsive, .ds-tabla-marco):first-child { border-radius: calc(var(--ds-radio-tarjeta) - 1px); }
/* acento de estado (falta / listo), como el borde del panel viejo */
body.ui-v2 .ds-tarjeta.ds-tarjeta-aviso { border-color: var(--ds-aviso-borde); }
body.ui-v2 .ds-tarjeta.ds-tarjeta-exito { border-color: var(--ds-exito-borde); }
body.ui-v2 .ds-tarjeta.ds-tarjeta-activa { border-color: var(--ds-acento); box-shadow: 0 0 0 1px var(--ds-acento); }
/* panel viejo: cuerpo con el mismo relleno que la tarjeta nueva */
body.ui-v2 .ui-panel > .card-body { padding: var(--ds-e4) 20px 20px; }
body.ui-v2 .ui-panel > .card-body.p-0 { padding: 0 !important; }
body.ui-v2 .ui-panel > .card-body.p-0 > .table-responsive:last-child .table { margin-bottom: 0; }


/* 24c. Lista de datos (rótulo / valor) ------------------------------------ */
/* Para fichas y detalles (OC, SIAF, artículo): rótulo 12/500 gris arriba,
   valor 14 abajo; columnas que se acomodan solas (mín. 200 px).
   <dl class="ds-datos"><div class="ds-dato"><dt>NIT</dt><dd>1234567-8</dd></div>…</dl>
   .ds-datos-2 / -3 / -4: columnas fijas desde tableta. .ds-datos-lista: una
   fila por dato (rótulo a la izquierda, valor a la derecha, línea fina),
   como la tabla de tarifas de la referencia. .ds-dato-ancho: ocupa la fila. */
body.ui-v2 .ds-datos {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: var(--ds-e4) var(--ds-e5);
    margin: 0;
}
body.ui-v2 .ds-dato { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
body.ui-v2 .ds-dato > dt {
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 500;
    line-height: 1.33334;
}
body.ui-v2 .ds-dato > dd {
    margin: 0;
    color: var(--ds-texto);
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.42858;
    overflow-wrap: anywhere;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .ds-dato > dd.ds-dato-fuerte,
body.ui-v2 .ds-dato-fuerte > dd { font-weight: 600; }
body.ui-v2 .ds-dato > dd .ds-texto-suave { font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-dato-vacio > dd { color: var(--ds-texto-2); }
body.ui-v2 .ds-dato-ancho { grid-column: 1 / -1; }
@media (min-width: 768px) {
    body.ui-v2 .ds-datos-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    body.ui-v2 .ds-datos-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    body.ui-v2 .ds-datos-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
body.ui-v2 .ds-datos-lista { display: block; }
body.ui-v2 .ds-datos-lista > .ds-dato {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--ds-e4);
    padding: 10px 0;
    border-bottom: 1px solid var(--ds-borde);
}
body.ui-v2 .ds-datos-lista > .ds-dato:first-child { padding-top: 0; }
body.ui-v2 .ds-datos-lista > .ds-dato:last-child { padding-bottom: 0; border-bottom: 0; }
body.ui-v2 .ds-datos-lista > .ds-dato > dt { flex: 0 1 45%; font-size: var(--ds-tam-tabla); line-height: 1.38462; }
body.ui-v2 .ds-datos-lista > .ds-dato > dd { flex: 1 1 auto; text-align: right; }
body.ui-v2 .ds-dato > dt .ds-info { width: 20px; height: 20px; margin-left: 2px; vertical-align: -5px; font-size: 14px; }


/* 24d. Formularios: grilla, grupos, pie fijo y lateral --------------------- */
/* <div class="ds-form-grilla">                         2 columnas (ds-form-grilla-3: 3)
     <div class="ds-campo">                             rótulo + control + ayuda + error
       <label class="ds-rotulo" for="nit">NIT</label>
       <input class="form-control" id="nit" name="nit">
       <p class="ds-ayuda-texto">Sin guion.</p>
     </div>
     <div class="ds-campo ds-campo-ancho">…</div>        ocupa la fila
   </div>
   Grupo: <fieldset class="ds-grupo-campos"><legend class="ds-grupo-titulo">Datos</legend>…</fieldset>
   Pie fijo (formularios largos): <div class="ds-pie-formulario">…botones…</div>
   Formulario con lateral: <div class="ds-form-con-lateral"><div>…</div><aside class="ds-form-lateral">…</aside></div> */
body.ui-v2 .ds-form-grilla {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--ds-e4) 20px;
    align-items: start;
}
body.ui-v2 .ds-form-grilla-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
body.ui-v2 .ds-form-grilla-1 { grid-template-columns: minmax(0, 1fr); }
body.ui-v2 .ds-form-grilla > .ds-campo,
body.ui-v2 .ds-form-grilla > .mb-3 { margin-bottom: 0 !important; min-width: 0; }
body.ui-v2 .ds-campo-ancho,
body.ui-v2 .ds-form-grilla > .ds-campo-ancho { grid-column: 1 / -1; }
body.ui-v2 .ds-campo-requerido > .ds-rotulo::after,
body.ui-v2 .ds-campo-requerido > .form-label::after { content: " *"; color: var(--ds-error); }
body.ui-v2 .ds-campo-error .ds-rotulo,
body.ui-v2 .ds-campo-error .form-label { color: var(--ds-error); }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-form-grilla,
    body.ui-v2 .ds-form-grilla-3 { grid-template-columns: minmax(0, 1fr); }
}
body.ui-v2 .ds-grupo-campos {
    min-width: 0;
    margin: 0 0 var(--ds-e5);
    padding: 0;
    border: 0;
}
body.ui-v2 .ds-grupo-campos + .ds-grupo-campos { padding-top: var(--ds-e5); border-top: 1px solid var(--ds-borde); }
body.ui-v2 .ds-grupo-titulo {
    float: left;               /* como el reboot de Bootstrap: sin cortar la línea de arriba del grupo */
    width: 100%;
    margin: 0 0 2px;
    padding: 0;
    color: var(--ds-texto);
    font-size: var(--ds-tam-seccion);
    font-weight: 600;
    line-height: 1.5;
}
body.ui-v2 .ds-grupo-linea { margin: 0 0 var(--ds-e4); color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); line-height: 1.38462; }
body.ui-v2 .ds-grupo-campos > :not(legend) { clear: left; }
/* el título es un <legend> flotante y lo que sigue lleva clear: un margen de
   arriba se perdía contra el float (el primer rótulo quedaba a 3 px del
   título); relleno en vez de margen */
body.ui-v2 .ds-grupo-titulo + .ds-form-grilla,
body.ui-v2 .ds-grupo-titulo + .ds-campo { margin-top: 0; padding-top: var(--ds-e3); }
/* pie fijo: barra flotante al pie de la ventana mientras el formulario sigue */
body.ui-v2 .ds-pie-formulario {
    position: sticky;
    bottom: var(--ds-e3);
    z-index: 1010;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--ds-e2);
    margin-top: var(--ds-e5);
    padding: 12px 16px;
    background: var(--ds-superficie);        /* opaco: con 96 % el texto que pasa por debajo se transparentaba */
    border: 1px solid var(--ds-borde-marco);
    border-radius: var(--ds-radio-dialogo);
    /* sombra solo hacia arriba: la franja ::after de abajo no la corta, así
       que cuando el pie no está pegado no se ve un escalón bajo la barra */
    box-shadow: var(--ds-sombra-pie);
}
body.ui-v2 .ds-pie-formulario > .ds-pie-formulario-texto {
    margin-right: auto;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
@media (max-width: 767.98px) {
    body.ui-v2 .ds-pie-formulario { bottom: 8px; padding: 10px 12px; }
    body.ui-v2 .ds-pie-formulario > .ds-pie-formulario-texto { flex-basis: 100%; }
}
/* franja del color de la página bajo el pie pegado: sin ella, el contenido
   que pasa por detrás se asomaba en los 12 px entre el pie y el borde de la
   ventana (como la banda sólida de la barra superior). No en un pie dentro de
   una tarjeta (muestra de /estilo): ahí, en su lugar natural, pintaría una
   franja gris dentro de la tarjeta. */
body.ui-v2 .ds-pie-formulario:not(.ds-tarjeta .ds-pie-formulario)::after {
    content: "";
    position: absolute;
    top: 100%;
    left: -4px;                 /* tapa también el borde y la sombra de la tarjeta que pasa por detrás */
    right: -4px;
    height: calc(var(--ds-e3) + 1px);
    background: var(--ds-fondo);
    pointer-events: none;
}
body.ui-v2 .ds-form-con-lateral {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(260px, 320px);
    gap: var(--ds-e5);
    align-items: start;
}
body.ui-v2 .ds-form-lateral { position: sticky; top: calc(var(--ds-alto-barra) + 24px); display: flex; flex-direction: column; gap: var(--ds-e4); }
@media (max-width: 1099.98px) {
    body.ui-v2 .ds-form-con-lateral { grid-template-columns: minmax(0, 1fr); }
    body.ui-v2 .ds-form-lateral { position: static; }
}
/* acciones al final de un formulario corto (sin pie fijo) */
body.ui-v2 .ds-form-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--ds-e2);
    margin-top: var(--ds-e5);
}


/* 24e. Carga de archivo --------------------------------------------------- */
/* Compacta (una fila, para varias cargas en una misma pantalla):
   <label class="ds-carga ds-carga-compacta">
     <input type="file" class="ds-carga-input" name="archivo" accept=".xlsx">
     <span class="ds-carga-icono"><i class="ti ti-file-upload"></i></span>
     <span class="ds-carga-texto">Elegir archivo</span>
     <span class="ds-carga-nombre" data-ds-carga-nombre>Ningún archivo</span>
   </label>
   ui.js pone el nombre del archivo elegido en [data-ds-carga-nombre] (y la
   clase .ds-carga-con-archivo) y .ds-carga-sobre mientras se arrastra.
   Fila de carga (título + ayuda a la izquierda, carga y botón a la derecha):
   <div class="ds-carga-fila"><div class="ds-carga-fila-texto">…</div><div class="ds-carga-fila-control">…</div></div> */
body.ui-v2 .ds-carga.ds-carga-compacta {
    flex-direction: row;
    justify-content: flex-start;
    gap: var(--ds-e3);
    width: 100%;
    min-height: 56px;
    padding: 10px 16px;
    text-align: left;
}
body.ui-v2 .ds-carga-compacta .ds-carga-icono { font-size: 22px; }
body.ui-v2 .ds-carga-nombre {
    min-width: 0;
    max-width: 100%;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    font-weight: 400;
    overflow-wrap: anywhere;
}
body.ui-v2 .ds-carga-compacta .ds-carga-nombre { margin-left: auto; text-align: right; }
body.ui-v2 .ds-carga.ds-carga-con-archivo { border-style: solid; border-color: var(--ds-acento); }
body.ui-v2 .ds-carga.ds-carga-con-archivo .ds-carga-nombre { color: var(--ds-texto); font-weight: 500; }
body.ui-v2 .ds-carga-fila {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(280px, 440px);
    gap: var(--ds-e3) var(--ds-e5);
    align-items: center;
    padding: var(--ds-e4) 0;
    border-bottom: 1px solid var(--ds-borde);
}
body.ui-v2 .ds-carga-fila:first-child { padding-top: 0; }
body.ui-v2 .ds-carga-fila:last-child { padding-bottom: 0; border-bottom: 0; }
body.ui-v2 .ds-carga-fila-titulo { margin: 0; font-size: var(--ds-tam-cuerpo); font-weight: 600; line-height: 1.42858; }
body.ui-v2 .ds-carga-fila-linea { margin: 2px 0 0; color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); line-height: 1.38462; }
body.ui-v2 .ds-carga-fila-control { display: flex; align-items: center; gap: var(--ds-e2); min-width: 0; }
body.ui-v2 .ds-carga-fila-control > .ds-carga { flex: 1 1 auto; }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-carga-fila { grid-template-columns: minmax(0, 1fr); }
}


/* 24f. Línea de tiempo (historial) ---------------------------------------- */
/* <ol class="ds-linea-tiempo">
     <li class="ds-evento ds-evento-exito">
       <div class="ds-evento-texto">Recibido en Compras</div>
       <div class="ds-evento-meta">20/09/2026 10:14 · Brandon Casia</div>
       <div class="ds-evento-detalle">Motivo: …</div>
     </li>
   </ol>
   Tonos del punto: -exito, -aviso, -error, -info (acento), -neutro (gris,
   por defecto después del primero). Mismo aspecto que .ds-lista-eventos. */
body.ui-v2 .ds-linea-tiempo {
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
body.ui-v2 .ds-linea-tiempo > .ds-evento {
    --ds-evento-punto: var(--ds-borde-fuerte);
    position: relative;
    padding: 0 0 var(--ds-e4) 22px;
}
body.ui-v2 .ds-linea-tiempo > .ds-evento:first-child { --ds-evento-punto: var(--ds-acento); }
body.ui-v2 .ds-linea-tiempo > .ds-evento::before {
    content: "";
    position: absolute;
    top: 0.35em;
    left: 0;
    width: 10px;
    height: 10px;
    border: 2px solid var(--ds-superficie);
    border-radius: 50%;
    background: var(--ds-evento-punto);
    box-shadow: 0 0 0 1px var(--ds-evento-punto);
}
body.ui-v2 .ds-linea-tiempo > .ds-evento::after {
    content: "";
    position: absolute;
    top: calc(0.35em + 14px);
    bottom: 2px;
    left: 4.5px;
    width: 1px;
    background: var(--ds-borde);
}
body.ui-v2 .ds-linea-tiempo > .ds-evento:last-child { padding-bottom: 0; }
body.ui-v2 .ds-linea-tiempo > .ds-evento:last-child::after { display: none; }
body.ui-v2 .ds-evento.ds-evento-exito { --ds-evento-punto: var(--ds-exito-punto); }
body.ui-v2 .ds-evento.ds-evento-aviso { --ds-evento-punto: var(--ds-aviso-punto); }
body.ui-v2 .ds-evento.ds-evento-error { --ds-evento-punto: var(--ds-error-punto); }
body.ui-v2 .ds-evento.ds-evento-info { --ds-evento-punto: var(--ds-acento); }
body.ui-v2 .ds-evento.ds-evento-neutro { --ds-evento-punto: var(--ds-borde-fuerte); }
body.ui-v2 .ds-evento-cabeza { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px var(--ds-e2); }
body.ui-v2 .ds-evento-cabeza > .ds-evento-meta { margin-left: auto; }


/* 24g. Pestañas de página (enlaces) --------------------------------------- */
/* Pestañas que cambian de página o de parámetro (servidor), subrayado del
   acento como las .nav-tabs re-pintadas:
   <nav class="ds-pestanas" aria-label="Secciones">
     <a class="ds-pestana" href="…" aria-current="page">Corridas <span class="ds-pestana-conteo">12</span></a>
     <a class="ds-pestana" href="…">Individuales</a>
   </nav>
   Para pestañas de Bootstrap (data-bs-toggle="tab") siga usando .nav-tabs. */
body.ui-v2 .ds-pestanas {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--ds-e5);
    margin: 0 0 var(--ds-e4);
    overflow-x: auto;
    border-bottom: 1px solid var(--ds-borde);
    scrollbar-width: none;
}
body.ui-v2 .ds-pestanas::-webkit-scrollbar { display: none; }
body.ui-v2 .ds-pestana {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 40px;
    margin-bottom: -1px;
    padding: 0 2px;
    border-bottom: 2px solid transparent;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-cuerpo);
    font-weight: 500;
    line-height: 1.42858;
    text-decoration: none;
    white-space: nowrap;
    transition: color var(--ds-transicion), border-color var(--ds-transicion);
}
body.ui-v2 .ds-pestana:hover,
body.ui-v2 .ds-pestana.ds-f-hover { color: var(--ds-texto); border-bottom-color: var(--ds-borde-fuerte); }
body.ui-v2 .ds-pestana[aria-current="page"],
body.ui-v2 .ds-pestana.activo,
body.ui-v2 .ds-pestana.ds-f-activo { color: var(--ds-acento-oscuro); border-bottom-color: var(--ds-acento); }
body.ui-v2 .ds-pestana:focus-visible { outline: 2px solid var(--ds-acento-oscuro); outline-offset: -2px; border-radius: 6px; }
body.ui-v2 .ds-pestana.disabled,
body.ui-v2 .ds-pestana[aria-disabled="true"] { color: var(--ds-texto-3); pointer-events: none; }
body.ui-v2 .ds-pestana-conteo {
    min-width: 20px;
    padding: 1px 6px;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-neutro-fondo);
    color: var(--ds-neutro);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.33334;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .ds-pestana[aria-current="page"] .ds-pestana-conteo,
body.ui-v2 .ds-pestana.activo .ds-pestana-conteo { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }


/* 24h. Paginación del servidor -------------------------------------------- */
/* <nav class="ds-paginacion" aria-label="Páginas">
     <span class="ds-paginacion-info">Página 2 de 9 · 214 SIAF</span>
     <ul class="pagination">…page-item / page-link (§14)…</ul>
   </nav> */
body.ui-v2 .ds-paginacion {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-e3);
    margin-top: var(--ds-e4);
}
body.ui-v2 .ds-paginacion-info { color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-paginacion .pagination { margin: 0; }
body.ui-v2 .ds-paginacion .page-link { min-width: 32px; height: auto; min-height: 32px; text-decoration: none; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-paginacion .page-item.disabled .page-link { color: var(--ds-texto-3); }
body.ui-v2 .ds-paginacion-hueco .page-link { border: 0; background: transparent; color: var(--ds-texto-3); pointer-events: none; }
/* dentro de una tarjeta plana, bajo la tabla */
body.ui-v2 .ds-tarjeta-plana .ds-paginacion { margin: 0; padding: var(--ds-e3) 20px; border-top: 1px solid var(--ds-borde); }


/* 24i. Página de error e inicio de sesión --------------------------------- */
/* Error (403, 404…): <div class="ds-error-pagina">ícono en círculo suave,
   código chico, título 20/600, una frase, acciones</div>. Macro
   ds.pagina_error(...). */
body.ui-v2 .ds-error-pagina {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--ds-e3);
    min-height: min(60vh, 520px);
    padding: var(--ds-e6) var(--ds-e4);
    text-align: center;
}
body.ui-v2 .ds-error-pagina-icono {
    display: inline-grid;
    place-items: center;
    width: 64px;
    height: 64px;
    margin-bottom: var(--ds-e1);
    border-radius: 50%;
    background: var(--ds-neutro-fondo);
    color: var(--ds-texto-2);
    font-size: 30px;
    line-height: 1;
}
body.ui-v2 .ds-error-pagina-codigo { margin: 0; color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); font-weight: 500; letter-spacing: 0.02em; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-error-pagina-titulo { margin: 0; color: var(--ds-texto); font-size: 20px; font-weight: 600; line-height: 1.4; letter-spacing: -0.01em; }
body.ui-v2 .ds-error-pagina-texto { max-width: 34em; margin: 0; color: var(--ds-texto-2); font-size: var(--ds-tam-cuerpo); line-height: 1.42858; }
body.ui-v2 .ds-error-pagina-acciones { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--ds-e2); margin-top: var(--ds-e2); }
/* Inicio de sesión: página sin riel ni barra; tarjeta centrada sobre el fondo
   gris de la app. <body class="ui-v2 ds-pagina-sola"><main class="ds-login">…</main> */
body.ui-v2.ds-pagina-sola { min-height: 100vh; }
body.ui-v2 .ds-login {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: var(--ds-e6) var(--ds-e4);
}
body.ui-v2 .ds-login-marca {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: var(--ds-e5);
    color: var(--ds-texto);
    font-size: 18px;
    font-weight: 500;
    letter-spacing: -0.02em;
}
body.ui-v2 .ds-login-marca b { font-weight: 700 !important; }
body.ui-v2 .ds-login-marca .ds-marca-simbolo { width: 40px; height: 40px; font-size: 22px; }
body.ui-v2 .ds-login-marca .ds-marca-logo { width: 40px; height: 40px; }
body.ui-v2 .ds-login-tarjeta {
    width: 100%;
    max-width: 400px;
    padding: 32px;
    background: var(--ds-superficie);
    border: 1px solid var(--ds-borde-marco);
    border-radius: var(--ds-radio-dialogo);
    box-shadow: var(--ds-sombra-flotante);
}
body.ui-v2 .ds-login-titulo { margin: 0 0 4px; font-size: 22px; font-weight: 600; line-height: 1.36364; letter-spacing: -0.02em; }
body.ui-v2 .ds-login-linea { margin: 0 0 var(--ds-e5); color: var(--ds-texto-2); font-size: var(--ds-tam-cuerpo); line-height: 1.42858; }
body.ui-v2 .ds-login-tarjeta .ds-campo:last-of-type { margin-bottom: var(--ds-e5); }
body.ui-v2 .ds-login-tarjeta .ds-btn { width: 100%; }
body.ui-v2 .ds-login-tarjeta .ds-aviso { margin-bottom: var(--ds-e4); }
@media (max-width: 479.98px) {
    body.ui-v2 .ds-login-tarjeta { padding: 24px 20px; }
}


/* 24j. Indicadores: barra de avance, variación, grilla compacta ----------- */
/* ds.kpi(..., barra=62, tono="aviso", delta="+4 %", tono_delta="exito"):
   barra de 6 px bajo el valor (porcentaje con aria); variación en una
   píldora mini. .ds-kpis-compactos: valor de 20 px (para 5-6 indicadores).
   .ds-kpis-4 / -5: columnas fijas desde 1280. */
/* barra de avance (también suelta: ds.barra_avance): <progress>, sin style="" */
body.ui-v2 progress.ds-barra-avance,
body.ui-v2 .ds-kpi-barra {
    --ds-barra-color: var(--ds-acento);
    display: block;
    width: 100%;
    height: 6px;
    margin-top: 4px;
    overflow: hidden;
    border: 0;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-neutro-fondo);
    color: var(--ds-barra-color);
    appearance: none;
    -webkit-appearance: none;
}
body.ui-v2 progress.ds-barra-avance::-webkit-progress-bar { background: var(--ds-neutro-fondo); border-radius: var(--ds-radio-pildora); }
body.ui-v2 progress.ds-barra-avance::-webkit-progress-value { background: var(--ds-barra-color); border-radius: var(--ds-radio-pildora); }
body.ui-v2 progress.ds-barra-avance::-moz-progress-bar { background: var(--ds-barra-color); border-radius: var(--ds-radio-pildora); }
body.ui-v2 .ds-barra-avance.ds-barra-exito, body.ui-v2 .ds-kpi-exito .ds-barra-avance { --ds-barra-color: var(--ds-exito-punto); }
body.ui-v2 .ds-barra-avance.ds-barra-aviso, body.ui-v2 .ds-kpi-aviso .ds-barra-avance { --ds-barra-color: var(--ds-aviso-punto); }
body.ui-v2 .ds-barra-avance.ds-barra-error, body.ui-v2 .ds-kpi-error .ds-barra-avance { --ds-barra-color: var(--ds-error-punto); }
body.ui-v2 .ds-barra-avance.ds-barra-neutro { --ds-barra-color: var(--ds-texto-3); }
body.ui-v2 .ds-kpi-valor-fila { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px var(--ds-e2); }
body.ui-v2 .ds-kpi-delta { font-size: var(--ds-tam-etiqueta); }
body.ui-v2 .ds-kpis-compactos { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: var(--ds-e3); }
body.ui-v2 .ds-kpis-compactos .ds-kpi { padding: var(--ds-e3) var(--ds-e4); gap: 4px; }
body.ui-v2 .ds-kpis-compactos .ds-kpi-valor { font-size: 20px; line-height: 1.4; }
body.ui-v2 .ds-kpis-compactos .ds-kpi-icono { width: 28px; height: 28px; font-size: 16px; }
@media (min-width: 1280px) {
    body.ui-v2 .ds-kpis-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    body.ui-v2 .ds-kpis-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}
body.ui-v2 .ds-kpi-valor.ds-kpi-valor-texto { font-size: 18px; line-height: 1.5; letter-spacing: -0.01em; }


/* 24k. Avisos con acción ---------------------------------------------------- */
/* ds.aviso(..., accion) o marcado: <div class="ds-aviso ds-aviso-info">…<div
   class="ds-aviso-acciones">…</div></div>; .ds-aviso-compacto: 8 px de alto de
   relleno, texto 13. */
body.ui-v2 .ds-aviso:has(> .ds-aviso-acciones) { align-items: center; }
body.ui-v2 .ds-aviso-acciones {
    display: flex;
    flex: none;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2);
    margin-left: auto;
    align-self: center;
}
body.ui-v2 .ds-aviso-compacto { padding: 8px 12px; font-size: var(--ds-tam-tabla); line-height: 1.38462; }
body.ui-v2 .ds-aviso-compacto .ds-aviso-icono { font-size: 18px; line-height: 1; }
body.ui-v2 .ds-aviso .ds-aviso-cuerpo > p { margin: 0 0 4px; }
body.ui-v2 .ds-aviso .ds-aviso-cuerpo > p:last-child { margin-bottom: 0; }
/* "Pendiente" / "En construcción": aviso neutro con línea discontinua */
body.ui-v2 .ds-aviso.ds-aviso-borrador { border: 1px dashed var(--ds-borde-fuerte); background: var(--ds-superficie); }


/* 24l. Gráficos ------------------------------------------------------------- */
/* <div class="ds-grafico" style-free: alto por clase> <canvas id="…" role="img" aria-label="…"></canvas></div>
   Colores: UI.paleta (ui.js) lee los tokens; UI.opcionesGrafico(tipo) arma las
   opciones base de Chart.js (fuente Inter, cuadrícula fina, sin azul marino). */
body.ui-v2 .ds-grafico { position: relative; width: 100%; height: 280px; min-width: 0; }
body.ui-v2 .ds-grafico-bajo { height: 200px; }
body.ui-v2 .ds-grafico-alto { height: 360px; }
body.ui-v2 .ds-grafico > canvas { display: block; max-width: 100%; }
body.ui-v2 .ds-leyenda {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ds-e2) var(--ds-e4);
    margin: var(--ds-e3) 0 0;
    padding: 0;
    list-style: none;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
}
body.ui-v2 .ds-leyenda > li { display: inline-flex; align-items: center; gap: 6px; }
body.ui-v2 .ds-leyenda-marca { width: 10px; height: 10px; border-radius: 3px; background: var(--ds-acento); }


/* 24m. Utilidades de maquetación ------------------------------------------- */
/* .ds-pila: bloques uno bajo otro con 24 px (ds-pila-apretada: 16).
   .ds-grilla: tarjetas en columnas que se acomodan (mín. 320 px);
   .ds-grilla-2 / -3: columnas fijas desde 1100 px.
   .ds-fila: en línea con 8 px (envuelve). .ds-fila-entre: extremos. */
body.ui-v2 .ds-pila { display: flex; flex-direction: column; gap: var(--ds-e5); min-width: 0; }
body.ui-v2 .ds-pila-apretada { gap: var(--ds-e4); }
body.ui-v2 .ds-pila > * { margin-bottom: 0; }
body.ui-v2 .ds-grilla {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
    gap: var(--ds-e4);
    align-items: start;
}
@media (min-width: 1100px) {
    body.ui-v2 .ds-grilla-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    body.ui-v2 .ds-grilla-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    body.ui-v2 .ds-grilla-2-1 { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
}
body.ui-v2 .ds-fila { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ds-e2); min-width: 0; }
body.ui-v2 .ds-fila-entre { justify-content: space-between; }
body.ui-v2 .ds-margen-abajo { margin-bottom: var(--ds-e4); }
body.ui-v2 .ds-texto-chico { font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-codigo { font-family: var(--ds-fuente); font-variant-numeric: tabular-nums; font-feature-settings: "zero" 0; letter-spacing: 0.01em; }
@media print {
    body.ui-v2 .ds-pie-formulario,
    body.ui-v2 .ds-filtros-get,
    body.ui-v2 .ds-paginacion { display: none !important; }
    body.ui-v2 .ds-tarjeta { box-shadow: none; break-inside: avoid; }
}
/* valor largo en una píldora de filtro del servidor: tope en ch (texto entero en aria-label) */
body.ui-v2 .ds-filtros-get .ds-pildora-filtro-valor { display: inline-block; max-width: 28ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
/* muestra de la página de error dentro de otra página (/estilo) */
body.ui-v2 .ds-error-pagina.ds-error-pagina-muestra { min-height: 0; padding: var(--ds-e5) var(--ds-e4); }


/* 24n. Chips de casilla, filas teñidas, visor, "Volver" y distribución ----- */
/* Chip de casilla o de opción (filtros de varios valores a la vista, p. ej.
   los centros de costo del tablero): la casilla real va adentro (oculta a la
   vista, no al teclado); radio marcado = relleno primario, casilla marcada =
   tinte acento claro con ✓. Macro ds.chip_casilla.
   <label class="ds-chip ds-chip-casilla"><input type="checkbox" name="cc" value="122" checked><span>122</span></label> */
body.ui-v2 .ds-chip.ds-chip-casilla { position: relative; }
body.ui-v2 .ds-chip.ds-chip-casilla > input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    opacity: 0;
}
body.ui-v2 .ds-chip.ds-chip-casilla:has(> input:checked) {
    border-color: var(--ds-relleno-primario);
    background: var(--ds-relleno-primario);
    color: var(--ds-texto-sobre-relleno);
}
body.ui-v2 .ds-chip.ds-chip-casilla:has(> input:checked):hover { border-color: var(--tb-relleno-hover); background: var(--tb-relleno-hover); }
body.ui-v2 .ds-chip.ds-chip-casilla:has(> input:checked) .ds-chip-conteo { color: var(--ds-texto-sobre-relleno-2); }
body.ui-v2 .ds-chip.ds-chip-casilla:has(> input:focus-visible) { box-shadow: var(--tb-anillo); border-color: var(--ds-acento); }
body.ui-v2 .ds-chip.ds-chip-casilla:has(> input:disabled) { color: var(--ds-texto-3); cursor: not-allowed; }
body.ui-v2 .ds-chip.ds-chip-casilla > .ti-check { display: none; font-size: 14px; }
body.ui-v2 .ds-chip.ds-chip-casilla:has(> input[type="checkbox"]:checked) > .ti-check { display: inline-block; }
/* casilla marcada (varios valores a la vez: renglones, centros de costo,
   "Solo homologados"): tinte de lo activo, como la píldora de filtro activa,
   con la ✓; el relleno queda para la opción única (radio, chip de estado).
   Cinco rellenos seguidos se leían como cinco botones primarios. */
body.ui-v2 .ds-chip.ds-chip-casilla:has(> input[type="checkbox"]:checked) {
    border-color: var(--ds-acento);   /* Corrección 2: marcado con el acento, como la píldora de filtro activa */
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
}
body.ui-v2 .ds-chip.ds-chip-casilla:has(> input[type="checkbox"]:checked):hover { border-color: var(--ds-acento); background: var(--ds-acento-claro-2); }
body.ui-v2 .ds-chip.ds-chip-casilla:has(> input[type="checkbox"]:checked) .ds-chip-conteo { color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-chip.ds-chip-casilla:has(> input[type="checkbox"]:focus-visible) { border-color: var(--ds-acento); }

/* Filas teñidas (resultado de una validación, fila con error): tinte suave
   del estado, sin tocar el texto. También re-pinta .table-danger/-warning/
   -success/-info de Bootstrap. Las filas alternadas (.table-striped) no se
   pintan en v2: solo líneas finas y el gris al pasar el mouse.
   --bs-table-bg-state: initial (y no none): Bootstrap pinta la celda con
   box-shadow: inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type));
   con "none" la sombra quedaba inválida y la fila NO se teñía. La barra de 3 px
   de error/aviso suma su sombra a la del tinte, y el gris al pasar el mouse va
   después para seguir ganando. */
body.ui-v2 :is(.table, .ui-tabla, .ds-tabla) > tbody > tr:is(.ds-fila-error, .table-danger) > * { --bs-table-bg-type: var(--ds-error-tenue); --bs-table-color-type: var(--ds-texto); --bs-table-bg-state: initial; }
body.ui-v2 :is(.table, .ui-tabla, .ds-tabla) > tbody > tr:is(.ds-fila-aviso, .table-warning) > * { --bs-table-bg-type: var(--ds-aviso-tenue); --bs-table-color-type: var(--ds-texto); --bs-table-bg-state: initial; }
body.ui-v2 :is(.table, .ui-tabla, .ds-tabla) > tbody > tr:is(.ds-fila-exito, .table-success) > * { --bs-table-bg-type: var(--ds-exito-tenue); --bs-table-color-type: var(--ds-texto); --bs-table-bg-state: initial; }
body.ui-v2 :is(.table, .ui-tabla, .ds-tabla) > tbody > tr:is(.ds-fila-info, .table-info) > * { --bs-table-bg-type: var(--ds-info-tenue); --bs-table-color-type: var(--ds-texto); --bs-table-bg-state: initial; }
body.ui-v2 :is(.table, .ui-tabla, .ds-tabla) > tbody > tr.ds-fila-apagada > * { color: var(--ds-texto-2); }
body.ui-v2 :is(.table, .ui-tabla, .ds-tabla) > tbody > tr:is(.ds-fila-error, .table-danger) > :first-child { box-shadow: inset 3px 0 0 var(--ds-error-borde), inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type)); }
body.ui-v2 :is(.table, .ui-tabla, .ds-tabla) > tbody > tr:is(.ds-fila-aviso, .table-warning) > :first-child { box-shadow: inset 3px 0 0 var(--ds-aviso-borde), inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type)); }
body.ui-v2 .table-striped > tbody > tr:nth-of-type(odd) > * { --bs-table-bg-type: transparent; --bs-table-color-type: inherit; }
body.ui-v2 .table-hover > tbody > tr:hover > *,
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr.ds-f-hover > * { --bs-table-bg-state: var(--ds-hover); }
body.ui-v2 .table-bordered > :not(caption) > * > * { border-width: 0; border-bottom-width: 1px; }
/* Tabla estática (hecha a mano) dentro de una tarjeta o marco: la misma
   apariencia que la de TablaDatos. <div class="ds-tabla-marco"><div class="table-responsive">
   <table class="table ds-tabla">…</table></div></div>  (+ .ds-tabla-compacta) */
body.ui-v2 .ds-tabla-marco > .table-responsive { margin: 0; }
body.ui-v2 .ds-tabla-marco .ds-tabla > :last-child > tr:last-child > * { border-bottom: 0; }
body.ui-v2 .ds-tabla > tfoot > tr > * {
    padding: 10px 12px;
    border-top: 1px solid var(--ds-borde);
    border-bottom: 0;
    background: var(--ds-fondo);
    font-weight: 600;
}

/* Visor de PDF u otro documento en la página (iframe): tarjeta con alto de
   la ventana. <div class="ds-visor"><iframe src="…" title="A-01 (PDF)"></iframe></div> */
body.ui-v2 .ds-visor {
    height: calc(100vh - var(--ds-alto-barra) - 120px);
    min-height: 480px;
    overflow: hidden;
    background: var(--ds-neutro-fondo);
    border: 1px solid var(--ds-borde-marco);
    border-radius: var(--ds-radio-tarjeta);
    box-shadow: var(--ds-sombra-tarjeta);
}
body.ui-v2 .ds-visor > iframe,
body.ui-v2 .ds-visor > object,
body.ui-v2 .ds-visor > embed { display: block; width: 100%; height: 100%; border: 0; }

/* "Volver" sobre el título de una ficha o formulario: enlace terciario con flecha.
   Macro ds.volver(href, texto). */
body.ui-v2 .ds-volver {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin: 0 0 var(--ds-e1) -6px;
    padding: 2px 8px 2px 6px;
    border-radius: var(--ds-radio-pildora);
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    font-weight: 500;
    line-height: 1.38462;
    text-decoration: none;
    transition: background-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .ds-volver > .ti { font-size: 16px; }
body.ui-v2 .ds-volver:hover { background: var(--ds-hover-fondo); color: var(--ds-texto); }

/* Barra de distribución (partes de un total: p. ej. artículos por
   clasificación). Cada parte crece según su valor: el JS pone
   el.style.flexGrow = n (o la clase de ancho); el color, por tono.
   <div class="ds-distribucion" role="img" aria-label="…"><span class="ds-distribucion-parte ds-parte-error"></span>…</div> */
body.ui-v2 .ds-distribucion {
    display: flex;
    gap: 2px;
    height: 8px;
    overflow: hidden;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-neutro-fondo);
}
body.ui-v2 .ds-distribucion-parte { flex: 1 1 0; min-width: 2px; background: var(--ds-acento); }
body.ui-v2 .ds-distribucion-parte.ds-parte-exito { background: var(--ds-exito-punto); }
body.ui-v2 .ds-distribucion-parte.ds-parte-aviso { background: var(--ds-aviso-punto); }
body.ui-v2 .ds-distribucion-parte.ds-parte-error { background: var(--ds-error-punto); }
body.ui-v2 .ds-distribucion-parte.ds-parte-neutro { background: var(--ds-texto-3); }
body.ui-v2 .ds-distribucion-parte.ds-parte-info { background: var(--ds-acento); }

/* Una sola familia de letra (decisión de diseño): lo que venía en monoespaciada
   (códigos, teclas) usa Inter con cifras tabulares; <pre> y los campos de pegado
   conservan su letra (alineación por tabuladores). <kbd> como tecla clara. */
body.ui-v2 :is(code, samp, .font-monospace):not(pre *) { font-family: var(--ds-fuente) !important; font-variant-numeric: tabular-nums; font-size: 0.95em; color: inherit; }
body.ui-v2 kbd {
    display: inline-block;
    min-width: 1.6em;
    padding: 1px 6px;
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: 6px;
    background: var(--ds-superficie);
    box-shadow: inset 0 -1px 0 var(--ds-borde);
    color: var(--ds-texto-2);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 500;
    line-height: 1.33334;
    text-align: center;
}


/* 25. Piezas de las pantallas migradas (fase "todo") ======================
   Lo que cada grupo de pantallas agregó durante la migración (2026-09-26/27,
   antes en static/css/_frag_A…_frag_H.css), fundido aquí por el integrador
   (2026-09-28): cada pieza está UNA vez, con nombre genérico ds- cuando
   sirve a cualquier pantalla. Los arreglos de piezas que ya existían se
   hicieron en su propia sección (§11 select con "…", §14 pie de diálogo,
   §15a relleno compacto en em, marco posicionado y encabezado con texto
   oculto, §24a filtros GET en una columna, §24d título de grupo y pie
   opaco, §24n filas teñidas). Quedan con nombre de pantalla solo las
   piezas sin equivalente genérico, con el porqué al lado: s182-/s465-
   (SIAF 182 y su cuadrícula de captura, §25n), g-col-/s182-col- (partes
   de ancho de columnas de una pantalla, §25o) y .det-* (clases que arma el
   panel Detalle del SIAF y usa static/js/detalle_siaf.js, §25m).
   Reglas de la fase (ver el inicio del archivo): interlineados sin unidad,
   altos como mínimos y anchos en em/ch (Safari con zoom bajo agranda el
   texto chico).
     25a. Columnas de tabla: partes, pisos, nombre largo, contenido angosto
     25b. Celdas: select ajustado, "+N" en la línea gris, celda holgada,
          enlace de fila, código gris, punto de estado, fila de detalle,
          encabezado ordenable por enlace
     25c. Tablas con forma propia: con selección que cabe en la ventana, con
          línea de tiempo, agrupada, con desplazamiento propio, en un panel
     25d. Barra de filtros: rótulo, casillas con código, píldora fija,
          buscadores rotulados y flexibles
     25e. Indicadores: tarjeta que es botón, resumen con distribución, montos
     25f. Píldoras, marcas y botones: píldora enlace y de conteo, contorno,
          marca de contrato abierto, píldora-acción, botón con conteo
     25g. Tarjetas, subpaneles, plegables y acordeón
     25h. Formularios: pasos-enlace, búsqueda en una fila, panel flotante,
          tarjetas seleccionables, reparto, campos de lectura y cantidad,
          formulario adaptable, listas de opciones y casillas, sugerencias
     25i. Tarjetas de carga de archivos
     25j. Pie fijo del formulario (resumen, avisos, botones)
     25k. Paneles laterales y diálogos
     25l. Avisos, notas, textos y paginación en la página
     25m. Ficha y panel Detalle del SIAF
     25n. SIAF 182 y cuadrícula de captura 465
     25o. Partes de ancho de columnas de una pantalla
     25p. Actas de adjudicación: tabla con campos dentro de las celdas,
          ofertas fijas e «Incluye IVA», bloque de adjudicación, texto legal,
          listas de avisos, el formulario por pasos en dos columnas (tabla
          ceñida, plegable chico, paso abierto) y el acta en vivo (hoja que
          se escala a su columna, sección resaltada y marca BORRADOR)
   ========================================================================== */


/* 25a. Columnas de tabla: partes, pisos, nombre largo, contenido angosto --- */
/* Parte del ancho de una columna de texto (.ds-col-texto toma el 30 %, .ds-col-flex
   el 24 %): cuando la descripción ES el dato principal (artículos, catálogo,
   renglones, unidades) toma más; un texto secundario, menos. */
body.ui-v2 .ds-col-parte-20 { --ds-col-parte: 20%; }
body.ui-v2 .ds-col-parte-40 { --ds-col-parte: 40%; }
body.ui-v2 .ds-col-parte-50 { --ds-col-parte: 50%; }
body.ui-v2 .ds-col-parte-60 { --ds-col-parte: 60%; }
body.ui-v2 .ds-col-parte-70 { --ds-col-parte: 70%; }
/* Columna de texto libre SIN parte fija (.ds-col-texto.ds-col-parte-auto): el
   reparto automático de la tabla le da ancho según lo que pide su texto (en
   una línea, hasta un tope) frente a las demás. Así un texto corto (un centro
   de costo) no se recorta mientras otra columna sobra, y uno largo (la
   justificación) se queda con el resto y se parte en dos líneas. Piso
   --ds-col-texto-min (12em) y tope de lo que pide --ds-col-texto-max (50em);
   con .ds-col-texto-corta: 8em y 30em (6em y 5em en contenido < 1272 / < 1150). */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-texto.ds-col-parte-auto { width: auto; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.ds-col-texto.ds-col-parte-auto > * { max-width: var(--ds-col-texto-max, 50em); }
body.ui-v2 .ds-col-parte-auto.ds-col-texto-corta { --ds-col-texto-min: 8em; --ds-col-texto-max: 30em; }
@container contenido (max-width: 1271.98px) {
    body.ui-v2 .ds-col-parte-auto.ds-col-texto-corta { --ds-col-texto-min: 6em; }   /* como el piso de .ds-col-flex (§23j) */
}
@container contenido (max-width: 1149.98px) {
    body.ui-v2 .ds-col-parte-auto.ds-col-texto-corta { --ds-col-texto-min: 5em; }
}
/* Columna de texto más angosta con parte fija (.ds-col-texto.ds-col-texto-corta,
   sin -parte-auto): un texto libre SECUNDARIO (método de compra, observación)
   toma el 18 % (22 % desde 1600 px de contenido) con piso de 10em (8em bajo 1150). */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-texto.ds-col-texto-corta:not(.ds-col-parte-auto) { --ds-col-parte: 18%; --ds-col-texto-min: 10em; }
/* Columna flexible con piso mayor (nombre + NIT debajo): en una tabla que en el
   teléfono se desplaza de lado, el proveedor no baja de 12em; desde 1600 px de
   contenido (1920-2560: el ancho que sobra iba a las columnas de monto mientras
   el proveedor seguía cortado) toma el 30 %. */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-flex.ds-col-flex-ancha { --ds-col-flex-min: 12em; }
@container contenido (min-width: 1600px) {
    body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-flex.ds-col-flex-ancha { --ds-col-parte: 30%; }
    body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-texto.ds-col-texto-corta:not(.ds-col-parte-auto) { --ds-col-parte: 22%; }
}
/* Contenido angosto (< 1150 px: 1280 con el riel expandido, o zoom): igual que
   §23j baja los pisos de la tabla, aquí bajan los pisos que se ponen en la
   CELDA (y por eso no ven la variable de la tabla), y una columna de contenido
   marcada .ds-col-envuelve (nombre de persona, tipo de reporte) puede partirse
   en dos líneas en vez de empujar la tabla de lado. */
@container contenido (max-width: 1149.98px) {
    body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-flex.ds-col-flex-ancha { --ds-col-flex-min: 9em; }
    body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-texto.ds-col-texto-corta:not(.ds-col-parte-auto) { --ds-col-texto-min: 8em; }
    body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.ds-col-envuelve { white-space: normal; }
    body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-envuelve { --ds-col-min: 6em; }
}
/* Columna de NOMBRE largo (.ds-col-nombre + .ds-celda-nombre), alternativa a
   .ds-col-flex para el texto largo de una fila (proveedor, razón social).
   .ds-col-flex toma una parte FIJA (24 %): en una ventana ancha (o Safari con
   zoom bajo) el nombre se cortaba a 2 letras del final mientras otras columnas
   sobraban. Aquí la columna es "auto": pide el ancho del nombre completo (su
   máximo) pero puede ceder hasta su piso. Las columnas de contenido no ceden
   nada, así esta es la primera (y la única) que se angosta cuando falta ancho,
   y cuando sobra crece como las demás.
   <th/td class="ds-col-nombre"> … <div class="ds-celda"><div class="ds-celda-principal">
       <span class="ds-celda-nombre" title="nombre completo">…</span></div>
     <div class="ds-celda-secundaria">…</div></div>
   .ds-celda-nombre: una línea; si no cabe, se llena la línea hasta el borde
   y "…" (el texto se parte en líneas por cualquier letra y se muestra solo la
   primera: así el mínimo de la columna es el piso y no el nombre entero, y a
   1280 se lee "COMPAÑIA FARMACE…" en vez de "COMPAÑIA…"). Con 1600 px o más
   de contenido, hasta dos líneas partidas por palabras. Pisos: 8em (13em en
   teléfono, donde la tabla se desplaza de lado dentro de su marco). */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.ds-col-nombre { white-space: normal; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-col-nombre::after {
    content: "";
    display: block;
    width: var(--ds-col-nombre-min, 8em);
    height: 0;
}
body.ui-v2 .ds-celda-nombre {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 1;
    line-clamp: 1;
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: normal;
    overflow-wrap: normal;
    word-break: break-all;
}
@container contenido (max-width: 767.98px) {
    body.ui-v2 :is(.ui-tabla, .ds-tabla) { --ds-col-nombre-min: 13em; }
}
@container contenido (min-width: 1600px) {
    body.ui-v2 .ds-celda-principal:has(> .ds-celda-nombre) {
        align-items: flex-start;
        height: auto;
        min-height: 1.3077em;
    }
    body.ui-v2 .ds-celda-principal > .ds-celda-nombre {
        -webkit-line-clamp: 2;
        line-clamp: 2;
        word-break: normal;
    }
}
/* Tabla en un espacio angosto (diálogo, panel lateral): <div class="ds-tabla-angosta">
   alrededor de la TablaDatos o de la tabla hecha a mano. Pisos menores para las
   columnas que ceden (.ds-col-nombre 6em, .ds-col-flex 5em) y relleno lateral de
   10 px (una tabla de cinco columnas cabe en su diálogo sin desplazarse). */
body.ui-v2 .ds-tabla-angosta { --ds-col-nombre-min: 6em; --ds-col-flex-min: 5em; }
body.ui-v2 .ds-tabla-angosta :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td):not(:first-child):not(:last-child) { padding-left: 10px; padding-right: 10px; }
/* Texto de dos líneas en una celda (.ds-texto-2-lineas, §23j): el ritmo de la
   celda de dos líneas (§23a, 17 px por línea con 13 px) y no el interlineado de
   20 px de la tabla, así la fila mide 44 y no 51. */
body.ui-v2 :is(.ds-tabla, .ui-tabla) > tbody > tr > td .ds-texto-2-lineas { line-height: 1.3077; }
/* Celda de texto libre que se parte en líneas sin tope de ancho */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.ds-celda-parte { white-space: normal; overflow-wrap: anywhere; }
/* Texto libre con cifras proporcionales: las celdas usan cifras tabulares
   (§15) y en Inter eso también ensancha el guion ("administrativo -
   financieras"). En las columnas de TEXTO libre (nombres, descripciones,
   títulos de grupo) vuelven las proporcionales; los códigos (.ds-codigo-gris,
   .ds-num) siguen tabulares. */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td:is(.ds-col-texto, .ds-celda-parte),
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td .ds-texto-2-lineas,
body.ui-v2 .ds-tabla-agrupada > tbody > tr.ds-fila-grupo > th { font-variant-numeric: normal; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > :is(td, th) .ds-codigo-gris { font-variant-numeric: tabular-nums; }


/* 25b. Celdas ---------------------------------------------------------------- */
/* Select de celda AJUSTADO (<select class="form-select form-select-sm
   ds-select-celda ds-select-ajustado">): mide su opción más larga (con las
   mismas opciones, todas las filas miden igual) y deja el aire a la derecha en
   vez de estirarse; relleno suave (sin caja marcada) para que una columna de
   selects no pese tanto; el que falta elegir conserva el anillo de atención
   (§23f) en caja blanca. */
body.ui-v2 .form-select.ds-select-celda.ds-select-ajustado,
body.ui-v2 .ds-linea > .form-select.ds-select-celda.ds-select-ajustado {
    flex: 0 1 auto;
    width: auto;
    min-width: 0;
    max-width: 100%;
    padding-left: 10px;
    padding-right: 26px;
    border-color: transparent;
    background-color: var(--ds-neutro-fondo);
}
body.ui-v2 .form-select.ds-select-celda.ds-select-ajustado:hover:not(:disabled):not(:focus),
body.ui-v2 .form-select.ds-select-celda.ds-select-ajustado.ds-f-hover {
    border-color: var(--ds-borde-fuerte);
    background-color: var(--ds-superficie);
}
body.ui-v2 .form-select.ds-select-celda.ds-select-ajustado:focus,
body.ui-v2 .form-select.ds-select-celda.ds-select-ajustado.ds-f-foco {
    border-color: var(--ds-acento);
    background-color: var(--ds-superficie);
}
/* sobre la fila con hover (gris muy claro) o seleccionada (celeste claro) el
   relleno suave se perdía: un gris un poco más oscuro / blanco */
@media (hover: hover) {
    body.ui-v2 .ui-tabla > tbody > tr:hover .form-select.ds-select-ajustado:not(:hover):not(:focus):not(.ds-atencion),
    body.ui-v2 .ui-tabla > tbody > tr.ds-f-hover .form-select.ds-select-ajustado:not(.ds-atencion) { background-color: var(--ds-neutro-hover); }
}
body.ui-v2 .ui-tabla > tbody > tr:has(> td > .tb-sel:checked) .form-select.ds-select-ajustado:not(:focus):not(.ds-atencion),
body.ui-v2 .ui-tabla > tbody > tr.ds-f-activo .form-select.ds-select-ajustado:not(.ds-atencion) { background-color: var(--ds-superficie); }
body.ui-v2 .form-select.ds-select-celda.ds-select-ajustado.ds-atencion {
    border-color: var(--ds-acento);
    background-color: var(--ds-superficie);
}
body.ui-v2 .form-select.ds-select-celda.ds-select-ajustado:disabled {
    border-color: transparent;
    background-color: var(--ds-neutro-fondo);
}
/* "+N" dentro de la línea secundaria, junto a la cifra (así el nombre de la
   primera línea usa todo el ancho). La línea mide 16 px (letra de 12): el "+N"
   usa ese alto; su área de toque sigue siendo de 22 px.
   <div class="ds-celda-secundaria"><span class="ds-celda-cifra">Q 125,400.00</span>
     <button type="button" class="ds-mas">+2</button></div> */
body.ui-v2 .ds-celda > .ds-celda-secundaria:has(> .ds-mas) {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}
body.ui-v2 .ds-celda > .ds-celda-secundaria:has(> .ds-mas) > * { flex: none; }
body.ui-v2 .ds-celda > .ds-celda-secundaria:has(> .ds-mas) > .ds-celda-texto { flex: 0 1 auto; min-width: 16px; }
body.ui-v2 .ds-celda-secundaria > .ds-mas {
    min-width: 1.9em;
    min-height: 0;
    padding: 0 5px;
    font-size: 11px;
    line-height: 1.45455;       /* 16 px, el alto de la línea; sin unidad: crece con el texto */
}
body.ui-v2 .ds-celda-secundaria > button.ds-mas::after { inset: -3px -1px; }
/* Celda de dos líneas HOLGADA: 0.2em entre las líneas cuando las dos son
   píldoras (Estado + "Desierto"), que así no se tocan; la fila crece 3 px solo
   ahí. <div class="ds-celda ds-celda-holgada">…</div> */
body.ui-v2 .ds-celda.ds-celda-holgada { gap: 0.2em; }
body.ui-v2 .ds-celda.ds-celda-holgada > .ds-celda-principal { height: auto; min-height: 1.3077em; }
body.ui-v2 .ds-celda.ds-celda-holgada > .ds-celda-secundaria { height: auto; min-height: 1.33334em; overflow: visible; }
/* Líneas apiladas sin .ds-celda (descripción y su característica debajo, una
   segunda línea gris de un código): 2 px de aire entre la línea y la gris. */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td > .ds-celda-secundaria,
body.ui-v2 .ds-panel-tabla .ds-tabla > tbody > tr > td > .ds-celda > .ds-celda-secundaria { margin-top: 2px; }
body.ui-v2 .ds-celda-meta { margin-top: 2px; }
body.ui-v2 .ds-celda-meta .ds-pildora { vertical-align: baseline; }
/* texto recortable bajo el estado que puede ser más largo que el tope normal
   (16ch). Tope medio: "Compra directa · NOG 32099223" entero; con OC termina
   en "…" (texto entero en title). Con 42ch esa línea (268 px) ensanchaba
   Estado a 292 px y Centro de costo se cortaba a 1440. */
body.ui-v2 .ds-celda-texto-amplia { --ds-texto-max: 26ch; }
/* texto recortable sin tope mientras quepa (p. ej. "Creado por …"); con el
   contenido angosto (< 1150 px) toma un tope como los demás */
body.ui-v2 .ds-celda-texto-libre { --ds-texto-max: none; }
@container contenido (max-width: 1149.98px) {
    body.ui-v2 .ds-celda-texto-amplia { --ds-texto-max: 22ch; }
    body.ui-v2 .ds-celda-texto-libre { --ds-texto-max: 24ch; }
}
/* píldora de estado envuelta en un <span title> (el detalle va en el title) */
body.ui-v2 .ds-pildora-con-titulo { display: inline-flex; min-width: 0; }
/* lugar del "⋯" en una fila sin más acciones (las columnas no bailan) */
body.ui-v2 .ds-acciones-hueco { display: inline-block; width: 32px; height: 1px; margin-left: 2px; }
/* celda alineada arriba (varias líneas de alto distinto en la fila) */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.ds-celda-arriba { vertical-align: top; padding-top: 10px; padding-bottom: 10px; }
/* acciones de la fila debajo del texto (en vez de una columna aparte) */
body.ui-v2 .ds-acciones-debajo { display: flex; flex-wrap: wrap; justify-content: flex-start; margin-top: 6px; }
/* Enlace principal de una fila (código que abre la ficha): acento oscuro y
   seminegrita, sin subrayado (una columna de enlaces subrayados se lee como
   ruido); subrayado al pasar el mouse o con foco. */
body.ui-v2 a.ds-enlace-fila { color: var(--ds-acento-oscuro); font-weight: 600; text-decoration: none; font-variant-numeric: tabular-nums; }
body.ui-v2 a.ds-enlace-fila:hover,
body.ui-v2 a.ds-enlace-fila:focus-visible { text-decoration: underline; }
/* cualquier enlace de texto dentro de una tabla o de una lista de datos, igual
   que .ds-enlace-fila: sin subrayado, subrayado al pasar o con foco (antes
   unas pantallas subrayaban "ADM-24-2026" o "15 creada" y otras no) */
body.ui-v2 :is(.ds-tabla, .ui-tabla, .ds-datos) a:not([class*="btn"], .dropdown-item, .ds-chip, .ds-pildora, .page-link) { text-decoration: none; }
body.ui-v2 :is(.ds-tabla, .ui-tabla, .ds-datos) a:not([class*="btn"], .dropdown-item, .ds-chip, .ds-pildora, .page-link):is(:hover, :focus-visible) { text-decoration: underline; }
/* código gris antes de un nombre (renglón, programa): "111 Energía eléctrica" */
body.ui-v2 .ds-codigo-gris { color: var(--ds-texto-2); font-variant-numeric: tabular-nums; }
/* Punto de estado junto a una cifra y marca de aviso junto a un dato:
   <span class="ds-cifra-con-punto"><span class="ds-punto ds-punto-aviso" title="…"></span>0.75</span> */
body.ui-v2 .ds-cifra-con-punto { display: inline-flex; align-items: center; gap: 6px; font-variant-numeric: tabular-nums; white-space: nowrap; }
body.ui-v2 .ds-punto {
    flex: none;
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--ds-texto-3);
}
body.ui-v2 .ds-punto-exito { background: var(--ds-exito-punto); }
body.ui-v2 .ds-punto-aviso { background: var(--ds-aviso-punto); }
body.ui-v2 .ds-punto-error { background: var(--ds-error-punto); }
body.ui-v2 .ds-punto-error-oscuro { background: var(--ds-error-punto-oscuro); }
body.ui-v2 .ds-punto-info { background: var(--ds-acento); }
body.ui-v2 .ds-punto-neutro { background: var(--ds-texto-3); }
/* ícono de aviso junto a un dato (p. ej. "recalculado"): 14 px, color aviso */
body.ui-v2 .ds-marca-aviso { display: inline-flex; align-items: center; color: var(--ds-aviso); font-size: 14px; line-height: 1; cursor: help; }
/* Interruptor solo dentro de una celda (sin rótulo): sin sangría */
body.ui-v2 .form-switch.ds-interruptor-celda {
    display: inline-flex;
    align-items: center;
    min-height: 0;
    margin: 0;
    padding: 0;
    vertical-align: middle;
}
body.ui-v2 .form-switch.ds-interruptor-celda > .form-check-input { float: none; margin: 0; cursor: pointer; }
/* nombre de archivo largo en una celda: se parte donde haga falta */
body.ui-v2 .ds-archivo { color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); line-height: 1.33334; overflow-wrap: anywhere; }
/* Fila de detalle bajo una fila (motivo de un rechazo): texto 12 en rojo, sin
   línea entre las dos. <tr class="ds-fila-detalle"><td colspan="…"><span class="ds-fila-detalle-texto">…</span></td></tr> */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr:has(+ tr.ds-fila-detalle) > td { border-bottom-color: transparent; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr.ds-fila-detalle > td { height: auto; padding-top: 2px; padding-bottom: 10px; white-space: normal; }
body.ui-v2 .ds-fila-detalle-texto { display: inline-flex; align-items: flex-start; gap: 6px; color: var(--ds-error); font-size: var(--ds-tam-etiqueta); line-height: 1.33334; overflow-wrap: anywhere; }
body.ui-v2 .ds-fila-detalle-texto > .ti { flex: none; font-size: 14px; line-height: 1.14286; }
/* fila con una celda de dos líneas en densidad compacta: 44 px también en la
   última fila (que no lleva línea abajo y medía 43) */
body.ui-v2 .ds-tabla-compacta > tbody > tr > td:has(> .ds-celda) { height: 3.3847em; }
/* segunda línea gris de un dato ("hace 3 días" bajo la fecha) */
body.ui-v2 .ds-dato-linea { display: block; color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); line-height: 1.33334; }
/* Encabezado ordenable por ENLACE, para tablas hechas a mano cuyo orden hace
   el servidor (?orden=…&direccion=…); mismo aspecto que el de TablaDatos.
   <th aria-sort="ascending"><a class="ds-th-orden" href="…"><span>Renglón</span><i class="ti ti-arrow-up"></i></a></th> */
body.ui-v2 .ds-th-orden {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    max-width: 100%;
    margin: 0 -4px;
    padding: 2px 4px;
    border-radius: 6px;
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
    transition: color var(--ds-transicion), background-color var(--ds-transicion);
}
body.ui-v2 .ds-th-orden:hover,
body.ui-v2 .ds-th-orden.ds-f-hover { color: var(--ds-texto); background: var(--ds-hover); }
body.ui-v2 .ds-th-orden:focus-visible { outline: 0; box-shadow: var(--tb-anillo); }
body.ui-v2 th[aria-sort] > .ds-th-orden { color: var(--ds-texto); }
body.ui-v2 .ds-th-orden > .ti { color: var(--ds-acento-oscuro); font-size: 14px; line-height: 1; }
/* en columnas de número, el título se alinea a la derecha como la cifra */
body.ui-v2 th.ds-col-monto > .ds-th-orden,
body.ui-v2 th.ds-num > .ds-th-orden { flex-direction: row-reverse; }


/* 25c. Tablas con forma propia ----------------------------------------------- */
/* Tabla hecha a mano con selección, que cabe en la ventana:
   <div class="ds-tabla-con-seleccion">
     <div class="ds-tabla-marco ds-tabla-ajustable"><div class="table-responsive">
       <table class="table table-hover ds-tabla ds-tabla-compacta ds-tabla-fija">…</table>
     </div></div>
     <div class="ds-barra-seleccion" hidden>…</div>
   </div>
   El JS de la página pone max-height al .table-responsive (alto de la ventana
   menos lo de arriba): la tabla se desplaza por dentro con el encabezado fijo
   (.ds-tabla-fija, §15a) y la página no. */
body.ui-v2 .ds-tabla-ajustable > .table-responsive { overflow: auto; scrollbar-width: thin; }
/* menos cromo vertical (como la sábana, §3d): encabezado y filtros a 8 px, el
   marco termina 12 px sobre el borde de la ventana. Meta: 12 filas a 1440×790. */
body.ui-v2 .ds-contenido:has(.ds-tabla-ajustable) { padding-bottom: var(--ds-e3); }
body.ui-v2 .ds-contenido:has(.ds-tabla-ajustable) > .ds-encabezado { margin-bottom: var(--ds-e2); }
body.ui-v2 .ds-contenido:has(.ds-tabla-ajustable) > .ds-filtros-get { margin-bottom: var(--ds-e2); }
/* el buscador de la barra superior reemplaza al de la lista (ui.js) */
body.ui-v2 .ds-buscador-get.ds-oculto-por-barra { display: none !important; }
/* con la barra de selección a la vista, espacio al final para que la última
   fila pase por encima de la barra (como el .tb-marco de TablaDatos, §23i) */
body.ui-v2 .ds-tabla-con-seleccion:has(> .ds-barra-seleccion:not([hidden])) .ds-tabla-marco > .table-responsive::after {
    content: "";
    display: block;
    height: 76px;
}
/* fila marcada con su casilla: celeste claro (como la selección de TablaDatos) */
body.ui-v2 .ds-tabla > tbody > tr:has(> td > input.form-check-input:checked) > * { --bs-table-bg-state: var(--ds-fila-seleccionada); }
body.ui-v2 .ds-tabla > thead > tr > th > .form-check-input,
body.ui-v2 .ds-tabla > tbody > tr > td > .form-check-input { float: none; margin: 0; vertical-align: middle; }
body.ui-v2 .ds-tabla > thead > tr > th:has(> .form-check-input),
body.ui-v2 .ds-tabla > tbody > tr > td:has(> .form-check-input) { padding-right: 4px; }
body.ui-v2 .ds-tabla > thead > tr > th:first-child:has(> .form-check-input):empty { padding-right: 4px; }
/* celda de la casilla vacía (fila que no se puede marcar): mismo ancho */
body.ui-v2 .ds-tabla-con-seleccion .ds-tabla > tbody > tr > td.ds-col-ajustada:first-child:empty::after,
body.ui-v2 .ds-tabla-con-seleccion .ds-tabla > tbody > tr > td.ds-col-ajustada:first-child:not(:has(*))::after { content: ""; display: inline-block; width: 1em; }
/* estado vacío dentro de la tabla: sin línea ni gris al pasar el mouse */
body.ui-v2 .ds-tabla > tbody > tr.ds-fila-vacia > td {
    height: auto;
    padding: var(--ds-e6) var(--ds-e4);
    border-bottom: 0;
    --bs-table-bg-state: transparent;
    text-align: center;
    white-space: normal;
}
/* dato secundario de la barra de selección ("2 se pueden enviar") */
body.ui-v2 .ds-barra-seleccion-detalle {
    margin-right: var(--ds-e1);
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
@media print {
    body.ui-v2 .ds-tabla-ajustable > .table-responsive { max-height: none !important; overflow: visible; }
    body.ui-v2 .ds-acciones-hueco { display: none; }
}
/* Tabla con riel de línea de tiempo: etapas o movimientos con muchas columnas
   (fecha, estado, montos) con un riel a la izquierda (punto del color del
   estado y línea que une las filas), como .ds-linea-tiempo.
   <table class="table ds-tabla ds-tabla-tiempo">…<td class="ds-tiempo"><span class="ds-tiempo-punto ds-tiempo-exito"></span></td>…
   Tonos: -exito, -aviso, -error, -info, -neutro (gris). */
body.ui-v2 .ds-tabla-tiempo > :is(thead, tbody) > tr > :is(th, td).ds-tiempo {
    position: relative;
    width: 1%;
    padding-right: 4px;
}
body.ui-v2 .ds-tabla-tiempo > tbody > tr > td.ds-tiempo::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: -1px;
    left: calc(var(--ds-e4) + 4.5px);
    width: 1px;
    background: var(--ds-borde-fuerte);
}
body.ui-v2 .ds-tabla-tiempo > tbody > tr:first-child > td.ds-tiempo::before { top: 50%; }
body.ui-v2 .ds-tabla-tiempo > tbody > tr:last-child > td.ds-tiempo::before { bottom: 50%; }
body.ui-v2 .ds-tabla-tiempo > tbody > tr:only-child > td.ds-tiempo::before { display: none; }
body.ui-v2 .ds-tiempo-punto {
    --ds-tiempo-color: var(--ds-texto-3);
    position: relative;
    display: block;
    width: 10px;
    height: 10px;
    border: 2px solid var(--ds-superficie);
    border-radius: 50%;
    background: var(--ds-tiempo-color);
    box-shadow: 0 0 0 1px var(--ds-tiempo-color);
}
body.ui-v2 .ds-tiempo-punto.ds-tiempo-exito { --ds-tiempo-color: var(--ds-exito-punto); }
body.ui-v2 .ds-tiempo-punto.ds-tiempo-aviso { --ds-tiempo-color: var(--ds-aviso-punto); }
body.ui-v2 .ds-tiempo-punto.ds-tiempo-error { --ds-tiempo-color: var(--ds-error-punto); }
body.ui-v2 .ds-tiempo-punto.ds-tiempo-info { --ds-tiempo-color: var(--ds-acento); }
/* Tabla agrupada: cada <tbody> empieza con su fila de grupo (fondo gris muy
   claro, 12/600), p. ej. el producto de sus subproductos. En el teléfono
   (< 576 px) cada fila es un bloque: el código gris arriba y el nombre a todo
   el ancho debajo; el encabezado queda solo para lectores de pantalla. */
body.ui-v2 .ds-tabla-agrupada > tbody > tr.ds-fila-grupo > th {
    height: auto;
    padding: 8px 12px;
    border-bottom: 1px solid var(--ds-borde);
    background: var(--ds-fondo);
    color: var(--ds-texto);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 600;
    line-height: 1.33334;
    white-space: normal;
}
body.ui-v2 .ds-tabla-agrupada > tbody > tr.ds-fila-grupo > th:first-child { padding-left: var(--ds-e4); }
body.ui-v2 .ds-tabla-agrupada > tbody + tbody > tr.ds-fila-grupo > th { border-top: 1px solid var(--ds-borde); }
body.ui-v2 .ds-tabla-agrupada > tbody > tr.ds-fila-grupo:hover > * { --bs-table-bg-state: transparent; }
@media (max-width: 575.98px) {
    body.ui-v2 .ds-tabla-agrupada > thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
    }
    body.ui-v2 .ds-tabla-agrupada > tbody > tr:not(.ds-fila-grupo) { display: flex; flex-direction: column; border-bottom: 1px solid var(--ds-borde); }
    body.ui-v2 .ds-tabla-agrupada > tbody > tr:not(.ds-fila-grupo) > td {
        width: auto;
        height: auto;
        padding: 0 var(--ds-e4);
        border: 0;
        white-space: normal;
    }
    body.ui-v2 .ds-tabla-agrupada > tbody > tr:not(.ds-fila-grupo) > td:first-child { padding-top: 10px; color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); line-height: 1.33334; }
    body.ui-v2 .ds-tabla-agrupada > tbody > tr:not(.ds-fila-grupo) > td:last-child { padding-bottom: 10px; line-height: 1.38462; }
    body.ui-v2 .ds-tabla-agrupada > tbody:last-child > tr:last-child { border-bottom: 0; }
    body.ui-v2 .ds-tabla-agrupada > :is(thead, tbody) > tr > :is(th, td)::after { display: none; }
}
/* Tabla que se desplaza en su caja (22 líneas y media, más o menos) con
   encabezado fijo: <div class="ds-tabla-desplazable"><table class="table ds-tabla ds-tabla-fija">… */
body.ui-v2 .ds-tabla-desplazable { max-height: 30em; overflow: auto; scrollbar-width: thin; }
body.ui-v2 .ds-tabla-desplazable .ds-tabla-fija > thead > tr > th { position: sticky; top: 0; z-index: 2; }
body.ui-v2 .ds-tabla-desplazable .ds-tabla > tbody > tr:last-child > td { border-bottom: 0; }
/* Tabla dentro de un panel lateral, de borde a borde del panel:
   <div class="ds-panel-tabla"><table class="table ds-tabla ds-tabla-compacta">… */
body.ui-v2 .ds-panel-tabla { margin: 0 -24px; border-top: 1px solid var(--ds-borde); border-bottom: 1px solid var(--ds-borde); }
body.ui-v2 .ds-panel-tabla .ds-tabla > :is(thead, tbody) > tr > :is(th, td):first-child { padding-left: 24px; }
body.ui-v2 .ds-panel-tabla .ds-tabla > :is(thead, tbody) > tr > :is(th, td):last-child { padding-right: 24px; }
body.ui-v2 .ds-panel-tabla .ds-tabla > tbody > tr:last-child > td { border-bottom: 0; }
@media (max-width: 575.98px) {
    body.ui-v2 .ds-panel-tabla .ds-tabla > :is(thead, tbody) > tr > :is(th, td):first-child { padding-left: 16px; }
    body.ui-v2 .ds-panel-tabla .ds-tabla > :is(thead, tbody) > tr > :is(th, td):last-child { padding-right: 12px; }
}


/* 25d. Barra de filtros: rótulo, casillas con código, píldora fija, buscadores */
/* Rótulo en línea antes de un control de la barra ("Centro de costo",
   "Severidad"): <span class="ds-filtros-rotulo">Severidad</span> */
body.ui-v2 .ds-filtros-rotulo {
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    font-weight: 500;
    line-height: 1.38462;
    white-space: nowrap;
}
/* Casillas del panel de una píldora con código + nombre (renglones): el nombre
   se parte en líneas y la casilla queda arriba, en la primera.
   <label><input type="checkbox" …><span class="ds-casilla-texto"><span class="ds-casilla-codigo">266</span> Nombre</span></label> */
/* el panel hereda white-space: nowrap de .ds-pildora-filtro (§6c): sin esto el
   nombre largo del renglón se salía del panel y se cortaba */
body.ui-v2 .ds-pildora-panel :is(.ds-casillas, .ds-casillas-vacio) { white-space: normal; }
body.ui-v2 .ds-pildora-panel .ds-casillas > label { align-items: flex-start; line-height: 1.38462; font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-pildora-panel .ds-casillas > label > .form-check-input { flex: none; margin-top: 0.08em; }
body.ui-v2 .ds-pildora-panel .ds-casilla-texto {
    min-width: 0;
    color: var(--ds-texto);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
body.ui-v2 .ds-casilla-codigo { font-weight: 600; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-casillas-vacio {
    margin: 0;
    padding: 6px 8px;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
/* Píldora informativa fija dentro de la barra (un solo valor posible, p. ej. el
   único centro de costo del usuario): alto de chip */
body.ui-v2 .ds-pildora.ds-pildora-fija { min-height: var(--ds-alto-chip); padding: 0 14px; font-size: var(--ds-tam-tabla); white-space: normal; line-height: 1.38462; }
/* Píldora de filtro activa que no abre panel (un filtro puesto desde otra
   parte, p. ej. una tarjeta): <div class="ds-pildora-filtro ds-pildora-filtro-activa">
   <span class="ds-pildora-filtro-boton ds-pildora-filtro-fija">…</span><button class="ds-pildora-filtro-quitar">✕</button></div> */
body.ui-v2 .ds-pildora-filtro-boton.ds-pildora-filtro-fija { cursor: default; }
/* Select en píldora con opciones muy largas (nombres de renglón de hasta 100
   letras): tope en em; 27em deja entero el nombre del renglón más usado (266)
   y el resto se ve con "…" y en el title. */
body.ui-v2 .ds-pildora-select.ds-pildora-select-tope { max-width: 27em; }
/* Campos de búsqueda en píldora con rótulo (filtros que se aplican mientras se
   escribe, sin formulario GET): la misma píldora de .ds-buscador-get con un
   rótulo corto adentro. <label class="ds-buscador-get ds-buscador-rotulado"><span
   class="ds-buscador-rotulo">IGSS</span><input type="search" …></label>;
   .ds-buscador-ancho: el campo de texto principal (crece; ancho con width y no
   con flex-basis: en la columna de .ds-filtros-get una base flexible hacía
   medir la fila en dos líneas). */
body.ui-v2 .ds-buscador-get.ds-buscador-rotulado { width: auto; min-width: 0; }
body.ui-v2 .ds-buscador-rotulado > .ds-buscador-rotulo {
    position: absolute;
    left: 14px;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    font-weight: 500;
    line-height: 1.38462;
    pointer-events: none;
}
body.ui-v2 .ds-buscador-rotulado > input { width: 12em; padding-left: 4.9em; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-buscador-rotulado.ds-buscador-ancho { flex: 0 1 auto; width: 30em; min-width: 14em; max-width: 100%; }
body.ui-v2 .ds-buscador-rotulado.ds-buscador-ancho > input { width: 100%; padding-left: 36px; }
body.ui-v2 .ds-buscador-get.ds-buscador-activo > .ds-buscador-rotulo { color: var(--ds-acento-oscuro); }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-filtros-fila-envuelve > .ds-buscador-rotulado:not(.ds-buscador-ancho) { flex: 1 1 8em; }
    body.ui-v2 .ds-filtros-fila-envuelve > .ds-buscador-rotulado:not(.ds-buscador-ancho) > input { width: 100%; }
    body.ui-v2 .ds-filtros-fila-envuelve > .ds-pildora-select { flex: 1 1 100%; max-width: 100%; }
}
/* Buscador de un formulario GET más ancho (búsqueda por varios campos: "NIT,
   razón social o nombre comercial"): el placeholder entero. */
body.ui-v2 .ds-buscador-get:has(> input.ds-buscador-largo) { width: 24em; }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-buscador-get:has(> input.ds-buscador-largo) { width: 100%; }
}
/* Fila con varios buscadores (<div class="ds-filtros-fila ds-filtros-flexible">):
   se encogen (piso 13em) antes de bajar de renglón; tope 22em. */
body.ui-v2 .ds-filtros-fila.ds-filtros-flexible > .ds-buscador-get { flex: 1 1 13em; width: auto; min-width: 13em; max-width: 22em; }
/* barra de filtros GET dentro de la cabeza de una tarjeta: sin margen propio */
body.ui-v2 .ds-filtros-get.ds-filtros-en-linea { margin: 0; }


/* 25e. Indicadores: tarjeta que es botón, resumen con distribución, montos --- */
/* Indicador (KPI) que es botón y filtra al hacer clic:
   <button type="button" class="ds-kpi ds-kpi-aviso" aria-pressed="false">…</button>
   Igual que la tarjeta de indicador; al pasar el mouse, sombra flotante; el
   activo (aria-pressed="true" o .activo) lleva el anillo acento, como a.ds-kpi. */
body.ui-v2 button.ds-kpi {
    width: 100%;
    margin: 0;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    transition: border-color var(--ds-transicion), box-shadow var(--ds-transicion), background-color var(--ds-transicion);
}
body.ui-v2 button.ds-kpi:hover,
body.ui-v2 button.ds-kpi.ds-f-hover { border-color: var(--ds-borde-fuerte); box-shadow: var(--ds-sombra-flotante); }
body.ui-v2 button.ds-kpi:focus-visible,
body.ui-v2 button.ds-kpi.ds-f-foco { outline: 0; border-color: var(--ds-acento); box-shadow: var(--tb-anillo); }
body.ui-v2 button.ds-kpi.activo,
body.ui-v2 button.ds-kpi[aria-pressed="true"],
body.ui-v2 button.ds-kpi.ds-f-activo { border-color: var(--ds-acento); box-shadow: 0 0 0 1px var(--ds-acento); }
body.ui-v2 button.ds-kpi .ds-kpi-valor-fila { align-items: baseline; }
/* tono "error oscuro" (más grave que error: p. ej. desabastecimiento total) */
body.ui-v2 .ds-kpi-error-oscuro .ds-kpi-icono { background: var(--ds-error); color: var(--ds-texto-sobre-relleno); }
/* Resumen con barra de distribución: la barra (partes de un total, §24n) sobre
   las tarjetas que la desglosan.
   <section class="ds-resumen-distribucion"><div class="ds-distribucion">…</div><div class="ds-kpis">…</div></section> */
body.ui-v2 .ds-resumen-distribucion { margin-bottom: var(--ds-e5); }
body.ui-v2 .ds-resumen-distribucion > .ds-distribucion { margin-bottom: var(--ds-e3); }
body.ui-v2 .ds-resumen-distribucion > .ds-kpis { margin-bottom: 0; }
body.ui-v2 .ds-distribucion-parte.ds-parte-error-oscuro { background: var(--ds-error-punto-oscuro); }
body.ui-v2 .ds-distribucion.ds-distribucion-vacia { background: var(--ds-neutro-fondo); }
/* Indicadores con montos (.ds-kpis-montos): "Q 16,054,123.45" nunca se parte
   ni se sale de la tarjeta: cada tarjeta es un contenedor y el valor toma su
   letra del ancho de la tarjeta (10.5cqi ≈ un monto de 15 caracteres a lo
   ancho), entre 16 px y la letra normal del indicador (26; 20 en compactos).
   Bajo 1280 (sin columnas fijas) una tarjeta no baja de 15em: en el teléfono,
   una por renglón. */
body.ui-v2 .ds-kpis-montos > .ds-kpi { container-type: inline-size; }
body.ui-v2 .ds-kpis-montos .ds-kpi-valor {
    font-size: clamp(16px, 10.5cqi, var(--ds-tam-titulo));
    font-variant-numeric: tabular-nums;
    overflow-wrap: normal;
    white-space: nowrap;
}
body.ui-v2 .ds-kpis-montos.ds-kpis-compactos .ds-kpi-valor { font-size: clamp(16px, 10.5cqi, 20px); }
@media (max-width: 1279.98px) {
    body.ui-v2 .ds-kpis.ds-kpis-montos { grid-template-columns: repeat(auto-fit, minmax(min(100%, 15em), 1fr)); }
}
/* Indicadores en una línea (<div class="ds-kpis ds-kpis-en-linea">), desde
   768 px: ícono a la izquierda, etiqueta arriba y detalle debajo al centro,
   valor a la derecha; ~50 px de alto en vez de ~86. Vale para el marcado del
   macro ds.kpi (valor y detalle sueltos; sin `info` ni `delta`) y para el de
   abastecimiento.js (valor y detalle en .ds-kpi-valor-fila). Tarjeta angosta
   (< 20em): sin el ícono, para que la etiqueta quepa. En el teléfono queda la
   tarjeta de siempre (etiqueta arriba, valor abajo). */
@media (min-width: 768px) {
    body.ui-v2 .ds-kpis-en-linea > .ds-kpi {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr) auto;
        grid-template-areas: "icono etiqueta valor" "icono detalle valor";
        align-items: center;
        gap: 0;
        padding: var(--ds-e2) var(--ds-e4);
        container-type: inline-size;
    }
    body.ui-v2 .ds-kpis-en-linea > .ds-kpi > :is(.ds-kpi-etiqueta, .ds-kpi-valor-fila) { display: contents; }
    body.ui-v2 .ds-kpis-en-linea .ds-kpi-icono { grid-area: icono; margin-right: var(--ds-e3); }
    body.ui-v2 .ds-kpis-en-linea .ds-kpi-etiqueta > span:not(.ds-kpi-icono) { grid-area: etiqueta; align-self: end; min-width: 0; line-height: 1.3; overflow-wrap: break-word; }
    body.ui-v2 .ds-kpis-en-linea .ds-kpi-detalle { grid-area: detalle; align-self: start; font-size: var(--ds-tam-etiqueta); line-height: 1.3; }
    body.ui-v2 .ds-kpis-en-linea .ds-kpi-valor { grid-area: valor; margin-left: var(--ds-e3); font-size: 20px; line-height: 1.2; white-space: nowrap; }
    body.ui-v2 .ds-kpis-en-linea > .ds-kpi > .ds-barra-avance { grid-column: 1 / -1; margin-top: var(--ds-e1); }
}
@container (max-width: 20em) {
    body.ui-v2 .ds-kpis-en-linea .ds-kpi-icono { display: none; }
}
/* Indicadores con montos en una línea (.ds-kpis-montos.ds-kpis-en-linea: Órdenes
   de Compra). "Q 55,173,992.22" pide ~15 caracteres: el valor toma su letra del
   ancho de la tarjeta (6.4cqi: 18 px en la tarjeta de 1440, 20 px desde ~310 px
   de contenido, 16 px a 1280) y el ícono se oculta bajo 24em, así etiqueta y
   detalle quedan en UNA línea a 1440 (60 px de alto). Menos aire bajo la fila
   de indicadores (16 px): la tabla gana una fila a 1440×790. En el teléfono,
   la tarjeta de siempre (con ícono). */
@media (min-width: 768px) {
    body.ui-v2 .ds-kpis-montos.ds-kpis-en-linea .ds-kpi-valor { font-size: clamp(16px, 6.4cqi, 20px); }
    body.ui-v2 .ds-kpis.ds-kpis-montos.ds-kpis-en-linea { margin-bottom: var(--ds-e4); }
    @container (max-width: 24em) {
        body.ui-v2 .ds-kpis-montos.ds-kpis-en-linea .ds-kpi-icono { display: none; }
    }
}


/* 25f. Píldoras, marcas y botones ---------------------------------------------- */
/* Píldora que es enlace; píldora de conteo (cifra centrada de ancho estable) */
body.ui-v2 a.ds-pildora { text-decoration: none; transition: filter var(--ds-transicion), box-shadow var(--ds-transicion); }
body.ui-v2 a.ds-pildora:hover { filter: brightness(0.95); }
body.ui-v2 a.ds-pildora:focus-visible { outline: 0; box-shadow: var(--tb-anillo); }
body.ui-v2 .ds-pildora.ds-pildora-conteo { justify-content: center; min-width: 3.6em; font-variant-numeric: tabular-nums; }
/* Píldora de contorno: aviso más suave que la píldora llena (solo borde
   punteado, sin relleno): "verifique", no "es así". .ds-marca-debajo: la
   píldora baja a su propia línea bajo un código. */
body.ui-v2 .ds-pildora.ds-pildora-contorno {
    background: transparent;
    color: var(--ds-aviso);
    border: 1px dashed var(--ds-ambar-punto);
    padding: calc(0.0834em - 1px) calc(0.6667em - 1px);   /* el borde no la agranda: mide lo de toda píldora (§7) */
}
body.ui-v2 .ds-pildora.ds-marca-debajo { display: flex; width: max-content; max-width: 100%; margin-top: 4px; white-space: nowrap; }
body.ui-v2 .ds-codigo-fuerte,
body.ui-v2 .ds-celda-codigo { font-weight: 600; color: var(--ds-texto); font-variant-numeric: tabular-nums; }
/* Marca de contrato abierto (enlace a Guatecompras). Firme (esta presentación
   exacta): píldora aviso con latido lento, solo opacidad (un elemento que
   cambia de tamaño nunca queda "estable" para un navegador automatizado).
   Aviso (otra presentación del mismo código): solo contorno discontinuo, sin
   latido.
   <a class="ds-pildora ds-pildora-aviso ds-pildora-sm ds-marca-contrato ds-latido" …>
   <a class="ds-etiqueta ds-etiqueta-aviso ds-marca-contrato ds-marca-contrato-aviso" …> */
@keyframes ds-latido { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
body.ui-v2 .ds-latido { animation: ds-latido 1.8s ease-in-out infinite; }
body.ui-v2 .ds-marca-contrato {
    display: flex;
    width: max-content;
    max-width: 100%;
    margin-top: 4px;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}
body.ui-v2 .ds-marca-contrato:hover { animation: none; filter: brightness(0.95); }
body.ui-v2 .ds-marca-contrato.ds-marca-contrato-aviso { border-style: dashed; font-weight: 500; }
body.ui-v2 .ds-marca-contrato > .ti { font-size: 13px; }
@media (prefers-reduced-motion: reduce) { body.ui-v2 .ds-latido { animation: none; } }
/* Píldora que es botón (un aviso del pie que lleva a su tarjeta) */
body.ui-v2 button.ds-pildora.ds-pildora-accion {
    border: 0;
    cursor: pointer;
    transition: background-color var(--ds-transicion), box-shadow var(--ds-transicion);
}
body.ui-v2 button.ds-pildora.ds-pildora-aviso.ds-pildora-accion:hover { background: color-mix(in srgb, var(--ds-aviso-fondo), var(--ds-ambar-borde)); }
body.ui-v2 button.ds-pildora.ds-pildora-accion:focus-visible { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 2px; }
/* Botón con conteo (carrito): <button class="ds-btn ds-btn-primario"><i …></i>
   <span>Listado</span><span class="ds-btn-conteo">3</span></button>
   .ds-btn-con-conteo (hay algo): el conteo en blanco lleno. .ds-pulso: un latido
   corto de escala al sumar (una vez; el JS vuelve a ponerlo). */
body.ui-v2 .ds-btn-conteo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.7em;
    padding: 1px 7px;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-conteo-sobre-relleno);          /* sobre el primario: blanco 7.57:1 (con blanco al 20 % era 3.70:1) */
    color: inherit;
    font-size: var(--ds-tam-etiqueta);
    font-weight: 600;
    line-height: 1.33334;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .ds-btn-secundario .ds-btn-conteo { background: var(--ds-neutro-fondo); color: var(--ds-neutro); }
body.ui-v2 .ds-btn-con-conteo .ds-btn-conteo { background: var(--ds-superficie); color: var(--ds-relleno-primario); }
@keyframes ds-pulso { 0% { transform: scale(1); } 40% { transform: scale(1.06); } 100% { transform: scale(1); } }
body.ui-v2 .ds-pulso { animation: ds-pulso 0.35s ease; }
@media (prefers-reduced-motion: reduce) { body.ui-v2 .ds-pulso { animation: none; } }
/* botón de fila que ya cumplió ("En el listado"): terciario en verde */
body.ui-v2 .ds-btn.ds-btn-en-lista { color: var(--ds-exito); }


/* 25g. Tarjetas, subpaneles, plegables y acordeón ------------------------------ */
/* Tarjeta plana mientras su contenido está oculto (p. ej. el cruce antes de
   pedirlo): solo su cabeza, sin línea ni relleno de más abajo. Pie de tarjeta
   cuyo único contenido está oculto: no se dibuja. */
body.ui-v2 .ds-tarjeta-plana:has(> .ds-tarjeta-cuerpo > [hidden]:only-child) > .ds-tarjeta-cabeza { padding-bottom: var(--ds-e4); border-bottom: 0; }
body.ui-v2 .ds-tarjeta-pie:has(> [hidden]:only-child) { display: none; }
/* Tarjeta numerada (paso de un formulario) con línea bajo el título: el número
   y las acciones se alinean con el título, arriba. */
body.ui-v2 .ds-tarjeta-cabeza:has(> .ds-tarjeta-numero):has(.ds-tarjeta-linea) > .ds-tarjeta-numero { align-self: flex-start; margin-top: 0; }
body.ui-v2 .ds-tarjeta-cabeza:has(> .ds-tarjeta-numero):has(.ds-tarjeta-linea) > .ds-tarjeta-acciones { align-self: flex-start; }
/* estado de una tarjeta junto a su título (píldora "Listo"/"Pendiente") */
body.ui-v2 .ds-tarjeta-estado { display: inline-flex; align-items: center; }
body.ui-v2 .ds-tarjeta-estado:empty { display: none; }
/* Subpaneles dentro de una tarjeta (un grupo de una sección, p. ej. los insumos
   de un renglón): borde fino, radio 12, cabecera gris muy clara con título y
   resumen, tabla hasta el borde y, abajo, avisos y bloques con su relleno.
   <section class="ds-subpanel"><header class="ds-subpanel-cabeza">
     <h3 class="ds-subpanel-titulo">…</h3><span class="ds-pildora">…</span></header>
     <div class="table-responsive"><table class="table ds-tabla ds-tabla-compacta">…</table></div>
     <div class="ds-subpanel-bloque">…</div></section>
   .ds-subpanel-aviso: el grupo que necesita algo (cabecera ámbar suave). */
body.ui-v2 .ds-subpaneles { display: flex; flex-direction: column; gap: var(--ds-e4); }
body.ui-v2 .ds-subpaneles:empty { display: none; }
body.ui-v2 .ds-subpanel {
    min-width: 0;
    background: var(--ds-superficie);
    border: 1px solid var(--ds-borde-marco);
    border-radius: var(--ds-radio-campo);
}
body.ui-v2 .ds-subpanel-cabeza {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-e2) var(--ds-e3);
    min-height: 44px;
    padding: 8px var(--ds-e4);
    background: var(--ds-fondo);
    border-bottom: 1px solid var(--ds-borde);
    border-radius: calc(var(--ds-radio-campo) - 1px) calc(var(--ds-radio-campo) - 1px) 0 0;
}
body.ui-v2 .ds-subpanel-titulo {
    min-width: 0;
    margin: 0;
    color: var(--ds-texto);
    font-size: var(--ds-tam-cuerpo);
    font-weight: 600;
    line-height: 1.42858;
}
body.ui-v2 .ds-subpanel.ds-subpanel-aviso { border-color: var(--ds-ambar-borde); }
body.ui-v2 .ds-subpanel.ds-subpanel-aviso > .ds-subpanel-cabeza { background: var(--ds-aviso-fondo); border-bottom-color: var(--ds-ambar-borde); }
body.ui-v2 .ds-subpanel > .table-responsive > .ds-tabla > tbody > tr:last-child > td { border-bottom: 0; }
body.ui-v2 .ds-subpanel-bloque { padding: var(--ds-e3) var(--ds-e4) var(--ds-e4); border-top: 1px solid var(--ds-borde); }
body.ui-v2 .ds-subpanel-bloque > .ds-aviso { margin: 0; }
/* Tabla de líneas de un subpanel: la descripción ocupa lo que sobra; código,
   cantidad y quitar miden lo que piden. Anchos en em: las columnas quedan
   alineadas entre un grupo y otro (con reparto automático cada tabla medía
   distinto según sus marcas); en el teléfono, reparto automático. */
body.ui-v2 .ds-tabla-lineas > tbody > tr > td { vertical-align: top; padding-top: 10px; padding-bottom: 10px; }
body.ui-v2 .ds-tabla-lineas > tbody > tr > td.ds-celda-codigo { padding-top: 16px; }
body.ui-v2 .ds-tabla-lineas > tbody > tr > td.ds-celda-texto-linea { padding-top: 16px; overflow-wrap: anywhere; }
body.ui-v2 .ds-tabla-lineas > tbody > tr > td.ds-celda-texto-linea:has(> input) { padding-top: 10px; }
body.ui-v2 .ds-tabla-lineas > tbody > tr > td.ds-celda-letras { padding-top: 16px; color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); line-height: 1.5; }
body.ui-v2 .ds-tabla.ds-tabla-lineas { table-layout: fixed; }
body.ui-v2 .ds-tabla.ds-tabla-lineas > thead > tr > th.ds-col-codigo-linea { width: 15.5em; }
body.ui-v2 .ds-tabla.ds-tabla-lineas > thead > tr > th.ds-col-renglon { width: 20em; }
body.ui-v2 .ds-tabla.ds-tabla-lineas > thead > tr > th.ds-col-cantidad { width: 13em; }   /* el campo de cantidad (12 cifras, §25h) + el relleno de la celda: con 10.5em el campo se angostaba y cortaba "3456789.00" */
body.ui-v2 .ds-tabla.ds-tabla-lineas > thead > tr > th.ds-col-letras { width: 14em; }
body.ui-v2 .ds-tabla.ds-tabla-lineas > thead > tr > th.ds-col-ajustada { width: 8.5em; }
body.ui-v2 .ds-tabla-lineas > :is(thead, tbody) > tr > :is(th, td).ds-col-cantidad { text-align: right; }
body.ui-v2 .ds-tabla-lineas > tbody > tr > td.ds-col-ajustada { white-space: nowrap; }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-tabla.ds-tabla-lineas { table-layout: auto; }
    body.ui-v2 .ds-tabla-lineas > tbody > tr > td.ds-celda-texto-linea { min-width: 14em; }
}
/* Plegables (details/summary) dentro de una tarjeta plana:
   <div class="ds-plegables"><details class="ds-plegable"><summary class="ds-plegable-cabeza">
   <i class="ti ti-chevron-right ds-plegable-flecha"></i> <span class="ds-pildora">12</span>
   <span class="ds-plegable-titulo">…</span></summary>…</details></div> */
body.ui-v2 .ds-plegables { display: flex; flex-direction: column; }
body.ui-v2 .ds-plegable { border-bottom: 1px solid var(--ds-borde); }
body.ui-v2 .ds-plegable:last-child { border-bottom: 0; }
body.ui-v2 .ds-plegable-cabeza {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-e2) var(--ds-e3);
    min-height: 48px;
    padding: 10px 20px;
    color: var(--ds-texto);
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.42858;
    list-style: none;
    cursor: pointer;
    transition: background-color var(--ds-transicion);
}
body.ui-v2 .ds-plegable-cabeza::-webkit-details-marker { display: none; }
body.ui-v2 .ds-plegable-cabeza::marker { content: ""; }
body.ui-v2 .ds-plegable-cabeza:hover { background: var(--ds-hover); }
body.ui-v2 .ds-plegable-cabeza:focus-visible { outline: 0; box-shadow: inset 0 0 0 2px var(--ds-acento-oscuro); }
body.ui-v2 .ds-plegable-flecha { flex: none; color: var(--ds-texto-2); font-size: 16px; transition: transform var(--ds-transicion); }
body.ui-v2 .ds-plegable[open] > .ds-plegable-cabeza .ds-plegable-flecha { transform: rotate(90deg); }
body.ui-v2 .ds-plegable-titulo { font-weight: 500; }
body.ui-v2 .ds-plegable-nota { color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-plegable-vacio { margin: 0; padding: 0 20px 14px 48px; color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-plegable[open] > .ds-plegable-cabeza { border-bottom: 1px solid var(--ds-borde); }
body.ui-v2 .ds-plegable[open]:has(> .ds-plegable-vacio) > .ds-plegable-cabeza { border-bottom: 0; }
body.ui-v2 .ds-aviso + .ds-plegable,
body.ui-v2 .ds-plegables > .ds-aviso { margin: 12px 20px; }
/* Acordeón con conteo: código + nombre a la izquierda, conteo a la derecha.
   <button class="accordion-button"><span class="ds-acordeon-titulo"><span class="ds-etiqueta">01</span>
   <span class="ds-acordeon-nombre">…</span></span><span class="ds-pildora ds-acordeon-conteo">5 subprogramas</span></button> */
body.ui-v2 .ds-acordeon .accordion-button { gap: var(--ds-e3); font-size: var(--ds-tam-cuerpo); line-height: 1.42858; }
body.ui-v2 .ds-acordeon-titulo { display: flex; flex: 1 1 auto; align-items: center; gap: 10px; min-width: 0; }
body.ui-v2 .ds-acordeon-nombre { min-width: 0; font-weight: 600; }
body.ui-v2 .ds-acordeon-conteo { flex: none; margin-right: var(--ds-e2); }
body.ui-v2 .ds-acordeon .accordion-button::after { margin-left: 0; }
body.ui-v2 .ds-acordeon .accordion-body { padding: var(--ds-e1) 20px 20px; color: var(--ds-texto); }
/* Bloque con título dentro de una tarjeta o acordeón (un subprograma, un
   grupo): título 14/600 con su código, y su tabla debajo. */
body.ui-v2 .ds-bloque-grupo + .ds-bloque-grupo { margin-top: var(--ds-e5); }
body.ui-v2 .ds-bloque-grupo-titulo {
    display: flex;
    align-items: center;
    gap: var(--ds-e2);
    margin: 0 0 10px;
    color: var(--ds-texto);
    font-size: var(--ds-tam-cuerpo);
    font-weight: 600;
    line-height: 1.42858;
}


/* 25h. Formularios ------------------------------------------------------------ */
/* Pasos como enlaces (formulario de una sola página): cada paso lleva a su
   tarjeta y muestra si está listo (✓), si es el que sigue (contorno) o si
   falta (gris).
   <nav class="ds-pasos-nav"><ol class="ds-pasos"><li class="ds-paso …">
     <a class="ds-paso-enlace" href="#seccion"><span class="ds-paso-marca">1</span>
     <span class="ds-paso-texto">Buscar</span></a></li>…</ol></nav> */
body.ui-v2 .ds-pasos-nav { margin: 0 0 var(--ds-e5); }
body.ui-v2 .ds-paso-enlace {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    margin: -4px;
    padding: 4px 10px 4px 4px;
    border-radius: var(--ds-radio-pildora);
    color: inherit;
    text-decoration: none;
    transition: background-color var(--ds-transicion), color var(--ds-transicion);
}
body.ui-v2 .ds-paso-enlace:hover { background: var(--ds-hover-fondo); color: var(--ds-texto); }
body.ui-v2 .ds-paso-enlace:focus-visible { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 0; }
/* Formulario POR PASOS (uno visible a la vez; acta de adjudicación, 2026-09-30): el paso ABIERTO lleva el tinte de
   lo activo; su marca sigue diciendo el estado (✓ listo, contorno = el primero que falta, gris = pendiente). */
body.ui-v2 .ds-paso-abierto > .ds-paso-enlace { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); font-weight: 600; }
/* ancla: la tarjeta a la que lleva un paso o un aviso queda bajo la barra superior */
body.ui-v2 .ds-ancla { scroll-margin-top: calc(var(--ds-alto-barra) + 28px); }
/* Campos de búsqueda en una fila: tres cajones y un botón al final, alineados por abajo. */
body.ui-v2 .ds-buscador-campos {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.6fr) auto;
    gap: var(--ds-e4);
    align-items: end;
}
body.ui-v2 .ds-buscador-campos > .ds-campo { margin: 0; min-width: 0; }
@media (max-width: 991.98px) {
    body.ui-v2 .ds-buscador-campos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    body.ui-v2 .ds-buscador-campos > :nth-child(3) { grid-column: 1 / -1; }
}
@media (max-width: 575.98px) {
    body.ui-v2 .ds-buscador-campos { grid-template-columns: minmax(0, 1fr); }
    body.ui-v2 .ds-buscador-campos > .ds-btn { justify-self: start; }
}
/* Panel flotante anclado (resultados de una búsqueda): se superpone al
   contenido de abajo sin empujarlo; queda por debajo del pie fijo (1010).
   <div class="ds-flotante-ancla"><div class="ds-flotante">
     <div class="ds-flotante-cabeza">…<button class="ds-btn-icono ds-btn-sm">✕</button></div>
     …tabla o estado vacío…</div></div> */
body.ui-v2 .ds-flotante-ancla { position: relative; }
body.ui-v2 .ds-flotante {
    position: absolute;
    top: var(--ds-e2);
    left: 0;
    right: 0;
    z-index: 200;
    max-height: min(62vh, 34em);
    overflow: auto;
    overscroll-behavior: contain;
    background: var(--ds-superficie);
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-tarjeta);
    box-shadow: var(--ds-sombra-menu);
    scrollbar-width: thin;
}
body.ui-v2 .ds-flotante-cabeza {
    position: sticky;
    top: 0;
    z-index: 3;
    display: flex;
    align-items: center;
    gap: var(--ds-e2);
    min-height: 44px;
    padding: 6px 8px 6px var(--ds-e4);
    background: var(--ds-superficie);
    border-bottom: 1px solid var(--ds-borde);
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
body.ui-v2 .ds-flotante-titulo { flex: 1 1 auto; min-width: 0; }
body.ui-v2 .ds-flotante-titulo > strong { color: var(--ds-texto); font-weight: 600; }
body.ui-v2 .ds-flotante-cargando {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--ds-e2);
    padding: var(--ds-e5) var(--ds-e4);
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
}
body.ui-v2 .ds-flotante-error { margin: 0; padding: var(--ds-e4); color: var(--ds-error); font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-flotante > .table-responsive { border-radius: 0 0 calc(var(--ds-radio-tarjeta) - 1px) calc(var(--ds-radio-tarjeta) - 1px); }
body.ui-v2 .ds-flotante .ds-tabla > tbody > tr > td { vertical-align: top; padding-top: 8px; padding-bottom: 8px; }
body.ui-v2 .ds-flotante .ds-tabla > tbody > tr > td.ds-celda-acciones { padding-top: 5px; padding-bottom: 5px; }
body.ui-v2 .ds-vacio.ds-vacio-compacto { gap: var(--ds-e2); padding: var(--ds-e5) var(--ds-e4); }
body.ui-v2 .ds-vacio.ds-vacio-compacto .ds-vacio-icono { font-size: 28px; }
/* Tarjetas seleccionables (botón con aria-pressed): borde fino, radio 12;
   elegida = borde acento, fondo acento claro y ✓ arriba a la derecha;
   deshabilitada = gris.
   <div class="ds-seleccionables">
     <button type="button" class="ds-seleccionable ds-seleccionada" aria-pressed="true">
       <span class="ds-seleccionable-titulo">001-004-0001</span>
       <span class="ds-seleccionable-linea">Saldo: Q 6,027,381.08</span>
       <span class="ds-seleccionable-recibe">Recibe 5</span>
       <i class="ti ti-circle-check ds-seleccionable-marca"></i></button></div>
   Persona: .ds-seleccionable-persona con <span class="ds-avatar" data-iniciales="BC">
   (el avatar de la tarjeta es gris; el de la barra superior, §3c, no cambia). */
body.ui-v2 .ds-seleccionables {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 13.5em), 1fr));
    gap: var(--ds-e2);
}
body.ui-v2 .ds-seleccionables-personas { grid-template-columns: repeat(auto-fill, minmax(min(100%, 22em), 1fr)); }
body.ui-v2 .ds-seleccionables > .ds-aviso { grid-column: 1 / -1; margin: 0; }
body.ui-v2 .ds-seleccionable {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    width: 100%;
    min-width: 0;
    margin: 0;
    padding: 10px 34px 10px 12px;
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: var(--ds-radio-campo);
    background: var(--ds-superficie);
    color: var(--ds-texto);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    text-align: left;
    cursor: pointer;
    transition: border-color var(--ds-transicion), background-color var(--ds-transicion), box-shadow var(--ds-transicion);
}
body.ui-v2 .ds-seleccionable > span:not(.ds-avatar):not(.ds-seleccionable-cuerpo),
body.ui-v2 .ds-seleccionable-cuerpo > span { display: block; max-width: 100%; overflow-wrap: anywhere; }
body.ui-v2 .ds-seleccionable:hover { border-color: var(--ds-borde-hover); background: var(--ds-hover); }
body.ui-v2 .ds-seleccionable:focus-visible { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 2px; }
body.ui-v2 .ds-seleccionable-titulo { font-size: var(--ds-tam-cuerpo); font-weight: 600; line-height: 1.42858; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-seleccionable-linea { color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); line-height: 1.5; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-seleccionable-linea.ds-texto-error { color: var(--ds-error); font-weight: 500; }
body.ui-v2 .ds-seleccionable-recibe { margin-top: 2px; color: var(--ds-acento-oscuro); font-size: var(--ds-tam-etiqueta); font-weight: 600; line-height: 1.5; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-seleccionable-marca {
    position: absolute;
    top: 9px;
    right: 9px;
    color: var(--ds-acento-oscuro);
    font-size: 18px;
    line-height: 1;
    opacity: 0;
    transition: opacity var(--ds-transicion);
}
body.ui-v2 .ds-seleccionable.ds-seleccionada,
body.ui-v2 .ds-seleccionable[aria-pressed="true"] {
    border-color: var(--ds-acento);
    background: var(--ds-acento-claro);
    box-shadow: inset 0 0 0 1px var(--ds-acento);
}
body.ui-v2 .ds-seleccionable.ds-seleccionada > .ds-seleccionable-marca,
body.ui-v2 .ds-seleccionable[aria-pressed="true"] > .ds-seleccionable-marca { opacity: 1; }
/* línea gris sobre el tinte de la elegida: --ds-neutro (6.9:1; texto-2 daba 4.3:1) */
body.ui-v2 .ds-seleccionable.ds-seleccionada .ds-seleccionable-linea,
body.ui-v2 .ds-seleccionable[aria-pressed="true"] .ds-seleccionable-linea { color: var(--ds-neutro); }
body.ui-v2 .ds-seleccionable:disabled,
body.ui-v2 .ds-seleccionable.ds-deshabilitada {
    border-color: var(--ds-borde);
    background: var(--ds-fondo);
    box-shadow: none;
    color: var(--ds-texto-3);
    cursor: not-allowed;
}
body.ui-v2 .ds-seleccionable:disabled .ds-seleccionable-linea,
body.ui-v2 .ds-seleccionable.ds-deshabilitada .ds-seleccionable-linea { color: var(--ds-texto-3); }
/* elegida pero deshabilitada (asignación conservada): gris con borde de
   acento punteado; se puede pulsar porque quitarla es lo único posible */
body.ui-v2 .ds-seleccionable.ds-deshabilitada.ds-seleccionada:not(:disabled) {
    border: 1px dashed var(--ds-acento);
    background: var(--ds-neutro-fondo);
    box-shadow: none;
    color: var(--ds-texto-2);
    cursor: pointer;
}
body.ui-v2 .ds-seleccionable.ds-deshabilitada.ds-seleccionada:not(:disabled):hover { background: var(--ds-hover); }
body.ui-v2 .ds-seleccionable.ds-deshabilitada.ds-seleccionada .ds-seleccionable-marca { color: var(--ds-texto-2); }
/* saldo negativo: sigue en rojo aunque la tarjeta esté deshabilitada */
body.ui-v2 .ds-seleccionable .ds-seleccionable-linea.ds-texto-error { color: var(--ds-error); }
/* persona: avatar con iniciales + nombre y cargo */
body.ui-v2 .ds-seleccionable.ds-seleccionable-persona {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    column-gap: var(--ds-e3);
    padding: 12px 36px 12px 12px;
}
body.ui-v2 .ds-seleccionable-cuerpo { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
body.ui-v2 .ds-seleccionable-cuerpo > span { overflow-wrap: anywhere; }
body.ui-v2 .ds-seleccionable .ds-avatar {
    display: inline-grid;
    place-items: center;
    width: 2.5em;
    height: 2.5em;
    border-radius: 50%;
    background: var(--ds-neutro-fondo);
    color: var(--ds-neutro);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0.02em;
}
body.ui-v2 .ds-seleccionable .ds-avatar[data-iniciales]::before { content: attr(data-iniciales); }
body.ui-v2 .ds-seleccionable[aria-pressed="true"] .ds-avatar { background: var(--ds-relleno-primario); color: var(--ds-texto-sobre-relleno); }
@media (max-width: 575.98px) {
    /* en dos columnas el código (001-004-0001) y el saldo se partían en dos
       líneas; en una sola columna cada tarjeta se lee entera */
    body.ui-v2 .ds-seleccionables:not(.ds-seleccionables-personas) { grid-template-columns: minmax(0, 1fr); gap: 6px; }
    body.ui-v2 .ds-seleccionable { padding: 8px 36px 8px 12px; }
    body.ui-v2 .ds-seleccionable-marca { top: 50%; right: 12px; transform: translateY(-50%); }
}
/* Reparto por subproducto: bloque bajo la tabla de un grupo (título + (i) +
   interruptor, la rejilla de tarjetas, las cantidades a mano y un resumen). */
body.ui-v2 .ds-reparto-cabeza {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-e2) var(--ds-e4);
    margin-bottom: var(--ds-e3);
}
body.ui-v2 .ds-reparto-titulo {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    min-width: 0;
    margin: 0;
    color: var(--ds-texto);
    font-size: var(--ds-tam-tabla);
    font-weight: 600;
    line-height: 1.38462;
}
body.ui-v2 .ds-reparto-cabeza .form-check { margin: 0; font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-reparto-manual:not(:empty) { display: flex; flex-direction: column; gap: var(--ds-e2); margin-top: var(--ds-e3); }
body.ui-v2 .ds-reparto-fila { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ds-e2) var(--ds-e3); }
body.ui-v2 .ds-reparto-etiqueta { min-width: 10em; color: var(--ds-texto); font-size: var(--ds-tam-tabla); font-weight: 500; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-reparto-resumen { margin: var(--ds-e3) 0 0; font-size: var(--ds-tam-tabla); line-height: 1.38462; }
body.ui-v2 .ds-reparto-resumen:empty { display: none; }
body.ui-v2 .ds-reparto-resumen.ds-texto-error { font-weight: 600; }
/* Campo de solo lectura (valor que no se edita, con el alto de un campo) */
body.ui-v2 .ds-campo-lectura {
    display: flex;
    align-items: center;
    min-height: var(--ds-alto-control);
    padding: 9px 14px;
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-campo);
    background: var(--ds-fondo);
    color: var(--ds-texto);
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.42858;
    overflow-wrap: anywhere;
}
body.ui-v2 .ds-campo-lectura.ds-texto-2 { color: var(--ds-texto-2); }
body.ui-v2 .ds-campo-lectura.ds-texto-error { color: var(--ds-error); }
/* Campo de cantidad: número a la derecha y sin las flechas del campo numérico
   (en Safari, sobre todo con zoom bajo, las flechas tapaban la última cifra:
   "1(" en vez de "10"); se sigue escribiendo y subiendo/bajando con ↑/↓.
   Ancho en ch más el relleno y el borde del campo, así cabe la cifra entera
   ("3456789.00"): en un formulario, 12 cifras; en la tabla de un panel
   lateral (carrito), 11 con alto y relleno de fila compacta (9 en el
   teléfono). En em se cortaba la última cifra ("3456789.0"). */
body.ui-v2 .ds-campo-cantidad { text-align: right; font-variant-numeric: tabular-nums; appearance: textfield; -webkit-appearance: textfield; -moz-appearance: textfield; }
body.ui-v2 .ds-campo-cantidad::-webkit-inner-spin-button,
body.ui-v2 .ds-campo-cantidad::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
body.ui-v2 .form-control.ds-campo-cantidad { width: calc(12ch + 30px); max-width: 100%; text-align: right; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-panel-tabla .form-control.ds-campo-cantidad { width: calc(11ch + 22px); min-height: 32px; padding: 4px 10px; }
@media (max-width: 575.98px) {
    body.ui-v2 .ds-panel-tabla .form-control.ds-campo-cantidad { width: calc(9ch + 18px); padding-right: 6px; }
}
body.ui-v2 .form-select.ds-campo-renglon { width: 100%; min-width: 16em; }
body.ui-v2 .form-select.ds-campo-presentacion { max-width: 32em; }
body.ui-v2 .ds-linea-presentacion { margin-top: 6px; font-size: var(--ds-tam-etiqueta); line-height: 1.5; }
body.ui-v2 .ds-linea-presentacion:empty { display: none; }
/* proveedor: NIT | nombre (doble) | fecha; en una columna angosta, uno bajo otro */
body.ui-v2 .ds-form-grilla-proveedor { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) minmax(0, 1fr); }
@container lateral (max-width: 44.99em) {
    body.ui-v2 .ds-form-grilla-proveedor { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 767.98px) {
    body.ui-v2 .ds-form-grilla-proveedor { grid-template-columns: minmax(0, 1fr); }
}
/* Grilla de formulario con un campo angosto y uno ancho (código + nombre) */
body.ui-v2 .ds-form-grilla.ds-form-grilla-1-3 { grid-template-columns: minmax(0, 1fr) minmax(0, 3fr); }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-form-grilla.ds-form-grilla-1-3 { grid-template-columns: minmax(0, 1fr); }
}
/* Formulario largo que aprovecha el ancho:
   <form class="ds-form-adaptable"><div class="ds-form-dos-columnas">
     <div class="ds-columna-principal">…tarjetas anchas (búsqueda, tablas)…</div>
     <div class="ds-columna-lateral">…tarjetas cortas (firmas, texto)…</div></div>
     …pie fijo…</form>
   Una sola columna de 86em (~1200 px, lo de un formulario de detalle); con
   contenido de 100em o más (~1400 px; consulta sobre main.ds-contenido:
   pantalla ancha, riel delgado o Safari con zoom bajo) la lateral pasa a la
   derecha (24–28em) y la principal toma el resto. El umbral va en em a
   propósito: con zoom de página WebKit compara el contenedor en px "con zoom"
   y un umbral en px no se cumplía nunca. El orden del documento (y del Tab) no
   cambia. .ds-par-tarjetas: dos tarjetas lado a lado si su contenedor es
   ancho, una bajo otra si no. En la columna angosta, título y píldora de estado
   de una tarjeta en la misma línea. */
body.ui-v2 .ds-form-adaptable { max-width: var(--ds-ancho-detalle); }
body.ui-v2 .ds-form-dos-columnas { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--ds-e5); align-items: start; }
body.ui-v2 .ds-columna-principal,
body.ui-v2 .ds-columna-lateral { display: flex; flex-direction: column; gap: var(--ds-e5); min-width: 0; }
body.ui-v2 .ds-columna-lateral { container: lateral / inline-size; }
body.ui-v2 :is(.ds-columna-principal, .ds-columna-lateral, .ds-par-tarjetas) > .ds-tarjeta { margin-bottom: 0; }
body.ui-v2 .ds-par-tarjetas { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--ds-e5); align-items: start; }
body.ui-v2 .ds-columna-lateral .ds-tarjeta-titulos { flex-basis: 9em; }
@container lateral (min-width: 50em) {
    body.ui-v2 .ds-par-tarjetas { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container contenido (min-width: 100em) {
    body.ui-v2 .ds-form-adaptable { max-width: none; }
    body.ui-v2 .ds-form-dos-columnas { grid-template-columns: minmax(0, 1fr) minmax(24em, 28em); }
}
/* Lista de errores (diálogo de "Revise antes de guardar") */
body.ui-v2 .ds-lista-errores {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 0;
    padding-left: 1.15em;
    color: var(--ds-texto);
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.42858;
}
body.ui-v2 .ds-lista-errores > li::marker { color: var(--ds-aviso); }
/* Interruptor con su rótulo en una línea (13 px) */
body.ui-v2 .form-switch.ds-interruptor {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-e2);
    min-height: 0;
    margin: 0;
    padding-left: 0;
}
body.ui-v2 .form-switch.ds-interruptor > .form-check-input { float: none; margin: 0; }
body.ui-v2 .form-switch.ds-interruptor > .form-check-label { color: var(--ds-texto); font-size: var(--ds-tam-tabla); line-height: 1.38462; cursor: pointer; }
/* Formulario corto en una fila (campos + botón al final, alineados abajo:
   agregar un servicio) o de un solo botón entre las acciones de un encabezado
   (Enviar a Compras). .ds-campo-crece se queda con el ancho que sobra. */
body.ui-v2 .ds-form-en-linea {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--ds-e3) var(--ds-e4);
    margin: 0;
}
body.ui-v2 .ds-form-en-linea > .ds-campo { flex: 0 1 12em; min-width: 8em; margin: 0; }
body.ui-v2 .ds-form-en-linea > .ds-campo.ds-campo-crece { flex: 1 1 20em; }
body.ui-v2 .ds-form-en-linea > .ds-btn { flex: none; }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-form-en-linea > .ds-campo { flex: 1 1 100%; }
}
/* Pieza a la izquierda de las acciones de un formulario corto (casilla o
   interruptor "De la unidad" junto a "Subir"): empuja los botones a la derecha. */
body.ui-v2 .ds-form-acciones > .ds-form-acciones-inicio { margin-right: auto; }
body.ui-v2 .ds-form-acciones > .form-check.ds-form-acciones-inicio { margin-bottom: 0; }
/* Mensaje en línea junto a un botón (resultado de un envío por fetch): 13 px;
   gris mientras trabaja, rojo si falló, verde si salió bien. */
body.ui-v2 .ds-mensaje-linea {
    min-width: 0;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    overflow-wrap: anywhere;
}
body.ui-v2 .ds-mensaje-linea.ds-mensaje-linea-error { color: var(--ds-error); font-weight: 500; }
body.ui-v2 .ds-mensaje-linea.ds-mensaje-linea-exito { color: var(--ds-exito); font-weight: 500; }
body.ui-v2 .ds-form-acciones > .ds-mensaje-linea { flex: 1 1 16em; text-align: right; }
body.ui-v2 .ds-mensaje-linea.ds-mensaje-linea-aviso { color: var(--ds-aviso); font-weight: 500; }
body.ui-v2 .ds-mensaje-linea.ds-mensaje-linea-info { color: var(--ds-texto-2); }
/* Lista de opciones (ajustes): una fila por opción con su casilla o
   interruptor a la izquierda y, si tiene, un control a la derecha (alcance de
   un módulo); líneas finas entre filas. .ds-opcion-sub = hija de un grupo
   (.ds-opcion-titulo), con sangría.
   <div class="ds-lista-opciones"><div class="ds-opcion"><div class="form-check">…</div>
   <select class="form-select form-select-sm ds-opcion-control">…</select></div>…</div> */
body.ui-v2 .ds-lista-opciones { display: flex; flex-direction: column; }
body.ui-v2 .ds-opcion {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-e2) var(--ds-e4);
    min-height: 2.75em;
    padding: 8px 0;
    border-bottom: 1px solid var(--ds-borde);
}
body.ui-v2 .ds-opcion:last-child { border-bottom: 0; }
body.ui-v2 .ds-opcion:first-child { padding-top: 0; }
body.ui-v2 .ds-opcion > .form-check { flex: 1 1 18em; min-width: 0; margin: 0; }
body.ui-v2 .ds-opcion > .form-check > .ds-ayuda-texto { margin: 2px 0 0; }
body.ui-v2 .ds-opcion.ds-opcion-sub { padding-left: 1.75em; }
body.ui-v2 .ds-opcion.ds-opcion-titulo {
    min-height: 0;
    padding-top: var(--ds-e3);
    padding-bottom: 4px;
    border-bottom: 0;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 600;
    line-height: 1.33334;
}
body.ui-v2 .ds-opcion > .ds-opcion-control { flex: 0 0 auto; width: auto; max-width: 100%; }
/* Casillas en columnas (servicios donde firma): se acomodan solas. */
body.ui-v2 .ds-casillas-grilla {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16em, 1fr));
    gap: 6px var(--ds-e4);
    margin-top: var(--ds-e3);
}
body.ui-v2 .ds-casillas-grilla > .form-check { margin: 0; }
/* bloque que depende de un interruptor: alineado con el texto del interruptor */
body.ui-v2 .ds-debajo-interruptor { margin-left: 2.9em; }
/* Lista larga con desplazamiento propio dentro de una tarjeta (renglones de un
   usuario): tope en em, marco fino. */
body.ui-v2 .ds-lista-desplazable {
    max-height: 30em;
    margin-top: var(--ds-e3);
    overflow-y: auto;
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-campo);
}
/* Grupo de casillas que se abre (grupo de gasto con sus renglones): cabeza con
   la casilla de "todos" + botón que abre (título, conteo y flecha); el cuerpo
   es un .collapse de Bootstrap con las casillas en columnas.
   <div class="ds-grupo-casillas"><div class="ds-grupo-casillas-cabeza">
     <input class="form-check-input" type="checkbox">
     <button class="ds-grupo-casillas-boton" data-bs-toggle="collapse" data-bs-target="#g1">
       <span class="ds-grupo-casillas-titulo">…</span><span class="ds-pildora …">12</span>
       <i class="ti ti-chevron-down ds-grupo-casillas-flecha"></i></button></div>
   <div class="collapse" id="g1"><div class="ds-grupo-casillas-cuerpo">…form-check…</div></div></div>
   La flecha gira cuando el cuerpo está abierto (también si lo abrió un script). */
body.ui-v2 .ds-grupo-casillas { border-bottom: 1px solid var(--ds-borde); }
body.ui-v2 .ds-grupo-casillas:last-child { border-bottom: 0; }
body.ui-v2 .ds-grupo-casillas-cabeza {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: var(--ds-e3);
    padding: 0 12px 0 14px;
    background: var(--ds-superficie);
}
body.ui-v2 .ds-grupo-casillas-cabeza > .form-check-input { flex: none; margin: 0; }
body.ui-v2 .ds-grupo-casillas-boton {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: var(--ds-e2);
    min-width: 0;
    min-height: 2.75em;
    padding: 6px 0;
    border: 0;
    background: none;
    color: var(--ds-texto);
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.42858;
    text-align: left;
    cursor: pointer;
}
body.ui-v2 .ds-grupo-casillas-boton:focus-visible { outline: 0; box-shadow: var(--tb-anillo); border-radius: 8px; }
body.ui-v2 .ds-grupo-casillas-titulo { flex: 1 1 auto; min-width: 0; }
body.ui-v2 .ds-grupo-casillas-flecha { flex: none; color: var(--ds-texto-2); font-size: 16px; transition: transform var(--ds-transicion); }
body.ui-v2 .ds-grupo-casillas:has(> .collapse.show) .ds-grupo-casillas-flecha,
body.ui-v2 .ds-grupo-casillas:has(> .collapsing) .ds-grupo-casillas-flecha { transform: rotate(180deg); }
body.ui-v2 .ds-grupo-casillas-cuerpo {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(22em, 1fr));
    gap: 4px var(--ds-e4);
    padding: 2px 14px 12px 3.1em;
}
body.ui-v2 .ds-grupo-casillas-cuerpo > .form-check { margin: 0; font-size: var(--ds-tam-tabla); line-height: 1.38462; }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-grupo-casillas-cuerpo { grid-template-columns: minmax(0, 1fr); padding-left: 14px; }
    body.ui-v2 .ds-debajo-interruptor { margin-left: 0; }
}
@media (prefers-reduced-motion: reduce) {
    body.ui-v2 .ds-grupo-casillas-flecha { transition: none; }
}
/* casillas de estas listas: 8 px entre la casilla (18 px) y su texto (con el
   relleno de Bootstrap quedaban a 3 px en letra de 13 px: "☑111") */
body.ui-v2 :is(.ds-grupo-casillas-cuerpo, .ds-casillas-grilla, .ds-opcion) > .form-check:not(.form-switch) { padding-left: calc(18px + 0.6em); }
body.ui-v2 :is(.ds-grupo-casillas-cuerpo, .ds-casillas-grilla, .ds-opcion) > .form-check:not(.form-switch) > .form-check-input { margin-left: calc(-18px - 0.6em); }
/* Campo con sugerencias (buscador + lista que se abre debajo, armada por JS
   con .list-group-item): <div class="ds-autocompletar"><label class="ds-buscador-get">…</label>
   <div class="list-group ds-autocompletar-lista d-none">…</div></div>. La lista flota sobre
   lo que sigue, con el ancho del campo (mínimo 24em) y desplazamiento propio. */
body.ui-v2 .ds-autocompletar { position: relative; display: flex; flex: 0 1 auto; min-width: 0; max-width: 100%; }
body.ui-v2 .ds-autocompletar > .ds-buscador-get { flex: 1 1 auto; }
body.ui-v2 .ds-autocompletar-lista {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 1030;
    width: max(100%, 24em);
    max-width: min(40em, calc(100vw - 32px));
    max-height: 22em;
    overflow-y: auto;
    border-radius: var(--ds-radio-campo);
    box-shadow: var(--ds-sombra-menu, var(--ds-sombra-flotante)) !important;
}
body.ui-v2 .ds-autocompletar-lista > .list-group-item {
    padding: 8px 14px;
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
@media (max-width: 767.98px) {
    body.ui-v2 .ds-autocompletar { flex: 1 1 100%; }
}


/* 25i. Tarjetas de carga de archivos ------------------------------------------ */
/* Una tarjeta por reporte: título, contador y una línea a la izquierda; a la
   derecha su formulario de carga (zona compacta + "Actualizar"):
   <section class="ds-tarjeta ds-tarjeta-carga">…<form class="ds-carga-form">[select]
   <label class="ds-carga ds-carga-compacta">…</label><button>Actualizar</button></form> */
body.ui-v2 .ds-carga-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--ds-e2);
    min-width: 0;
    margin: 0;
}
body.ui-v2 .ds-carga-form > .ds-carga.ds-carga-compacta {
    flex: 1 1 18em;
    width: auto;
    min-width: 16em;
    max-width: 26em;
    min-height: 44px;
    padding: 6px 14px;
}
body.ui-v2 .ds-carga-form > .ds-carga-compacta .ds-carga-icono { font-size: 20px; }
body.ui-v2 .ds-carga-form > .ds-carga-compacta .ds-carga-texto { white-space: nowrap; }
body.ui-v2 .ds-carga-form > .ds-carga-compacta .ds-carga-nombre { max-width: 14em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Saldos Ene–X (2026-10-13): el estado de los saldos sobre la tabla de meses del panel («Saldos al …» / «Sin saldos
   cargados»), el formulario compacto «Actualizar cierre» de cada mes terminado y la nota de la fecha de los saldos
   en la rejilla de subproductos del SIAF. */
body.ui-v2 .ds-saldos-estado { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ds-e2); padding: var(--ds-e3) var(--ds-e4) var(--ds-e2); }
body.ui-v2 .ds-carga-form-cierre { justify-content: flex-end; }
body.ui-v2 .ds-carga-form-cierre > .ds-carga.ds-carga-compacta { min-height: 32px; }
body.ui-v2 .ds-carga-form-cierre > .ds-carga-compacta .ds-carga-nombre { max-width: 9em; }
body.ui-v2 .ds-reparto-saldos { margin: 0 0 var(--ds-e2); }
body.ui-v2 .ds-carga-select { flex: 0 1 18em; width: auto; min-width: 12em; max-width: 22em; }
/* en la cabeza de una tarjeta de carga, el formulario ocupa lo que dejan los títulos */
body.ui-v2 .ds-tarjeta-carga > .ds-tarjeta-cabeza > .ds-tarjeta-titulos { flex: 1 1 22em; }
body.ui-v2 .ds-tarjeta-carga > .ds-tarjeta-cabeza > .ds-tarjeta-acciones { flex: 0 1 auto; max-width: 100%; }
/* nota al pie de una tarjeta (una línea gris con ícono) */
body.ui-v2 .ds-pie-nota {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-right: auto;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
body.ui-v2 .ds-pie-nota > .ti { font-size: 16px; }
/* Grilla principal + lateral (p. ej. saldos a la izquierda y las demás cargas a
   la derecha): una columna hasta ~1500 px de contenido; desde ahí, dos. */
body.ui-v2 .ds-grilla-lateral { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--ds-e5); align-items: start; }
body.ui-v2 .ds-grilla-lateral > * { margin-bottom: 0; min-width: 0; }
@container contenido (min-width: 1500px) {
    body.ui-v2 .ds-grilla-lateral { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); }
}
body.ui-v2 .ds-datos.ds-datos-carga { gap: var(--ds-e3) var(--ds-e5); }
/* Varios a la vez: una zona por reporte en columnas; abajo el centro de costo y el botón */
body.ui-v2 .ds-carga-varios-zonas {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 16em), 1fr));
    gap: var(--ds-e3) var(--ds-e4);
}
body.ui-v2 .ds-carga-varios-zonas > .ds-campo { margin: 0; min-width: 0; }
body.ui-v2 .ds-carga-varios-zonas .ds-carga.ds-carga-compacta { min-height: 48px; }
body.ui-v2 .ds-carga-varios-pie {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: flex-end;
    gap: var(--ds-e3);
    margin-top: var(--ds-e4);
}
body.ui-v2 .ds-carga-varios-cc { flex: 0 1 26em; min-width: 14em; margin: 0 auto 0 0; }


/* 25j. Pie fijo del formulario: resumen, avisos y botones ---------------------- */
/* (el pie en sí es §24d: barra flotante opaca al pie de la ventana) */
body.ui-v2 .ds-pie-resumen {
    color: var(--ds-texto);
    font-size: var(--ds-tam-cuerpo);
    font-weight: 600;
    line-height: 1.42858;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .ds-pie-sep { margin: 0 6px; color: var(--ds-texto-3); font-weight: 400; }
body.ui-v2 .ds-pie-rotulo { color: var(--ds-texto-2); font-weight: 400; }
body.ui-v2 .ds-pie-avisos { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; margin-right: auto; margin-left: var(--ds-e2); }
body.ui-v2 .ds-pie-botones { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--ds-e2); }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-pie-avisos { margin-left: 0; flex-basis: 100%; }
    /* sin avisos (el JS lo vacía): sin la fila fantasma de 8 px. NO ≥ 768: ahí
       su margin-right: auto empuja los botones a la derecha. */
    body.ui-v2 .ds-pie-avisos:empty { display: none; }
    body.ui-v2 .ds-pie-botones { flex: 1 1 100%; }
    body.ui-v2 .ds-pie-botones > .ds-btn-terciario { margin-right: auto; }
}
@media (max-width: 575.98px) {
    body.ui-v2 .ds-pie-botones .ds-btn { --ds-btn-alto: 36px; padding: 0 14px; font-size: var(--ds-tam-tabla); }
    /* avisos del pie en UNA fila que se desplaza de lado (en dos filas el pie
       llegaba a 194 px de 844); el relleno 3 px / margen −3 px deja entero el
       anillo de foco de las píldoras */
    body.ui-v2 .ds-pie-avisos { gap: 4px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding: 3px; margin: -3px; }
    body.ui-v2 .ds-pie-avisos::-webkit-scrollbar { display: none; }
    body.ui-v2 .ds-pie-avisos > * { flex: none; }
}
/* Avisos flotantes sobre el pie fijo de un formulario: sin esto, un aviso de
   error (queda hasta cerrarlo) tapaba "Guardar" y "Confirmar". */
body.ui-v2:has(.ds-pie-formulario) .ds-estados { bottom: calc(var(--ds-alto-control) + 52px); }
@media (max-width: 767.98px) {
    body.ui-v2:has(.ds-pie-formulario) .ds-estados { bottom: 172px; }
}


/* 25k. Paneles laterales y diálogos -------------------------------------------- */
/* Panel lateral para contenido ancho (tablas de reportes): hasta 1100 px. */
body.ui-v2 .offcanvas.offcanvas-end.ds-panel-lateral-amplio { --bs-offcanvas-width: min(1100px, calc(100vw - 24px)); }
/* Línea de "Cargando…" (spinner + texto) mientras llega un contenido: en una
   tarjeta o un panel con relleno propio; suelta en el cuerpo de un panel
   lateral (que ya tiene su relleno), sin relleno lateral. */
body.ui-v2 .ds-cargando-linea {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0;
    padding: 14px 20px;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
}
body.ui-v2 .ds-cargando-linea > .spinner-border { flex: none; color: var(--ds-acento); }
body.ui-v2 .offcanvas-body > .ds-cargando-linea { gap: var(--ds-e2); padding: var(--ds-e4) 0; line-height: 1.38462; }
/* Panel lateral NO modal que acompaña a la página mientras se trabaja en ella
   (sin fondo oscuro: data-bs-backdrop="false" data-bs-scroll="true"): el JS de
   la página pone su `top` bajo el encabezado (así no tapa el botón que lo
   abre). Sombra más marcada (no hay fondo que lo separe); pie fijo con el
   conteo y los botones. */
body.ui-v2 .offcanvas.offcanvas-end.ds-panel-lateral-acompana {
    --bs-offcanvas-width: 560px;
    box-shadow: var(--ds-sombra-dialogo-fuerte), 0 0 0 1px var(--ds-borde);
}
body.ui-v2 .ds-panel-lateral-acompana .offcanvas-body { display: flex; flex-direction: column; gap: var(--ds-e3); min-height: 0; }
body.ui-v2 .ds-panel-lateral-acompana .nav-tabs { flex: none; }
body.ui-v2 .ds-panel-lateral-acompana .tab-content { flex: 1 1 auto; min-height: 0; }
body.ui-v2 .ds-panel-lateral-acompana .ds-panel-lateral-pie { flex-wrap: wrap; align-items: center; justify-content: space-between; }
body.ui-v2 .ds-panel-lateral-acompana .ds-vacio { padding: var(--ds-e5) var(--ds-e3); }
body.ui-v2 .ds-panel-pie-fijo {
    position: sticky;
    bottom: calc(-1 * var(--bs-offcanvas-padding-y, 20px));
    z-index: 3;
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: var(--ds-e3) -24px calc(-1 * var(--bs-offcanvas-padding-y, 20px));
    padding: var(--ds-e3) 24px var(--ds-e4);
    border-top: 1px solid var(--ds-borde);
    background: var(--ds-superficie);
}
body.ui-v2 .ds-panel-pie-fijo .ds-error-texto:empty { display: none; }
body.ui-v2 .ds-panel-pie-linea,
body.ui-v2 .ds-panel-conteo { margin: 0; color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); line-height: 1.38462; }
body.ui-v2 .ds-panel-conteo { margin-bottom: var(--ds-e3); }
body.ui-v2 .ds-filtros-get.ds-filtros-panel { margin-bottom: var(--ds-e2); }
body.ui-v2 .ds-filtros-panel .ds-buscador-rotulado.ds-buscador-ancho { width: 18em; min-width: 10em; }
/* Diálogo con vista previa de un contenido para Word (.ds-modal-medio.ds-modal-previa;
   "Encabezado de bases" de la sábana, 2026-09-30): 780 px para que quepa la hoja de
   16.5 cm sin desplazarse de lado. La hoja (.ds-previa-word-hoja) recibe HTML que arma
   el SERVIDOR con estilos en línea, porque es lo que Word lee al pegar (única excepción
   a "sin estilos en línea", ver app/bases_compra.py): aquí solo se le da el marco, el
   papel blanco y el desplazamiento. Bootstrap angosta el diálogo en ventanas chicas. */
body.ui-v2 .modal.ds-modal-medio.ds-modal-previa { --bs-modal-width: 780px; }
/* observaciones de dos renglones (el piso general de un textarea es 88 px): el diálogo cabe en una laptop */
body.ui-v2 .ds-modal-previa textarea.form-control { min-height: 60px; }
body.ui-v2 .ds-previa-word-rotulo { margin-top: 14px; }
body.ui-v2 .ds-previa-word {
    /* lo que queda de la ventana después del resto del diálogo (unos 470 px): cabe sin desplazar el diálogo desde 720 de alto */
    max-height: clamp(180px, calc(100vh - 474px), 420px);
    min-height: 96px;
    padding: 12px;
    overflow: auto;
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-campo);
    background: var(--ds-neutro-fondo);
}
body.ui-v2 .ds-previa-word:focus-visible { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 2px; }
body.ui-v2 .ds-previa-word-hoja {
    width: max-content;
    min-width: min(100%, 17.5cm);
    margin: 0 auto;
    padding: 0.5cm;
    background: var(--ds-hoja);
    color: var(--ds-hoja-tinta);
    box-shadow: var(--ds-sombra-hoja);
    -webkit-user-select: text;
    user-select: text;
}
body.ui-v2 .ds-previa-word-hoja:empty { display: none; }   /* sin tipo elegido todavía no hay encabezado: queda el marco */
body.ui-v2 .ds-previa-word-ocupada { opacity: 0.55; }
body.ui-v2 .ds-previa-word-mensaje { margin-top: 10px; }
body.ui-v2 .ds-previa-word-mensaje[hidden] { display: none; }
body.ui-v2 .ds-previa-word-mensaje.ds-previa-word-error { color: var(--ds-error); }
/* Código destacado en un diálogo (el ítem al que se refiere) y línea de error
   del diálogo que solo se ve con texto */
body.ui-v2 .ds-modal-codigo { margin: 0 0 2px; color: var(--ds-texto); font-weight: 600; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-modal-error:empty { display: none; }
/* Diálogo de envío masivo: tres grupos (se enviarán / no cuadran / se
   ignoran) con su conteo en píldora y la lista de SIAF; luego el avance
   (<progress>) y el resultado. */
body.ui-v2 .ds-envio-grupos { display: grid; gap: var(--ds-e4); }
body.ui-v2 .ds-envio-grupos .ds-modal-seccion { margin-bottom: 6px; }
body.ui-v2 .ds-envio-grupo-exito .ds-modal-seccion > .ti { color: var(--ds-exito); }
body.ui-v2 .ds-envio-grupo-error .ds-modal-seccion > .ti { color: var(--ds-error); }
body.ui-v2 .ds-envio-grupo-neutro .ds-modal-seccion > .ti { color: var(--ds-texto-3); }
body.ui-v2 .ds-envio-grupos .ds-modal-seccion > .ti { font-size: 18px; line-height: 1; }
body.ui-v2 .ds-envio-grupos .ds-modal-meta { margin-bottom: 6px; }
body.ui-v2 .ds-envio-lista {
    max-height: 9.5em;
    margin: 0;
    padding: 8px 12px;
    overflow: auto;
    border-radius: var(--ds-radio-campo);
    background: var(--ds-neutro-fondo);
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    list-style: none;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .ds-envio-lista > li + li { margin-top: 4px; }
body.ui-v2 .ds-envio-lista[hidden],
body.ui-v2 .ds-envio-lista:empty { display: none; }
/* Noche 5 · 2f: una sola línea gris para los SIAF que no se envían, con «Ver cuáles» que despliega la lista */
body.ui-v2 .ds-envio-excluidos { margin: 0; color: var(--ds-texto-3); font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-envio-excluidos[hidden] { display: none; }
body.ui-v2 .ds-envio-lista-excluidos { max-height: 6em; }
body.ui-v2 .ds-envio-progreso-texto {
    display: flex;
    align-items: center;
    gap: var(--ds-e2);
    margin: 0 0 var(--ds-e3);
    font-size: var(--ds-tam-cuerpo);
    line-height: 1.42858;
}
body.ui-v2 .ds-envio-progreso-texto > .spinner-border { flex: none; color: var(--ds-acento); }
body.ui-v2 #envio-progreso > .ds-barra-avance { display: block; width: 100%; }
body.ui-v2 .ds-envio-nota { margin: var(--ds-e3) 0 0; }
body.ui-v2 #envio-resultado > .ds-aviso { margin-bottom: var(--ds-e3); }
body.ui-v2 #envio-resultado > .ds-aviso:last-child { margin-bottom: 0; }


/* 25l. Avisos, notas, textos y paginación en la página ------------------------ */
/* Aviso compacto con acción: la acción se alinea al centro del texto */
body.ui-v2 .ds-aviso.ds-aviso-compacto:where(:has(> .ds-aviso-acciones)) { align-items: center; }
body.ui-v2 .ds-aviso.ds-aviso-compacto .ds-aviso-acciones .ds-btn-sm { min-height: 30px; }
/* Aviso con acción en el teléfono: el botón a la derecha dejaba el texto en una
   columna de 150 px (seis líneas); bajo 576 px la acción baja debajo del texto. */
@media (max-width: 575.98px) {
    body.ui-v2 .ds-aviso:has(> .ds-aviso-acciones) { flex-wrap: wrap; align-items: flex-start; }
    body.ui-v2 .ds-aviso:has(> .ds-aviso-acciones) > .ds-aviso-cuerpo { flex: 1 1 calc(100% - 2.5em); }
    body.ui-v2 .ds-aviso > .ds-aviso-acciones { flex: 1 1 100%; margin-left: 0; padding-left: 28px; }
}
/* Enlace al pie de un aviso en línea y líneas o lista dentro del cuerpo */
body.ui-v2 .ds-aviso-enlace { display: inline-block; margin-top: 4px; font-weight: 500; }
body.ui-v2 .ds-aviso-cuerpo > div + div { margin-top: 2px; }
body.ui-v2 .ds-aviso-cuerpo ul { margin: 4px 0 8px; padding-left: 1.25em; }
body.ui-v2 .ds-aviso-cuerpo li + li { margin-top: 2px; }
/* Nota: una línea gris de 13 px (bajo unas pestañas, en un diálogo). */
body.ui-v2 .ds-nota { margin: 0 0 var(--ds-e3); color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); line-height: 1.38462; }
/* Nota bajo el valor de un dato (ds.dato): 12 px gris, en su propia línea. */
body.ui-v2 .ds-dato-nota { display: block; margin-top: 2px; color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); line-height: 1.33334; }
/* Lista corta dentro de un dato o un aviso */
body.ui-v2 .ds-lista-compacta { margin: 4px 0 0; padding-left: 1.25em; font-size: var(--ds-tam-tabla); line-height: 1.38462; }
/* Pestañas de Bootstrap seguidas de su contenido: aire entre la línea y el
   contenido (en el panel lateral que acompaña, §25k, lo da el gap del panel). */
body.ui-v2 .nav-tabs + .tab-content:not(.ds-panel-lateral-acompana .tab-content) { padding-top: var(--ds-e3); }
/* Textos de estado (color solo): gris, apagado, éxito y error (el rojo gana
   siempre: una cifra con error no se apaga aunque su tarjeta esté deshabilitada) */
body.ui-v2 .ds-texto-2 { color: var(--ds-texto-2); }
body.ui-v2 .ds-texto-3 { color: var(--ds-texto-2); }   /* "Sin renglón": dato apagado pero legible (4.8:1); el nombre queda por compatibilidad */
body.ui-v2 .ds-texto-exito { color: var(--ds-exito); }
body.ui-v2 .ds-texto-error { color: var(--ds-error) !important; }
/* Paginación en la página, para listas que pagina el JS (sin recargar):
   Anterior · "1–50 de 1,234 · página 1 de 25" · Siguiente.
   <div class="ds-paginacion-cliente">…</div> (.ds-paginacion-panel: centrada, en un panel) */
body.ui-v2 .ds-paginacion-cliente {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-e2) var(--ds-e3);
    width: 100%;
}
body.ui-v2 .ds-paginacion-cliente > .ds-paginacion-info { color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); line-height: 1.38462; text-align: center; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-paginacion-cliente.ds-paginacion-panel { justify-content: center; margin-top: var(--ds-e3); }
/* Barra de una TablaDatos v2 en el teléfono: si su final (contador propio y
   "Quitar filtros") está todo oculto, no ocupa una línea vacía debajo de las
   píldoras. */
@media (max-width: 767.98px) {
    body.ui-v2 .tb-barra-fin:not(:has(> :not([hidden]))) { display: none; }
}
/* Barra de una TablaDatos sin nada visible (búsqueda en la barra superior con
   busquedaExterna, contador en otro lado, sin píldoras ni chips: bitácora de
   OCDS): no deja una fila vacía de 36 px sobre la tabla. Con un filtro activo
   vuelve, con "Quitar filtros". */
body.ui-v2 .tb-v2 > .tb-barra:not(:has(.tb-buscador-caja, .tb-barra-filtros > .ds-chips, .ds-pildoras > *, .tb-chips > *, .ds-mas-filtros, .ds-pildora-orden, .tb-densidad, .tb-barra-fin > :not([hidden]))) { display: none; }


/* 25m. Ficha y panel Detalle del SIAF ------------------------------------------- */
/* Ficha: "Volver a la lista" pegado al título; estado (píldora) junto al
   título, en la línea del contador; avisos del puente con Compras uno bajo
   otro antes del contenido; visor del PDF a la izquierda y datos a la derecha
   (.ds-form-con-lateral, §24d); una columna bajo 1100 px. */
body.ui-v2 .ds-ficha-volver { margin: 0 0 var(--ds-e1); }
body.ui-v2 .ds-ficha-volver > .ds-volver { margin-bottom: 0; }
body.ui-v2 .ds-encabezado-ficha .ds-subtitulo { align-items: center; overflow: visible; }
body.ui-v2 .ds-encabezado-ficha .ds-contador { display: inline-flex; align-items: center; }
body.ui-v2 .ds-ficha-avisos:empty { display: none; }
body.ui-v2 .ds-ficha-avisos { display: grid; gap: var(--ds-e2); margin-bottom: var(--ds-e4); }
body.ui-v2 .ds-ficha-avisos > .ds-aviso { margin: 0; }
/* bloque que se abre sobre el visor (Detalle) */
body.ui-v2 .ds-ficha-detalle { margin-bottom: var(--ds-e5); scroll-margin-top: calc(var(--ds-alto-barra) + var(--ds-e5)); }
body.ui-v2 .ds-ficha-detalle > .ds-aviso { margin: 0; }
body.ui-v2 .ds-ficha { grid-template-columns: minmax(0, 1fr) minmax(17rem, 22rem); }
body.ui-v2 .ds-ficha-visor { height: calc(100vh - var(--ds-alto-barra) - 96px); min-height: 520px; }
body.ui-v2 .ds-ficha-lateral > .ds-tarjeta { margin-bottom: 0; }
/* datos de una columna, con más aire entre rótulo y valor */
body.ui-v2 .ds-datos.ds-datos-ficha { grid-template-columns: minmax(0, 1fr); gap: var(--ds-e3); }
/* texto largo en tres líneas como máximo (texto entero en title) */
body.ui-v2 .ds-texto-3-lineas {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
    overflow-wrap: anywhere;
}
@media (max-width: 1099.98px) {
    body.ui-v2 .ds-ficha { grid-template-columns: minmax(0, 1fr); }
    body.ui-v2 .ds-ficha-lateral { order: -1; }
    body.ui-v2 .ds-datos.ds-datos-ficha { grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); }
}
/* Panel Detalle (ds.tarjeta con .det-panel.ds-detalle; lo arma
   templates/solicitudes/_detalle_panel.html y lo maneja static/js/detalle_siaf.js):
   dentro del panel lateral va plana, porque el panel ya es la tarjeta. */
body.ui-v2 .ds-detalle { margin-bottom: 0; }
body.ui-v2 .ds-detalle .ds-tarjeta-acciones { align-items: center; }
body.ui-v2 .ds-detalle-estado { display: inline-flex; align-items: center; margin-right: var(--ds-e1); }
body.ui-v2 .offcanvas .ds-detalle { border: 0; border-radius: 0; box-shadow: none; }
body.ui-v2 .offcanvas .ds-detalle > .ds-tarjeta-cabeza { padding: 0 0 var(--ds-e3); }
body.ui-v2 .offcanvas .ds-detalle > .ds-tarjeta-cabeza .ds-tarjeta-titulo { display: none; }   /* el título ya está en el panel */
body.ui-v2 .offcanvas .ds-detalle > .ds-tarjeta-cuerpo { padding: 0; }
/* cuadre y avisos: franjas en línea con su lista */
body.ui-v2 .ds-detalle-cuadre { margin: 0 0 var(--ds-e3); }
body.ui-v2 .ds-detalle-lista { margin: 4px 0 0; padding-left: 1.2em; font-size: var(--ds-tam-tabla); line-height: 1.38462; }
body.ui-v2 .ds-detalle-lista > li + li { margin-top: 2px; }
/* pestañas de reportes (.nav-tabs re-pintadas, §14) y la nota de precios */
body.ui-v2 .ds-detalle-pestanas {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--ds-e2) var(--ds-e4);
    margin: var(--ds-e4) 0 var(--ds-e3);
    border-bottom: 1px solid var(--ds-borde);
}
body.ui-v2 .ds-detalle-pestanas > .nav-tabs { flex-wrap: nowrap; margin-bottom: -1px; border-bottom: 0; }
body.ui-v2 .ds-detalle-pestanas > .ds-detalle-nota { padding-bottom: 10px; }
body.ui-v2 .ds-detalle-nota {
    margin: 0;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
body.ui-v2 .ds-detalle-nota strong { color: var(--ds-texto); font-weight: 600; }
/* barra de cada reporte: nota a la izquierda, herramientas a la derecha */
body.ui-v2 .ds-detalle-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-e2) var(--ds-e4);
    margin-bottom: var(--ds-e3);
}
body.ui-v2 .ds-detalle-herramientas { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ds-e3); margin-left: auto; }
/* tablas de los reportes: marco de 12 px sin sombra, números a la derecha */
body.ui-v2 .ds-detalle-marco { border-radius: var(--ds-radio-campo); box-shadow: none; }
body.ui-v2 .ds-detalle-marco > .table-responsive { max-height: min(60vh, 560px); overflow: auto; scrollbar-width: thin; }
body.ui-v2 .ds-detalle-marco .ds-tabla > thead > tr > th { position: sticky; top: 0; z-index: 2; }
/* (clases .det-* que arman _detalle_panel.html y detalle_siaf.js; custom.css las
   pintaba en azul marino: aquí con los tokens) */
body.ui-v2 .det-tabla th.det-num,
body.ui-v2 .det-tabla td.det-num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
body.ui-v2 .det-tabla td.det-descripcion { min-width: 16em; white-space: normal; overflow-wrap: anywhere; }
body.ui-v2 .det-tabla td.det-descripcion > .ds-pildora { margin-left: 4px; vertical-align: 1px; }
body.ui-v2 .det-tabla td.det-fuerte { font-weight: 600; }
body.ui-v2 .det-tabla > tbody > tr > td.det-no_aplica { --bs-table-bg-type: var(--ds-neutro-fondo); color: var(--ds-texto-2); }
body.ui-v2 .det-tabla > tbody > tr.det-grupo > td {
    --bs-table-bg-type: var(--ds-fondo);
    height: auto;
    padding-top: 8px;
    padding-bottom: 8px;
    color: var(--ds-texto);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 600;
    line-height: 1.33334;
}
body.ui-v2 .det-tabla > tbody > tr.det-subtotal > td { --bs-table-bg-type: var(--ds-fondo); font-weight: 600; }
body.ui-v2 .det-tabla > tfoot > tr.det-total > td { border-top: 1px solid var(--ds-borde-fuerte); font-weight: 600; }
body.ui-v2 .det-punto { width: 6px; height: 6px; margin-left: 4px; background: var(--ds-aviso-punto); }
body.ui-v2 .ds-detalle-leyenda {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ds-e1) var(--ds-e4);
    margin: var(--ds-e2) 0 0;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.33334;
}
body.ui-v2 .ds-detalle-leyenda-item { display: inline-flex; align-items: center; gap: 6px; }
body.ui-v2 .ds-detalle-leyenda .det-leyenda {
    display: inline-grid;
    place-items: center;
    width: 16px;
    height: 12px;
    margin: 0;
    border: 1px solid var(--ds-borde-fuerte);
    border-radius: 3px;
}
body.ui-v2 .ds-detalle-leyenda .det-leyenda.det-no_aplica { background: var(--ds-neutro-fondo); }
body.ui-v2 .ds-detalle-leyenda .det-leyenda.det-conservada { background: var(--ds-superficie); }
body.ui-v2 .ds-detalle-leyenda .det-leyenda > .det-punto { margin: 0; }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-ficha-visor { height: 70vh; min-height: 360px; }
    body.ui-v2 .ds-detalle-herramientas { margin-left: 0; }
    body.ui-v2 .ds-detalle-pestanas > .nav-tabs { overflow-x: auto; scrollbar-width: none; }
}


/* 25n. SIAF 182 y cuadrícula de captura 465 ------------------------------------ */
/* Nombres s182-/s465- a propósito: la cuadrícula 465 (static/js/sabana_465.js)
   es una planilla de captura, no una tabla de datos, y no tiene pieza genérica
   equivalente; custom.css (sección K, ya no se carga) la pintaba en azul
   marino. Todo en em: la fila (2.6154em = 34 px con 13 px) crece con la letra.
     (1) Piezas de las pantallas del 182 (lista, precios, pegar)
     (2) Cuadrícula 465: marco, encabezado claro fijo, celdas, marca, cruce,
         columna apagada, escoger código
     (3) Barra de la cuadrícula (subproducto activo, estado del guardado) y
         atajos del "?"
     (4) Proveedor, montos y generar
     (5) Barra de total fija abajo */

/* (1) Piezas de las pantallas del 182 */
/* formulario en línea del encabezado (centro de costo + "Nuevo A-01 SIAF") */
body.ui-v2 .s182-form-nueva { flex-wrap: nowrap; margin: 0; }
body.ui-v2 .s182-select-en-linea { width: auto; max-width: min(22em, 100%); }
@media (max-width: 767.98px) {
    body.ui-v2 .s182-form-nueva { flex-wrap: wrap; min-width: 0; max-width: 100%; }
}
/* lista de capturas: el proveedor (texto que se parte) toma una parte menor
   para que el nombre de quien la creó quepa en una línea desde 1440 */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).s182-col-proveedor { --ds-col-parte: 18%; --ds-col-texto-min: 10em; }
/* contenido ancho (1920): sobra lugar para quien la creó, la fecha y el
   centro de costo; el proveedor toma más parte y no se parte en dos líneas */
@container contenido (min-width: 1500px) {
    body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).s182-col-proveedor { --ds-col-parte: 28%; }
}
/* precios: proveedor y descripción se quedan con casi todo el ancho que sobra
   (las cifras y códigos miden lo suyo; sin esto el precio quedaba con un
   hueco grande a su izquierda y el nombre del proveedor se cortaba a 1440) */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).s182-col-proveedor-precio { --ds-col-parte: 32%; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).s182-col-descripcion { --ds-col-parte: 30%; }
/* en teléfono la tabla se desplaza de lado dentro de su marco: el proveedor
   conserva un ancho que deja leer el nombre y el NIT entero */
@media (max-width: 767.98px) {
    body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).s182-col-proveedor-precio { --ds-col-flex-min: 13em; }
}
/* nombre de una persona: una línea si hay lugar; en contenido angosto se
   parte en dos (nunca "…") */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.s182-col-persona { line-height: 1.3077; white-space: normal; }
/* piso de 9em (como los de §23j: un bloque de alto 0; min-width en celdas no vale igual en WebKit y Blink) */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.s182-col-persona::after { content: ""; display: block; width: 9em; height: 0; }
/* filtro de proveedor (select en píldora): tope en em, el nombre entero en la lista */
body.ui-v2 .s182-select-proveedor { max-width: min(24em, 100%); }
/* precio: campo corto */
body.ui-v2 .s182-campo-precio { max-width: 14em; }
/* Pegar precios: cuadro de pegado en letra de ancho fijo (las columnas de
   Excel llegan separadas por tabulador y así se leen alineadas) */
body.ui-v2 .s182-pegado {
    min-height: 12em;
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: var(--ds-tam-tabla);
    line-height: 1.53847;
    tab-size: 14;
    -moz-tab-size: 14;
    resize: vertical;
}
body.ui-v2 .s182-resumen { gap: 6px; }
body.ui-v2 .s182-pie-guardar { flex: 1 1 auto; justify-content: flex-end; flex-wrap: wrap; margin: 0; }
body.ui-v2 .s182-pie-texto {
    margin-right: auto;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
/* celdas de la vista previa */
body.ui-v2 .s182-codigo { line-height: 1.38462; white-space: normal; }
body.ui-v2 .s182-nota {
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.33334;
    white-space: normal;
}
body.ui-v2 .s182-motivo-problema {
    margin-top: 2px;
    color: var(--ds-error);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.33334;
    white-space: normal;
}
body.ui-v2 .s182-col-que-pasa .ds-pildora + .s182-nota,
body.ui-v2 .s182-col-que-pasa .ds-pildora + .s182-motivo-problema { margin-top: 4px; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).s182-col-que-pasa { --ds-col-parte: 26%; }
body.ui-v2 .s182-precio-anterior { color: var(--ds-texto-2); text-decoration: line-through; }
body.ui-v2 .s182-flecha { color: var(--ds-texto-3); }

/* (2) Cuadrícula 465 */
/* Marco: tarjeta blanca de radio 16 con la barra de la cuadrícula arriba y
   la zona con desplazamiento (encabezado y columnas de código fijos). */
body.ui-v2 .s465-marco {
    display: flex;
    flex-direction: column;
    min-width: 0;
    overflow: hidden;
    background: var(--ds-superficie);
    border: 1px solid var(--ds-borde-marco);
    border-radius: var(--ds-radio-tarjeta);
    box-shadow: var(--ds-sombra-tarjeta);
}
body.ui-v2 .s465-scroll {
    /* alto de la ventana menos la barra superior, el encabezado, la barra de
       la cuadrícula y la barra de total de abajo (1440×790: 13 filas; el
       borde de abajo queda 16 px sobre la barra de total) */
    max-height: calc(100vh - 272px);
    min-height: 320px;
    overflow: auto;
    border: 0;
    border-radius: 0;
    background: var(--ds-superficie);
    scrollbar-width: thin;
}
/* captura generada (solo lectura): sin filas vacías, el marco mide lo que
   tienen sus filas (el piso de 320 px es para capturar) */
body.ui-v2 .s465-solo-lectura .s465-scroll { min-height: 0; }
body.ui-v2 .s465-tabla {
    --s465-fila: 2.6154em;                 /* 34 px con 13 px; crece con la letra */
    --s465-linea: var(--ds-borde-suave);                 /* línea fina entre celdas */
    --s465-linea-grupo: var(--ds-borde-fuerte);
    --s465-fondo-fijo: var(--ds-superficie);
    --s465-col-activa: var(--ds-acento-tenue);            /* columna del cruce */
    --s465-fila-foco: var(--ds-acento-tenue);             /* fila del cruce */
    --s465-celda-cruce: var(--ds-acento-claro);
    border-collapse: separate;
    border-spacing: 0;
    table-layout: fixed;
    color: var(--ds-texto);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-tabla);
    font-variant-numeric: tabular-nums;
}
/* Encabezado claro de UNA fila, fijo al desplazar, en tipo oración. */
body.ui-v2 .s465-tabla th {
    position: sticky;
    top: 0;
    z-index: 3;
    height: auto;
    padding: 8px 4px 0;
    background: var(--ds-encabezado-tabla);
    color: var(--ds-texto-2);
    border: 0;
    border-right: 1px solid var(--s465-linea);
    box-shadow: inset 0 -1px 0 var(--ds-borde);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 500;
    line-height: 1.33334;
    letter-spacing: 0;
    text-align: center;
    text-transform: none;
    vertical-align: bottom;
}
body.ui-v2 .s465-tabla th.s465-fija,
body.ui-v2 .s465-tabla th.s465-desc-th {
    z-index: 5;
    padding: 0 10px 10px;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    letter-spacing: 0;
    text-align: left;
    text-transform: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
body.ui-v2 .s465-tabla th.s465-desc-th { z-index: 3; border-left: 1px solid var(--s465-linea-grupo); }
body.ui-v2 .s465-tabla th.s465-c-num { text-align: right; padding-right: 8px; padding-left: 4px; }
body.ui-v2 .s465-tabla th.s465-th-sp .s465-pr {
    display: block;
    color: var(--ds-texto-2);
    font-family: var(--ds-fuente);
    font-size: 11px;
    font-weight: 500;
    line-height: 1.27273;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
body.ui-v2 .s465-tabla th.s465-th-sp .s465-nu {
    display: block;
    padding-bottom: 5px;
    color: var(--ds-texto);
    font-family: var(--ds-fuente);
    font-size: var(--ds-tam-tabla);
    font-weight: 600;
    line-height: 1.3077;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
/* Noche 5 · 4: el saldo del subproducto (mismo dato que Creación general), bajo el número */
body.ui-v2 .s465-tabla th.s465-th-sp .s465-saldo {
    display: block;
    padding-bottom: 5px;
    color: var(--ds-texto-2);
    font-family: var(--ds-fuente);
    font-size: 11px;
    font-weight: 500;
    line-height: 1.27273;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
body.ui-v2 .s465-tabla th.s465-th-sp .s465-saldo:empty { display: none; }
body.ui-v2 .s465-tabla th.s465-th-sp .s465-saldo-neg { color: var(--ds-error); }
/* la línea de 3 px con el color del producto (lo pone el JS) */
body.ui-v2 .s465-tabla th.s465-th-sp i {
    display: block;
    height: 3px;
    margin: 0 6px 6px;
    border-radius: 2px;
}
body.ui-v2 .s465-tabla th.s465-th-sp.s465-th-activa { background: var(--ds-acento-claro); }
body.ui-v2 .s465-tabla th.s465-th-sp.s465-th-activa .s465-pr { color: var(--ds-acento-oscuro); }
body.ui-v2 .s465-tabla th.s465-th-sp.s465-th-activa .s465-nu { color: var(--ds-acento-oscuro); }
body.ui-v2 .s465-tabla th.s465-deshab { background: var(--ds-neutro-fondo); }
body.ui-v2 .s465-tabla th.s465-deshab .s465-nu { color: var(--ds-texto-3); text-decoration: line-through; opacity: 1; }
body.ui-v2 .s465-tabla th.s465-deshab .s465-pr { opacity: 1; }
body.ui-v2 .s465-tabla th.s465-deshab i { background: repeating-linear-gradient(45deg, var(--ds-texto-3), var(--ds-texto-3) 3px, transparent 3px, transparent 6px) !important; }
/* Filas: una línea, alto en em (crece con la letra, nunca se enciman). */
body.ui-v2 .s465-tabla tbody tr { height: auto; }
body.ui-v2 .s465-tabla td {
    height: var(--s465-fila);
    max-height: none;
    padding: 0;
    background: var(--ds-superficie);
    border: 0;
    border-bottom: 1px solid var(--s465-linea);
    border-right: 1px solid var(--s465-linea);
    font-size: var(--ds-tam-tabla);
    line-height: 1.3077;
    white-space: nowrap;
    overflow: hidden;
    vertical-align: middle;
}
/* columnas de código congeladas: su `left` lo escribe el JS en variables */
body.ui-v2 .s465-tabla td.s465-fija,
body.ui-v2 .s465-tabla th.s465-fija { position: sticky; background: var(--s465-fondo-fijo); }
body.ui-v2 .s465-tabla thead th.s465-fija { background: var(--ds-encabezado-tabla); }   /* encabezado gris, como toda tabla */
body.ui-v2 .s465-tabla td.s465-fija { z-index: 2; }
body.ui-v2 .s465-tabla .s465-c-num { left: 0; }
body.ui-v2 .s465-tabla .s465-c-igss { left: var(--s465-l-igss, 40px); }
body.ui-v2 .s465-tabla .s465-c-minfin { left: var(--s465-l-minfin, 180px); }
body.ui-v2 .s465-tabla td.s465-borde,
body.ui-v2 .s465-tabla th.s465-borde { border-right: 1px solid var(--s465-linea-grupo); }
/* el código no se recorta con la celda: el cuadro de "varias coincidencias" cuelga de ella */
body.ui-v2 .s465-tabla td.s465-codigo { overflow: visible; }
body.ui-v2 .s465-tabla td.s465-num {
    padding: 0 8px 0 4px;
    background: var(--ds-fondo);
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta);
    text-align: right;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .s465-tabla td.s465-desc {
    max-width: 0;
    padding: 0 12px;
    border-left: 1px solid var(--s465-linea-grupo);
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
body.ui-v2 .s465-tabla input {
    display: block;
    width: 100%;
    height: var(--s465-fila);
    padding: 0 10px;
    border: 0;
    border-radius: 0;
    outline: none;
    background: transparent;
    color: var(--ds-texto);
    font: inherit;
    font-size: var(--ds-tam-tabla);
    line-height: normal;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .s465-tabla input[readonly] { cursor: default; }
/* celdas de datos blancas; el <col> pinta solo la columna del cruce */
body.ui-v2 .s465-tabla col { background: transparent; }
body.ui-v2 .s465-tabla col.s465-col-activa { background: var(--s465-col-activa); }
body.ui-v2 .s465-tabla td.s465-sp { background: transparent; text-align: center; }
/* donde cambia el producto, una divisoria más marcada */
body.ui-v2 .s465-tabla th.s465-inicio-grupo,
body.ui-v2 .s465-tabla td.s465-inicio-grupo { border-left: 1px solid var(--s465-linea-grupo); }
/* el cruce: fila entera, columna entera (vía <col>) y la celda donde se cruzan */
body.ui-v2 .s465-tabla tr.s465-foco td { background: var(--s465-fila-foco); }
body.ui-v2 .s465-tabla tr.s465-foco td.s465-num { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
body.ui-v2 .s465-tabla td.s465-cruce { background: var(--s465-celda-cruce) !important; box-shadow: inset 0 0 0 2px var(--ds-acento); }
/* la marca: botón que llena la celda; marcada = relleno primario con ✓ blanco,
   como un mosaico redondeado dentro de la celda */
body.ui-v2 .s465-marca {
    display: block;
    width: 100%;
    height: var(--s465-fila);
    padding: 4px 5px;
    border: 0;
    border-radius: 10px;
    outline: none;
    background: transparent;
    background-clip: content-box;
    font: inherit;
    font-size: var(--ds-tam-tabla);
    cursor: pointer;
    transition: background-color var(--ds-transicion);
}
body.ui-v2 .s465-marca.s465-on,
body.ui-v2 .s465-marca.s465-on:hover {
    background: var(--ds-relleno-primario) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'><path d='M6.2 12.3 2.5 8.6l1.3-1.3 2.4 2.4 6-6 1.3 1.3z'/></svg>") center / 1.1em 1.1em no-repeat;
    background-clip: content-box;
}
/* vacía al pasar el mouse: el mosaico en celeste claro con un ✓ tenue (se ve dónde cae la marca) */
@media (hover: hover) {
    body.ui-v2 .s465-marca:not(.s465-on):not(.s465-deshab):not(:disabled):hover {
        background: var(--ds-acento-claro) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23a3c5d9'><path d='M6.2 12.3 2.5 8.6l1.3-1.3 2.4 2.4 6-6 1.3 1.3z'/></svg>") center / 1.1em 1.1em no-repeat;
        background-clip: content-box;
    }
}
body.ui-v2 .s465-marca:disabled { cursor: default; }
/* subproducto deshabilitado en Saldos SIGES: celda rayada gris claro, no
   acepta marcas nuevas; una marca vieja se conserva con borde rojo */
body.ui-v2 .s465-tabla td.s465-sp-deshab { background: repeating-linear-gradient(135deg, var(--ds-hover) 0 5px, var(--ds-neutro-fondo) 5px 10px); }
body.ui-v2 .s465-marca.s465-deshab { cursor: not-allowed; }
body.ui-v2 .s465-marca.s465-deshab.s465-on { box-shadow: inset 0 0 0 2px var(--ds-error); }
/* celda activa (foco) */
body.ui-v2 .s465-tabla td.s465-activa { z-index: 2; box-shadow: inset 0 0 0 2px var(--ds-acento); }
body.ui-v2 .s465-tabla td.s465-fija.s465-activa { z-index: 3; }
body.ui-v2 .s465-tabla td.s465-activa .s465-marca.s465-on { box-shadow: none; }
body.ui-v2 .s465-tabla td.s465-rango { background: var(--ds-acento-claro-2) !important; }
/* estados de la fila */
body.ui-v2 .s465-tabla tr.s465-error td.s465-codigo input { color: var(--ds-error); font-weight: 600; }
body.ui-v2 .s465-tabla tr.s465-error td.s465-desc { color: var(--ds-error); }
body.ui-v2 .s465-tabla tr.s465-ambiguo td.s465-desc { color: var(--ds-aviso); }
body.ui-v2 .s465-tabla tr.s465-invalida td { background: var(--ds-error-tenue); }
body.ui-v2 .s465-tabla tr.s465-invalida td.s465-num { box-shadow: inset 3px 0 0 var(--ds-error-borde); }
body.ui-v2 .s465-punto {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--ds-acento);
    vertical-align: middle;
    animation: s465-latido 1.2s ease-in-out infinite;
}
body.ui-v2 .s465-buscando { color: var(--ds-texto-3); }
@keyframes s465-latido { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
/* tirador para repetir un código (arrastrar) */
body.ui-v2 .s465-handle {
    position: absolute;
    right: 1px;
    bottom: 1px;
    width: 8px;
    height: 8px;
    border: 1.5px solid var(--ds-superficie);
    border-radius: 2px;
    background: var(--ds-acento);
    cursor: crosshair;
    z-index: 6;
}
body.ui-v2 .s465-tabla td.s465-fija .s465-handle { right: 1px; bottom: 1px; }
/* vaciar la fila: ✕ discreto al pasar el mouse */
body.ui-v2 .s465-tabla td.s465-quitar-td { text-align: center; }
body.ui-v2 .s465-quitar {
    display: none;
    width: 100%;
    height: 2.125em;                       /* = alto de la fila (34 px) con su letra de 16 px: pasar el mouse no agranda la fila */
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--ds-texto-3);
    font-size: 1.2308em;
    line-height: 1;
    cursor: pointer;
}
body.ui-v2 .s465-quitar:hover { color: var(--ds-error); }
body.ui-v2 .s465-tabla tr:hover .s465-quitar:not(:disabled) { display: block; }
/* "varias coincidencias": menú que cuelga de la celda del código */
body.ui-v2 .s465-chooser {
    position: absolute;
    left: 0;
    top: calc(100% + 4px);
    z-index: 20;
    min-width: 34em;
    max-width: 52em;
    padding: 4px;
    background: var(--ds-superficie);
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-campo);
    box-shadow: var(--ds-sombra-menu);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    white-space: nowrap;
}
body.ui-v2 .s465-chooser div {
    padding: 8px 10px;
    border: 0;
    border-radius: var(--ds-radio-item);
    cursor: pointer;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
body.ui-v2 .s465-chooser div:hover { background: var(--ds-hover); }
body.ui-v2 .s465-chooser div.s465-sel { background: var(--ds-acento-claro); color: var(--ds-acento-oscuro); }
body.ui-v2 .s465-chooser code { color: inherit; font-weight: 600; }
/* contrato abierto dentro de la descripción: píldora corta de aviso */
body.ui-v2 .s465-ca {
    display: inline-block;
    padding: 0 6px;
    border: 0;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-aviso-fondo);
    color: var(--ds-aviso);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 500;
    line-height: 1.5;
    vertical-align: baseline;
}
body.ui-v2 .s465-ca.s465-ca-aviso { background: transparent; box-shadow: inset 0 0 0 1px var(--ds-aviso-borde); }
/* Año de precio por orden (Noche 4 · Paso 1, 2026-10-17): selector chico en su columna; un REMANENTE (año distinto al
   de la captura) lleva la marca neutra «Remanente 2026» al inicio de la descripción (no es un aviso: es normal) */
body.ui-v2 .s465-ca.s465-remanente { background: var(--ds-neutro-fondo); color: var(--ds-neutro); }
body.ui-v2 .s465-tabla td.s465-anio-td { text-align: center; padding: 0 2px; }
body.ui-v2 .s465-tabla select.s465-anio {
    width: 100%;
    min-height: 1.9231em;
    padding: 0 2px;
    border: 1px solid transparent;
    border-radius: var(--ds-radio-item);
    background: transparent;
    color: var(--ds-texto-2);
    font: inherit;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .s465-tabla select.s465-anio:hover, body.ui-v2 .s465-tabla select.s465-anio:focus { border-color: var(--ds-borde-fuerte); background: var(--ds-superficie); }
body.ui-v2 .s465-tabla tr.s465-fila-remanente select.s465-anio { color: var(--ds-texto); font-weight: 600; }
body.ui-v2 .s465-tabla th.s465-anio-th { padding: 0 4px 10px; text-align: center; }   /* misma línea base que «Descripción» */
body.ui-v2 .s465-tabla tr.s465-sin-orden select.s465-anio { visibility: hidden; }
body.ui-v2 .s465-anio-defecto { display: inline-flex; align-items: center; gap: var(--ds-e1); margin: 0; color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); white-space: nowrap; }
body.ui-v2 .s465-anio-defecto select { width: auto; }
body.ui-v2 .s182-reabrir, body.ui-v2 .s182-copiar-form { gap: var(--ds-e2); flex-wrap: wrap; align-items: center; margin-bottom: var(--ds-e3); }
body.ui-v2 .s182-reabrir input { max-width: 28em; }
body.ui-v2 .s182-movimientos { margin: var(--ds-e2) 0 0; }
body.ui-v2 .s182-copiar { margin-top: var(--ds-e4); }

/* (3) Barra de la cuadrícula y atajos */
/* subproducto activo (código en píldora + nombre) y, a la derecha, el estado
   del guardado. Todo en una línea de alto estable: nada mueve la cuadrícula. */
body.ui-v2 .s465-barra-grilla {
    display: flex;
    align-items: center;
    gap: var(--ds-e3);
    min-width: 0;
    min-height: 3.2em;
    padding: 8px 12px 8px 16px;
    border-bottom: 1px solid var(--ds-borde);
}
body.ui-v2 .s465-chip {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    width: auto;
    min-width: 15.5em;
    min-height: 1.8em;
    padding: 2px 12px;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-acento-claro);
    color: var(--ds-acento-oscuro);
    font-size: var(--ds-tam-etiqueta);
    font-weight: 500;
    line-height: 1.33334;
    letter-spacing: 0;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .s465-chip b { font-weight: 600; }
/* sin subproducto elegido ("Subproducto —"): texto apagado sin fondo; con fondo gris parecía
   un campo deshabilitado. Conserva su ancho mínimo (la grilla no se mueve). */
body.ui-v2 .s465-chip.s465-chip-vacio { background: transparent; color: var(--ds-texto-2); padding-left: 0; }
body.ui-v2 .s465-col-etiqueta {
    flex: 1 1 0;
    min-width: 0;
    height: auto;
    color: var(--ds-texto-2);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
body.ui-v2 .s465-col-nombre { color: var(--ds-texto); }
body.ui-v2 .s465-col-producto { color: var(--ds-texto-2); }
body.ui-v2 .s465-estado { flex: none; margin-left: auto; }
/* atajos de teclado dentro del "?" del encabezado */
body.ui-v2 .popover:has(.s465-atajos) { --bs-popover-max-width: 33em; }
body.ui-v2 .s465-atajos {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 8px 12px;
    align-items: baseline;
    margin: 0;
}
body.ui-v2 .s465-atajos dt { margin: 0; color: var(--ds-texto); font-weight: 500; white-space: nowrap; }
body.ui-v2 .s465-atajos kbd { margin-right: 2px; }
body.ui-v2 .s465-atajos dd { margin: 0; }

/* (4) Proveedor, montos y generar */
body.ui-v2 .s465-inferior {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ds-e4);
    align-items: start;
    margin-top: var(--ds-e4);
}
@media (min-width: 1100px) {
    body.ui-v2 .s465-inferior { grid-template-columns: minmax(17em, 1fr) minmax(0, 2fr) minmax(19em, 1fr); }
}
body.ui-v2 .s465-inferior > .ds-tarjeta { margin-bottom: 0; }
/* tarjeta angosta: el título no ocupa 240 px de base, así "Precios" queda en su misma línea */
body.ui-v2 .s465-inferior .ds-tarjeta-titulos { flex-basis: auto; }
body.ui-v2 .s465-proveedor-elegido {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-height: 2.4em;
    margin-bottom: var(--ds-e3);
    line-height: 1.42858;
}
body.ui-v2 .s465-prov-nombre { color: var(--ds-texto); font-weight: 600; overflow-wrap: anywhere; }
body.ui-v2 .s465-prov-nit { color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); line-height: 1.33334; font-variant-numeric: tabular-nums; }
body.ui-v2 .s465-prov-vacio { color: var(--ds-texto-2); }
body.ui-v2 .s465-buscador-proveedor { position: relative; }
body.ui-v2 .s465-buscador-proveedor > .ti {
    position: absolute;
    top: 50%;
    left: 14px;
    transform: translateY(-50%);
    color: var(--ds-texto-3);
    font-size: 16px;
    pointer-events: none;
}
body.ui-v2 .s465-buscador-proveedor > .form-control { padding-left: 38px; border-radius: var(--ds-radio-pildora); }
/* resultados: se abren hacia ARRIBA (abajo está la barra de total fija) */
body.ui-v2 .s465-prov-lista {
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(100% + 6px);
    z-index: 30;
    max-height: 18em;
    padding: 4px;
    overflow: auto;
    background: var(--ds-superficie);
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-campo);
    box-shadow: var(--ds-sombra-menu);
    font-size: var(--ds-tam-tabla);
}
body.ui-v2 .s465-prov-lista > div {
    padding: 8px 10px;
    border: 0;
    border-radius: var(--ds-radio-item);
    cursor: pointer;
}
body.ui-v2 .s465-prov-lista > div:hover { background: var(--ds-hover); }
body.ui-v2 .s465-prov-lista > div.s465-sel { background: var(--ds-acento-claro); }
/* adentro de cada resultado, ningún div lleva relleno, línea ni fondo propio */
body.ui-v2 .s465-prov-lista > div div { padding: 0; border: 0; background: transparent; }
body.ui-v2 .s465-prov-lista > div + div { margin-top: 2px; }
body.ui-v2 .s465-prov-lista .s465-nom { color: var(--ds-texto); font-weight: 600; line-height: 1.38462; }
body.ui-v2 .s465-prov-lista > div.s465-sel .s465-nom { color: var(--ds-acento-oscuro); }
body.ui-v2 .s465-prov-lista .s465-nit { color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); line-height: 1.33334; }
body.ui-v2 .s465-prov-lista .s465-prov-sin { color: var(--ds-texto-3); cursor: default; }
/* montos por código: el código se recorta con "…", las cifras no se parten */
body.ui-v2 .s465-montos > :is(thead, tbody, tfoot) > tr > :is(th, td).s465-res-codigo { width: 100%; }
body.ui-v2 .s465-montos > tbody > tr > td.s465-res-codigo > .ds-celda { width: 0; min-width: 100%; }
body.ui-v2 .s465-montos .s465-res-cifra { width: 1%; white-space: nowrap; font-variant-numeric: tabular-nums; }
body.ui-v2 .s465-montos > tbody > tr.s465-res-vacio > td {
    height: auto;
    padding: var(--ds-e5) var(--ds-e4);
    color: var(--ds-texto-2);
    text-align: center;
}
body.ui-v2 .s465-montos > tfoot > tr > th { font-size: var(--ds-tam-tabla); }
body.ui-v2 .s465-montos > tfoot > tr > th:first-child { padding-left: var(--ds-e4); }
body.ui-v2 .s465-montos > tfoot > tr > th:last-child { padding-right: var(--ds-e4); }
body.ui-v2 .s465-sin-dato { color: var(--ds-texto-2); }
/* generar */
body.ui-v2 .s465-form-generar { display: flex; flex-direction: column; gap: var(--ds-e3); }
body.ui-v2 .s465-form-generar .ds-campo { margin: 0; }
body.ui-v2 .s465-btn-generar { width: 100%; margin-top: var(--ds-e1); }
body.ui-v2 .s465-pend:empty,
body.ui-v2 .s465-msg:empty { display: none; }
body.ui-v2 .s465-pend {
    color: var(--ds-aviso);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.5;
}
/* un pendiente corto (código: sin precio) no se parte en dos líneas */
body.ui-v2 .s465-pend-item { white-space: nowrap; }
body.ui-v2 .s465-msg {
    color: var(--ds-error);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.5;
}
body.ui-v2 .s465-generado { margin: 0; line-height: 1.5; }
body.ui-v2 .s465-generado a { white-space: nowrap; }

/* (5) Barra de total fija abajo */
/* Siempre visible mientras se captura: pegada al pie de la ventana (sticky al
   final del contenido, así tiene el mismo ancho que la página). Blanca y
   flotante, como el pie de los formularios largos. */
body.ui-v2 .s465-barra-total {
    position: sticky;
    left: auto;
    right: auto;
    bottom: var(--ds-e3);
    z-index: 1015;
    display: flex;
    align-items: center;
    gap: var(--ds-e4);
    min-width: 0;
    margin-top: var(--ds-e4);
    padding: 10px 20px;
    background: var(--ds-superficie);
    color: var(--ds-texto);
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-dialogo);
    box-shadow: var(--ds-sombra-pie);   /* hacia arriba, como .ds-pie-formulario */
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
}
body.ui-v2 .s465-barra-resumen {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: var(--ds-e3);
    min-width: 0;
}
/* franja del color de la página bajo la barra pegada (como bajo .ds-pie-formulario, §24d) */
body.ui-v2 .s465-barra-total::after {
    content: "";
    position: absolute;
    top: 100%;
    left: -4px;                 /* tapa también el borde y la sombra de la tarjeta que pasa por detrás */
    right: -4px;
    height: calc(var(--ds-e3) + 1px);
    background: var(--ds-fondo);
    pointer-events: none;
}
body.ui-v2 .s465-barra-detalle { flex: none; color: var(--ds-texto-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
body.ui-v2 .s465-barra-total .s465-barra-codigos {
    display: flex;
    flex: 1 1 auto;
    gap: 6px;
    min-width: 8em;
    overflow-x: auto;
    white-space: nowrap;
    scrollbar-width: none;
}
body.ui-v2 .s465-barra-total .s465-barra-codigos::-webkit-scrollbar { display: none; }
body.ui-v2 .s465-barra-total .s465-barra-codigos span {
    flex: none;
    padding: 2px 10px;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-neutro-fondo);
    color: var(--ds-neutro);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.5;
    font-variant-numeric: tabular-nums;
}
body.ui-v2 .s465-barra-total .s465-barra-codigos span.s465-sin-precio { background: var(--ds-aviso-fondo); color: var(--ds-aviso); }
body.ui-v2 .s465-barra-total code { color: var(--ds-texto); font-weight: 600; }
body.ui-v2 .s465-barra-total .s465-sin-precio code { color: inherit; }
body.ui-v2 .s465-barra-bloque {
    display: flex;
    flex: none;
    align-items: baseline;
    gap: var(--ds-e2);
    padding-left: var(--ds-e4);
    border-left: 1px solid var(--ds-borde);
}
body.ui-v2 .s465-barra-rotulo { color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); font-weight: 500; }
body.ui-v2 .s465-barra-total .s465-barra-monto {
    color: var(--ds-texto);
    font-size: 20px;
    font-weight: 700;
    line-height: 1.2;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
/* contrato abierto en vivo: píldora de aviso */
body.ui-v2 .s465-barra-ca {
    display: inline-flex;
    flex: 0 1 auto;
    max-width: 50%;                        /* los códigos conservan su lugar (se desplazan de lado) */
    align-items: center;
    gap: 6px;
    min-width: 0;
    padding: 2px 12px;
    border-radius: var(--ds-radio-pildora);
    background: var(--ds-aviso-fondo);
    color: var(--ds-aviso);
    font-size: var(--ds-tam-etiqueta);
    line-height: 1.5;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
body.ui-v2 .s465-barra-ca[hidden] { display: none; }
body.ui-v2 .s465-barra-ca > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
body.ui-v2 .s465-barra-ca code { color: inherit; font-weight: 600; }
body.ui-v2 .s465-barra-ca a { color: inherit; text-decoration: underline; }
@media (max-width: 767.98px) {
    body.ui-v2 .s465-barra-total { flex-wrap: wrap; gap: var(--ds-e2) var(--ds-e3); padding: 8px 14px; bottom: 8px; }
    body.ui-v2 .s465-barra-resumen { flex-wrap: wrap; }
    body.ui-v2 .s465-barra-bloque { margin-left: auto; padding-left: 0; border-left: 0; }
    body.ui-v2 .s465-barra-total .s465-barra-codigos { flex-basis: 100%; }
    body.ui-v2 .s465-scroll { max-height: calc(100vh - 240px); }
}
@media (prefers-reduced-motion: reduce) {
    body.ui-v2 .s465-punto { animation: none; }
    body.ui-v2 .s465-marca { transition: none; }
}
@media print {
    body.ui-v2 .s465-barra-total,
    body.ui-v2 .s465-barra-grilla { display: none !important; }
}


/* 25o. Partes de ancho de columnas de Proveedores y Administración ------------ */
/* Nombres g-col- a propósito: cada uno fija la parte de UNA columna de una
   pantalla (§23j, --ds-col-parte y pisos), no es una pieza reutilizable. Las
   del 182 (s182-col-*) están en §25n. */
/* Proveedores */
/* El nombre es LA columna de la lista (el régimen y el contacto casi siempre
   están vacíos): se queda con la parte grande del ancho que sobra; régimen y
   contacto, con partes chicas (se parten en dos líneas). Con 40/15/16 a
   1440 se cortaban tres nombres mientras régimen y contacto mostraban "—". */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).g-col-proveedor { --ds-col-parte: 55%; --ds-col-flex-min: 12em; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).g-col-regimen { --ds-col-parte: 9%; --ds-col-texto-min: 9em; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).g-col-contacto { --ds-col-parte: 10%; --ds-col-texto-min: 9em; }
/* Administración */
/* usuarios: nombre + usuario de acceso (y "Administrador") y el centro de costo */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).g-col-usuario { --ds-col-parte: 24%; --ds-col-flex-min: 13em; }
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).g-col-centro { --ds-col-parte: 20%; --ds-col-texto-min: 9em; }

/* OCDS: el estado (píldora + motivo o respuesta de Guatecompras) se parte en dos líneas */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).g-col-estado-ocds { --ds-col-parte: 26%; --ds-col-texto-min: 11em; }
/* en el teléfono la tabla se desplaza de lado dentro de su marco: el nombre conserva un ancho legible */
@media (max-width: 767.98px) {
    body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).g-col-proveedor { --ds-col-flex-min: 14em; }
}


/* 25p. Actas de adjudicación (2026-09-28) --------------------------------------- */
/* Tabla con CAMPOS dentro de las celdas (ofertas, adjudicación, junta, líneas del
   acta): <table class="table ds-tabla ds-tabla-editable">. Los campos miden lo que
   una fila compacta (~32 px con letra de 13 px) y todo en em: con Safari alejado la
   letra sube y las cajas la siguen. Cantidad y precio en columnas de ancho fijo en
   em (caben 12 cifras con decimales). */
body.ui-v2 .ds-tabla-editable > tbody > tr > td { vertical-align: middle; }
body.ui-v2 .ds-tabla-editable :is(.form-control, .form-select) {
    min-height: 2.4615em;
    height: auto;
    padding-top: 0.2308em;
    padding-bottom: 0.2308em;
    font-size: var(--ds-tam-tabla);
}
body.ui-v2 .ds-tabla-editable .form-select { padding-right: 2em; }
body.ui-v2 .ds-tabla-editable > :is(thead, tbody, tfoot) > tr > :is(th, td).ds-col-cantidad { width: 10em; }
body.ui-v2 .ds-tabla-editable > :is(thead, tbody, tfoot) > tr > :is(th, td).ds-col-precio { width: 11em; }
body.ui-v2 .ds-tabla-editable > tfoot > tr > td { border-top: 1px solid var(--ds-borde); background: var(--ds-fondo); }
/* la lista de sugerencias de un campo dentro de una tabla no se recorta: el marco deja pasar lo que sobresale */
body.ui-v2 .ds-tabla-marco.ds-tabla-desborde { overflow: visible; }
/* Decisión por oferente: nombre y NIT · decisión · texto (justificación o motivo) */
body.ui-v2 .ds-decision {
    display: grid;
    grid-template-columns: minmax(16em, 1.2fr) auto minmax(18em, 2fr);
    gap: 0.9em 1.5em;
    align-items: start;
    padding: 1em 0;
    border-top: 1px solid var(--ds-borde);
}
body.ui-v2 .ds-decision:first-of-type { border-top: 0; }
@media (max-width: 991.98px) {
    body.ui-v2 .ds-decision { grid-template-columns: 1fr; }
}
/* Texto legal (CUARTO) tal como se imprime */
body.ui-v2 .ds-texto-legal {
    background: var(--ds-neutro-fondo);
    border-radius: var(--ds-radio-campo);
    padding: 0.9em 1.1em;
    line-height: 1.5;
    overflow-wrap: anywhere;
}
/* Lista de avisos (bullets sobrios) y fila de píldoras */
body.ui-v2 .ds-lista-avisos { margin: 0.5em 0 0; padding-left: 1.25em; color: var(--ds-texto-2); }
body.ui-v2 .ds-pildoras-fila { display: flex; flex-wrap: wrap; gap: 0.5em; align-items: center; }
body.ui-v2 .ds-pila-chica { display: flex; flex-direction: column; gap: 0.5em; }
body.ui-v2 .ds-pila-chica:empty { display: none; }
/* Campos cortos del formulario del acta */
body.ui-v2 .ds-campo-junta { min-width: 16em; }
body.ui-v2 .ds-cierre-texto { min-height: 2.5em; padding-top: 0.55em; }
body.ui-v2 .ds-campo-corto { max-width: 5.5em; }
body.ui-v2 .ds-tabla > tbody > tr.ds-fila-info > td { background: var(--ds-acento-claro); }
/* Ofertas pegadas de Guatecompras (2026-09-30): cantidad y precio fijos, como texto; columna «Incluye IVA» */
body.ui-v2 .ds-oferta-fija { display: inline-block; min-width: 100%; text-align: right; color: var(--ds-texto); font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-tabla > tbody > tr.ds-fila-fija > td { background: var(--ds-neutro-fondo); }
body.ui-v2 .ds-tabla-editable > :is(thead, tbody, tfoot) > tr > :is(th, td).ds-col-iva { width: 9em; }
/* «Incluye IVA» del adjudicado, dentro de la fila de justificación del bloque de adjudicación (2026-09-30) */
body.ui-v2 .ds-fila-justificacion .ds-campo-iva .form-select { width: auto; min-width: 8em; }
body.ui-v2 .ds-tabla-editable .ds-col-iva .form-select, body.ui-v2 .ds-tabla-editable > tbody > tr > td:has(> select[data-campo="incluye_iva"]) .form-select { min-width: 7em; }
/* Adjudicación en un solo bloque (2026-09-30): casilla «Adjudicar» por oferta y la fila de justificación del oferente */
body.ui-v2 .ds-tabla-editable > :is(thead, tbody, tfoot) > tr > :is(th, td).ds-col-adjudicar { width: 6.5em; }
body.ui-v2 .ds-tabla-editable .ds-celda-adjudicar { text-align: center; }
body.ui-v2 .ds-tabla-editable .ds-celda-adjudicar .form-check-input { width: 1.3em; height: 1.3em; margin: 0; float: none; }
body.ui-v2 .ds-tabla > tbody > tr.ds-fila-justificacion > td { background: var(--ds-acento-claro); border-top: 0; padding-top: 0.2em; padding-bottom: 0.7em; }
/* Aviso dentro de una fila de la tabla de ofertas (texto completo, se parte en líneas; 2026-09-30) */
body.ui-v2 .ds-aviso-fila { display: inline-block; color: var(--ds-aviso); font-size: 12px; line-height: 1.33; white-space: normal; }

/* Formulario del acta POR PASOS, en DOS COLUMNAS (2026-09-30): el formulario a la izquierda (45 %) y el acta en vivo
   a la derecha (55 %), fija al desplazarse y con su propio desplazamiento si es más alta que la ventana.
   <div class="ds-acta-dos-columnas"><div class="ds-acta-columna-form">pasos + una tarjeta .ds-acta-paso por paso +
   pie fijo</div><aside class="ds-acta-columna-hoja">…<div class="ds-acta-hoja-marco"><div class="ds-acta-previa">…
   Todo en fr / em; con el contenido angosto (umbral en em sobre main.ds-contenido) el acta pasa debajo, a todo el
   ancho. */
body.ui-v2 .ds-acta-dos-columnas {
    display: grid;
    grid-template-columns: minmax(0, 9fr) minmax(0, 11fr);
    gap: var(--ds-e5);
    align-items: start;
}
body.ui-v2 .ds-acta-columna-form { min-width: 0; }
body.ui-v2 .ds-acta-columna-form > .ds-pasos-nav { margin-bottom: var(--ds-e4); }
body.ui-v2 .ds-acta-columna-form > .ds-pasos-nav > .ds-pasos { gap: var(--ds-e2) var(--ds-e3); }   /* los cuatro en una línea desde 1280 */
body.ui-v2 .ds-acta-columna-form > .ds-tarjeta { margin-bottom: 0; }
body.ui-v2 .ds-acta-columna-form > .ds-pie-formulario { margin-top: var(--ds-e4); }
/* barra inferior del formulario de actas (COMÚN a adjudicación y negociación, Corrección 3 del 2026-10-01), en dos
   filas: arriba Anterior · estado del borrador · Siguiente (la navegación); abajo Descartar (a la izquierda, chico) ·
   Guardar borrador · Emitir acta (las acciones del borrador). `.ds-acta-pie-salto` parte las filas. Cabe en la
   columna del formulario desde 1280 (contenido de ~1070 px). */
body.ui-v2 .ds-acta-pie { justify-content: flex-end; padding-left: 12px; padding-right: 12px; }   /* 12 a los lados: la fila de abajo cabe a 1280 */
body.ui-v2 .ds-acta-pie > .ds-pie-formulario-texto { flex: 1 1 10em; min-width: 0; margin-right: 0; }
body.ui-v2 .ds-acta-pie > .ds-acta-pie-salto { flex-basis: 100%; height: 0; }
body.ui-v2 .ds-acta-pie > .ds-acta-pie-descartar { margin-right: auto; }
body.ui-v2 .ds-acta-columna-hoja {
    position: sticky;
    top: calc(var(--ds-alto-barra) + 24px);
    display: flex;
    flex-direction: column;
    min-width: 0;
    /* --ds-acta-alto-ventana lo pone acta_form.js (= la ventana; con zoom en la página 100vh no lo es) */
    max-height: calc(var(--ds-acta-alto-ventana, 100vh) - var(--ds-alto-barra) - 36px);
}
body.ui-v2 .ds-acta-hoja-cabeza { flex: none; display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0 var(--ds-e3); margin-bottom: var(--ds-e2); }
/* el marco es el CONTENEDOR de la hoja: la hoja y todo lo que lleva dentro se miden en partes de su ancho (cqw) */
body.ui-v2 .ds-acta-hoja-marco {
    flex: 1 1 auto;
    min-height: 0;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    container: hoja / inline-size;
    border-radius: var(--ds-radio-item);
}
body.ui-v2 .ds-acta-hoja-marco:focus-visible { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 2px; }
@container contenido (max-width: 72em) {
    body.ui-v2 .ds-acta-dos-columnas { grid-template-columns: minmax(0, 1fr); }
    body.ui-v2 .ds-acta-columna-hoja { position: static; max-height: none; }
    body.ui-v2 .ds-acta-hoja-marco { overflow: visible; }
}
/* un paso: una tarjeta que recibe el foco al abrirse; Anterior / Siguiente van en el pie fijo del formulario */
body.ui-v2 .ds-acta-paso { scroll-margin-top: calc(var(--ds-alto-barra) + 28px); }
body.ui-v2 .ds-acta-paso:focus { outline: none; }
body.ui-v2 .ds-acta-paso:focus-visible { border-color: var(--ds-acento); box-shadow: 0 0 0 1px var(--ds-acento); }
/* bloques dentro de un paso (junta, objeto) y filas de acciones */
body.ui-v2 .ds-acta-bloque { margin-top: var(--ds-e4); padding-top: var(--ds-e4); border-top: 1px solid var(--ds-borde); }
body.ui-v2 .ds-acta-bloque-cabeza { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--ds-e2) var(--ds-e3); margin-bottom: var(--ds-e2); }
body.ui-v2 .ds-acta-bloque-cabeza > .ds-rotulo { margin-bottom: 0; }
body.ui-v2 .ds-acta-subtitulo { margin: 0; color: var(--ds-texto); font-size: var(--ds-tam-cuerpo); font-weight: 600; line-height: 1.42858; }
body.ui-v2 .ds-acta-dato-linea { margin: var(--ds-e3) 0 0; color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); line-height: 1.38462; }
body.ui-v2 .ds-acta-dato-linea > span { color: var(--ds-texto); }
body.ui-v2 .ds-form-grilla.ds-acta-grilla-datos { grid-template-columns: repeat(auto-fit, minmax(9.5em, 1fr)); }
body.ui-v2 .ds-acta-acciones { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ds-e2); margin-top: var(--ds-e3); }
body.ui-v2 .ds-acta-acciones-finales { margin-top: var(--ds-e4); padding-top: var(--ds-e4); border-top: 1px solid var(--ds-borde); }
body.ui-v2 .ds-acta-pegar { margin-bottom: var(--ds-e3); }
body.ui-v2 .ds-acta-verificacion { margin-bottom: var(--ds-e3); }
body.ui-v2 .ds-acta-verificacion:empty { display: none; }
/* una línea de estado (ícono + texto): verificación con OCDS, lo que falta en Revisar */
body.ui-v2 .ds-linea-estado { display: flex; align-items: baseline; gap: 6px; margin: 0; color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); line-height: 1.38462; }
body.ui-v2 .ds-linea-estado > .ti { flex: none; align-self: center; font-size: 16px; }
body.ui-v2 .ds-linea-estado-exito > .ti { color: var(--ds-exito); }
body.ui-v2 .ds-linea-estado-aviso { color: var(--ds-aviso); }
/* Plegable chico (details/summary de UNA línea dentro de un formulario: lo poco frecuente o el detalle de un aviso):
   <details class="ds-plegable-chico"><summary><i class="ti ti-chevron-right"></i><span>Título</span></summary>…</details> */
body.ui-v2 .ds-plegable-chico { margin-top: var(--ds-e3); }
body.ui-v2 .ds-plegable-chico > summary {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: -4px;
    padding: 4px 10px 4px 4px;
    border-radius: var(--ds-radio-item);
    color: var(--ds-acento-oscuro);
    font-size: var(--ds-tam-tabla);
    font-weight: 500;
    line-height: 1.38462;
    cursor: pointer;
    list-style: none;
}
body.ui-v2 .ds-plegable-chico > summary::-webkit-details-marker { display: none; }
body.ui-v2 .ds-plegable-chico > summary::marker { content: ""; }
body.ui-v2 .ds-plegable-chico > summary:hover { background: var(--ds-hover); }
body.ui-v2 .ds-plegable-chico > summary:focus-visible { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 0; }
body.ui-v2 .ds-plegable-chico > summary > .ti { flex: none; font-size: 16px; transition: transform var(--ds-transicion); }
body.ui-v2 .ds-plegable-chico[open] > summary > .ti-chevron-right { transform: rotate(90deg); }
body.ui-v2 .ds-plegable-chico[open] > summary { margin-bottom: var(--ds-e2); }
body.ui-v2 .ds-plegable-chico.ds-plegable-aviso { margin-top: 0; }
body.ui-v2 .ds-plegable-chico.ds-plegable-aviso > summary { color: var(--ds-aviso); }
body.ui-v2 .ds-plegable-chico > .ds-lista-avisos { margin-top: 0; font-size: var(--ds-tam-tabla); line-height: 1.38462; }
/* Tabla CEÑIDA (.ds-tabla-cenida, junto a .ds-tabla-compacta y .ds-tabla-editable): la de una columna angosta de
   formulario. Menos relleno a los lados; cantidad y precio a lo justo; y la celda APILADA
   (.ds-celda-apilada): el nombre entero, partido en líneas, su segunda línea gris y los avisos debajo (a diferencia
   de .ds-celda, que recorta cada línea con "…"). */
body.ui-v2 .ds-tabla-cenida > :is(thead, tbody, tfoot) > tr > :is(th, td) { padding-left: 8px; padding-right: 8px; }
body.ui-v2 .ds-tabla-cenida > :is(thead, tbody, tfoot) > tr > :is(th, td):first-child { padding-left: 12px; }
body.ui-v2 .ds-tabla-cenida > :is(thead, tbody, tfoot) > tr > :is(th, td):last-child { padding-right: 12px; }
/* cantidad y precio: columnas a lo justo (.ds-col-ajustada); un campo de cifra mide 6em con menos relleno (caben 8
   cifras con decimales), un texto fijo, lo que pide: así el nombre se queda con el resto */
body.ui-v2 .ds-tabla-cenida.ds-tabla-editable > tbody > tr > td > input.form-control.ds-num { width: 6em; min-width: 100%; padding-left: 8px; padding-right: 8px; }
body.ui-v2 .ds-tabla-cenida.ds-tabla-editable > :is(thead, tbody, tfoot) > tr > :is(th, td).ds-col-adjudicar { width: 5.5em; }
body.ui-v2 .ds-tabla-cenida .ds-celda-acciones { width: 1%; }
/* acción escrita como enlace dentro de un texto (un <button>): «Quitar» junto al NIT, el paso al que lleva un aviso */
body.ui-v2 .ds-enlace-accion { padding: 0; border: 0; background: none; color: var(--ds-acento-oscuro); font: inherit; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
body.ui-v2 .ds-enlace-accion:hover { color: var(--ds-texto); }
body.ui-v2 .ds-enlace-accion:focus-visible { outline: 2px solid var(--ds-acento-oscuro); outline-offset: 2px; border-radius: 2px; }
body.ui-v2 .ds-tabla > tbody > tr > td.ds-celda-apilada { white-space: normal; overflow-wrap: break-word; line-height: 1.3077; }
/* piso de la columna del nombre (un bloque de alto 0, como los pisos de §23j): con campos en las otras columnas el
   nombre no se queda en dos letras por línea; si no cabe, la tabla se desplaza dentro de su marco */
body.ui-v2 .ds-tabla > tbody > tr > td.ds-celda-apilada::after { content: ""; display: block; width: 8em; height: 0; }
body.ui-v2 .ds-celda-apilada > .ds-celda-fuerte { display: block; color: var(--ds-texto); }
body.ui-v2 .ds-celda-apilada > .ds-celda-secundaria { white-space: normal; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-celda-apilada > .ds-celda-avisos { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
body.ui-v2 .ds-celda-apilada > .ds-celda-avisos:empty { display: none; }
/* un aviso largo se parte en líneas dentro de su etiqueta en vez de ensanchar la tabla */
body.ui-v2 .ds-celda-avisos > .ds-pildora { border-radius: var(--ds-radio-item); white-space: normal; text-align: left; }

/* §25r Historial ESTÁNDAR del SIAF (Noche 2 · Paso 3, 2026-10-01; templates/_historial_siaf.html,
   static/js/historial_siaf.js): diálogo amplio con la LÍNEA DE ETAPAS arriba (horizontal; se parte en filas cuando no
   cabe) y el detalle en una TablaDatos. "Contraste, no color": una etapa HECHA lleva ✓ en un círculo lleno y su fecha;
   una FUTURA, círculo con borde punteado, texto gris y la palabra "Pendiente"; una DEVUELTA, la flecha y su nota. */
body.ui-v2 .ds-hs-cabecera { min-width: 0; }
body.ui-v2 .ds-hs-cabecera .modal-title { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5em; }
body.ui-v2 .ds-hs-cabecera .ds-modal-meta { margin: 0.25em 0 0; }
body.ui-v2 .ds-hs-etapas {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10.5em, 1fr));
    gap: var(--ds-e3, 12px) var(--ds-e2, 8px);
    margin: 0 0 var(--ds-e5, 24px);
    padding: 0;
    list-style: none;
}
/* cada etapa: el punto arriba (con la raya hacia la siguiente) y el texto DEBAJO, así la raya nunca cruza el texto */
body.ui-v2 .ds-hs-etapa { position: relative; display: flex; flex-direction: column; gap: 0.35em; min-width: 0; }
body.ui-v2 .ds-hs-etapa::before {
    content: "";
    position: absolute;
    top: calc(0.75em - 1px);
    left: 1.75em;
    right: calc(-1 * var(--ds-e2, 8px) + 0.25em);
    border-top: 2px solid var(--ds-borde);
}
body.ui-v2 .ds-hs-etapa:last-child::before { display: none; }
body.ui-v2 .ds-hs-hecha::before { border-top-color: var(--ds-texto-2); }
body.ui-v2 .ds-hs-pendiente::before { border-top-style: dashed; }
body.ui-v2 .ds-hs-marca {
    position: relative;
    z-index: 1;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5em;
    height: 1.5em;
    border: 2px solid var(--ds-texto-2);
    border-radius: 50%;
    background: var(--ds-superficie);
    color: var(--ds-texto-2);
    font-size: 13px;
}
body.ui-v2 .ds-hs-marca > .ti { font-size: 0.9em; }
body.ui-v2 .ds-hs-hecha > .ds-hs-marca { border-color: var(--ds-texto); background: var(--ds-texto); color: var(--ds-superficie); }
body.ui-v2 .ds-hs-pendiente > .ds-hs-marca { border-style: dashed; border-color: var(--ds-borde-fuerte); }
body.ui-v2 .ds-hs-devuelta > .ds-hs-marca { border-color: var(--ds-aviso); color: var(--ds-aviso); }
/* en curso (Noche 2 · Paso 6: cheque de algunos proveedores del acta, no de todos): borde lleno, fondo blanco, ícono de progreso */
body.ui-v2 .ds-hs-en_curso > .ds-hs-marca { border-color: var(--ds-texto); color: var(--ds-texto); }
body.ui-v2 .ds-hs-cuerpo { min-width: 0; padding-top: 0.05em; font-size: 13px; line-height: 1.35; }
body.ui-v2 .ds-hs-titulo { color: var(--ds-texto); font-weight: 600; }
body.ui-v2 .ds-hs-pendiente .ds-hs-titulo,
body.ui-v2 .ds-hs-pendiente .ds-hs-sub { color: var(--ds-texto-2); font-weight: 400; }
body.ui-v2 .ds-hs-sub { color: var(--ds-texto); overflow-wrap: anywhere; }
body.ui-v2 .ds-hs-fecha { color: var(--ds-texto-2); font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-hs-fecha-vacia { font-style: italic; }
body.ui-v2 .ds-hs-nota { margin-top: 0.25em; color: var(--ds-aviso); font-size: var(--ds-tam-etiqueta, 12px); }
body.ui-v2 .ds-hs-lineas { margin: 0.25em 0 0; padding: 0; list-style: none; color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta, 12px); }
body.ui-v2 .ds-hs-lineas > li { overflow-wrap: anywhere; }
body.ui-v2 .ds-hs-grupo { margin-top: 0.4em; padding-left: 0.5em; border-left: 2px solid var(--ds-borde); }
body.ui-v2 .ds-hs-grupo-titulo { color: var(--ds-texto); font-size: var(--ds-tam-etiqueta, 12px); font-weight: 600; }
body.ui-v2 .ds-hs-grupo-apagado .ds-hs-grupo-titulo { color: var(--ds-texto-2); font-weight: 400; }
body.ui-v2 .ds-historial-siaf .modal-body { min-height: 12em; }
/* sugerencias del buscador de la barra superior: SIAF por número con «Ver» y «Historial» */
body.ui-v2 .ds-hs-sugerencias {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    z-index: 1050;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--ds-e2, 8px);
    border: 1px solid var(--ds-borde);
    border-radius: var(--ds-radio-tarjeta, 16px);
    background: var(--ds-superficie);
    box-shadow: var(--tb-sombra-panel);
}
body.ui-v2 .ds-hs-sugerencia { display: flex; align-items: center; justify-content: space-between; gap: 0.75em; padding: 0.25em 0.5em; font-size: 13px; }
body.ui-v2 .ds-hs-sugerencia-texto { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25em 0.6em; min-width: 0; }
body.ui-v2 .ds-hs-sugerencia-acciones { display: flex; flex: none; gap: 0.25em; }
/* sábana: el ícono FIJO de historial junto al "⋯" en cada fila; la columna de acciones suma su ancho */
body.ui-v2 :is(.ui-tabla, .ds-tabla).ds-acciones-con-historial { --ds-menu-ancho: 74px; }   /* ícono 32 + "⋯" 32 + separaciones */
/* §25s Color en lo SELECCIONADO y lo FLOTANTE (Noche 2 · Paso 4, 2026-10-01; decisión del usuario). Los módulos y
   fondos siguen en grises neutros y los íconos monocromos; el acento va SOLO en:
   - lo ACTIVO del riel (relleno #1a6fa0, ícono y texto blancos: reglas de §3);
   - lo SELECCIONADO: la fila con la casilla marcada (tinte --ds-fila-seleccionada; el hover de fila sigue gris) y
     la barra flotante de selección (relleno #1a6fa0, texto blanco, botones blancos con borde);
   - lo FLOTANTE (submenús del riel, paneles de filtro y orden, menús "⋯", popovers, diálogos —también el del
     historial—, paneles laterales, avisos flotantes y sugerencias del buscador): borde azul suave
     (--ds-flotante-borde), sombra marcada (--ds-sombra-flotante-fuerte) y, si tiene TÍTULO, una franja azul muy
     clara (--ds-flotante-franja) con el título en #1a6fa0; si no tiene título (menú "⋯", aviso flotante,
     sugerencias), una franja superior fina: el borde de arriba de 4 px. El riel del teléfono (offcanvas-md) es la
     barra lateral, no algo flotante: sigue gris. Mismas formas y medidas de siempre. */
body.ui-v2 :is(.dropdown-menu, .ds-menu, .tb-popover, .ds-menu-filtro, .popover, .ds-estado, .toast, .ds-hs-sugerencias) {
    border-color: var(--ds-flotante-borde);
    box-shadow: var(--ds-sombra-flotante-fuerte);
}
body.ui-v2 .dropdown-menu { --bs-dropdown-border-color: var(--ds-flotante-borde); --bs-dropdown-box-shadow: var(--ds-sombra-flotante-fuerte); }
body.ui-v2 .popover { --bs-popover-border-color: var(--ds-flotante-borde); --bs-popover-box-shadow: var(--ds-sombra-flotante-fuerte); }
body.ui-v2 :is(.ds-estado, .toast) { --bs-toast-border-color: var(--ds-flotante-borde); --bs-toast-box-shadow: var(--ds-sombra-flotante-fuerte); }
/* sin título: franja superior fina (el borde de arriba, de 4 px) */
body.ui-v2 :is(.dropdown-menu, .ds-menu, .ds-estado, .toast, .ds-hs-sugerencias),
body.ui-v2 .popover:not(:has(> .popover-header)),
body.ui-v2 .tb-popover:not(:has(> .tb-pop-titulo)) { border-top-width: 4px; border-top-style: solid; }
/* con título: franja azul muy clara de borde a borde con el título en el acento */
body.ui-v2 .tb-popover > .tb-pop-titulo:first-child {
    margin: -0.9231em -0.9231em 0.6154em;
    padding: 0.6923em 0.9231em;
    border-bottom: 1px solid var(--ds-flotante-borde);
    border-radius: calc(var(--ds-radio-tarjeta) - 1px) calc(var(--ds-radio-tarjeta) - 1px) 0 0;
    background: var(--ds-flotante-franja);
    color: var(--ds-flotante-titulo);
}
body.ui-v2 .tb-popover:not(.tb-panel) > .tb-pop-titulo:first-child { margin: -12px -12px 8px; padding: 9px 12px; }
body.ui-v2 .popover > .popover-header {
    padding-bottom: var(--bs-popover-header-padding-y);
    border-bottom: 1px solid var(--ds-flotante-borde);
    background: var(--ds-flotante-franja);
    color: var(--ds-flotante-titulo);
}
@media (min-width: 768px) {
    body.ui-v2:not(.ds-riel-expandido) .ds-riel-sub.abierto > .ds-riel-sub-titulo {
        margin: -8px -8px 8px;
        padding: 10px 16px;
        border-bottom: 1px solid var(--ds-flotante-borde);
        border-radius: calc(var(--ds-radio-tarjeta) - 1px) calc(var(--ds-radio-tarjeta) - 1px) 0 0;
        background: var(--ds-flotante-franja);
        color: var(--ds-flotante-titulo);
    }
    body.ui-v2:not(.ds-riel-expandido) .ds-riel-sub.abierto a.ds-riel-subitem:not(.activo):hover { background: var(--ds-hover); }
}
/* la muestra fija de /estilo §17b: el mismo submenú flotante, sin posición fija */
body.ui-v2 .ds-riel-sub.ds-riel-sub-muestra {
    display: block;
    width: 240px;
    padding: 8px;
    border: 1px solid var(--ds-flotante-borde);
    border-radius: var(--ds-radio-tarjeta);
    background: var(--ds-superficie);
    box-shadow: var(--ds-sombra-flotante-fuerte);
}
body.ui-v2 .ds-riel-sub-muestra > .ds-riel-sub-titulo {
    margin: -8px -8px 8px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--ds-flotante-borde);
    border-radius: calc(var(--ds-radio-tarjeta) - 1px) calc(var(--ds-radio-tarjeta) - 1px) 0 0;
    background: var(--ds-flotante-franja);
    color: var(--ds-flotante-titulo);
}
body.ui-v2 .ds-riel-sub-muestra .ds-riel-subitem.ds-f-hover { background: var(--ds-hover); }
/* diálogos (también UI.confirmar, el de /estilo y el del historial) y paneles laterales: encabezado con la franja */
body.ui-v2 .modal,
body.ui-v2 .ds-dialogo:not(.modal) {
    --bs-modal-border-color: var(--ds-flotante-borde);
    --bs-modal-border-width: 1px;
    --bs-modal-box-shadow: var(--ds-sombra-flotante-fuerte);
    --bs-modal-header-padding: 16px 24px 14px;
}
body.ui-v2 :is(.modal, .ds-dialogo) .modal-header {
    border-bottom: 1px solid var(--ds-flotante-borde);
    border-radius: calc(var(--ds-radio-dialogo) - 1px) calc(var(--ds-radio-dialogo) - 1px) 0 0;
    background: var(--ds-flotante-franja);
}
body.ui-v2 :is(.modal, .ds-dialogo) .modal-title,
body.ui-v2 :is(.modal, .ds-dialogo) .modal-title > .ti { color: var(--ds-flotante-titulo); }
body.ui-v2 :is(.modal, .ds-dialogo) .modal-body { padding-top: 16px; }
body.ui-v2 .ds-dialogo .modal-header { padding-top: 16px; }
body.ui-v2 .offcanvas { --bs-offcanvas-border-color: var(--ds-flotante-borde); }
body.ui-v2 .offcanvas.offcanvas-end { border: 1px solid var(--ds-flotante-borde); box-shadow: var(--ds-sombra-flotante-fuerte); }
body.ui-v2 .offcanvas-header {
    padding-bottom: 14px;
    border-bottom: 1px solid var(--ds-flotante-borde);
    background: var(--ds-flotante-franja);
}
body.ui-v2 .offcanvas-header .offcanvas-title { color: var(--ds-flotante-titulo); }
body.ui-v2 .offcanvas-body { padding-top: 16px; }
/* barra flotante de SELECCIÓN: relleno del acento, texto blanco, botones blancos con borde */
body.ui-v2 .ds-barra-seleccion-interior {
    border-color: var(--ds-seleccion-fondo);
    background: var(--ds-seleccion-fondo);
    color: var(--ds-texto-sobre-relleno);
    box-shadow: var(--ds-sombra-flotante-fuerte);
}
body.ui-v2 .ds-barra-seleccion-interior .ds-barra-seleccion-detalle { color: var(--ds-texto-sobre-relleno); }
body.ui-v2 .ds-barra-seleccion-interior .ds-barra-seleccion-sep { background: var(--ds-seleccion-separador); }
body.ui-v2 .ds-barra-seleccion-interior :is(.ds-btn, .ds-btn-icono) {
    border: 1px solid var(--ds-texto-sobre-relleno);
    background: transparent;
    color: var(--ds-texto-sobre-relleno);
}
body.ui-v2 .ds-barra-seleccion-interior .ds-btn-icono { border-color: transparent; }
body.ui-v2 .ds-barra-seleccion-interior :is(.ds-btn, .ds-btn-icono) > .ti { color: inherit; }
body.ui-v2 .ds-barra-seleccion-interior :is(.ds-btn, .ds-btn-icono):not(:disabled):hover { background: var(--ds-seleccion-hover); color: var(--ds-texto-sobre-relleno); }
body.ui-v2 .ds-barra-seleccion-interior :is(.ds-btn, .ds-btn-icono):focus-visible { outline: 2px solid var(--ds-texto-sobre-relleno); outline-offset: 2px; box-shadow: none; }
body.ui-v2 .ds-barra-seleccion-interior .ds-btn:disabled { border-color: var(--ds-seleccion-apagado); background: transparent; color: var(--ds-seleccion-apagado); opacity: 1; }
/* fila SELECCIONADA (casilla marcada): tinte del acento; al pasar, un paso más (el hover de una fila sin marcar sigue gris) */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr:has(> td > :is(.tb-sel, input.form-check-input):checked):hover > * { --bs-table-bg-state: var(--ds-fila-seleccionada-hover); }

/* Acta EN VIVO (2026-09-30): el HTML de actas_word._ConstructorHtml en la columna derecha del formulario. Hoja blanca
   con el FORMATO DEL LIBRO (acta_form.js pone las variables --ds-acta-*, en números: puntos y centímetros) que se
   ESCALA a su columna sin zoom ni transform: --ds-acta-u es lo que mide UN PUNTO del Word en esta hoja (el ancho de
   la columna entre el ancho del papel en puntos) y todo lo de adentro (letra, márgenes, tablas, firmas) se mide en
   esa unidad, así la hoja es la misma, más grande o más chica, en cualquier ancho. Aquí va calculada con unidades
   de contenedor (cqw) y acta_form.js (ajustarHoja) la fija en px medidos: WebKit, con la página alejada, resuelve
   cqw sin el zoom. Sin tope a propósito: con Safari alejado (50 %) una hoja topada al ancho real del papel dejaba
   la letra bajo 9 px de pantalla, WebKit la subía y las tablas se salían de la hoja; a todo el ancho de la columna
   la letra nunca baja de ahí. Marca de agua BORRADOR solo aquí; el Word emitido no la lleva. */
body.ui-v2 .ds-acta-previa {
    --ds-acta-u: calc(100cqw / 612);   /* Carta = 612 pt de ancho; acta_form.js pone el valor medido, con el papel del libro */
    position: relative;
    overflow: hidden;
    box-sizing: border-box;
    width: 100%;
    margin: 0 auto;
    padding: calc(var(--ds-acta-m-sup, 2.2) * 28.3465 * var(--ds-acta-u)) calc(var(--ds-acta-m-der, 2) * 28.3465 * var(--ds-acta-u))
             calc(var(--ds-acta-m-inf, 2.2) * 28.3465 * var(--ds-acta-u)) calc(var(--ds-acta-m-izq, 2) * 28.3465 * var(--ds-acta-u));
    background: var(--ds-hoja);
    color: var(--ds-hoja-tinta);
    border: 1px solid var(--ds-borde-marco);
    box-shadow: var(--ds-sombra-tarjeta);
    font-family: var(--ds-acta-fuente, Arial), Arial, Helvetica, sans-serif;
    font-size: calc(var(--ds-acta-pt, 11) * var(--ds-acta-u));
    line-height: 1.15;
}
body.ui-v2 .ds-acta-previa[aria-busy="true"] { opacity: 0.6; }
body.ui-v2 .ds-acta-previa-borrador::before {
    content: "BORRADOR";
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 6.5em;
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--ds-hoja-marca);
    transform: rotate(-30deg);
    pointer-events: none;
    z-index: 1;
}
/* secciones de la armadura (data-seccion: primero, segundo, tercero, cuarto): la del paso actual va resaltada */
body.ui-v2 .ds-acta-seccion { position: relative; scroll-margin: calc(24 * var(--ds-acta-u)) 0; transition: background-color var(--ds-transicion), box-shadow var(--ds-transicion); }
body.ui-v2 .ds-acta-seccion-actual { background: var(--ds-acento-claro); box-shadow: 0 0 0 calc(6 * var(--ds-acta-u)) var(--ds-acento-claro); }
body.ui-v2 .ds-acta-seccion-actual::before {
    content: "";
    position: absolute;
    top: calc(-6 * var(--ds-acta-u));
    bottom: calc(-6 * var(--ds-acta-u));
    left: calc(-14 * var(--ds-acta-u));
    width: calc(3 * var(--ds-acta-u));
    border-radius: calc(2 * var(--ds-acta-u));
    background: var(--ds-acento);
}
body.ui-v2 .ds-acta-parrafo { margin: 0 0 calc(3 * var(--ds-acta-u)); text-align: var(--ds-acta-alineacion, justify); }
body.ui-v2 .ds-acta-tabla { width: 100%; margin: 0 0 calc(3 * var(--ds-acta-u)); border-collapse: collapse; font-size: calc((var(--ds-acta-pt, 11) - 1) * var(--ds-acta-u)); }
body.ui-v2 .ds-acta-tabla > :is(thead, tbody) > tr > :is(th, td) { border: 1px solid var(--ds-hoja-tinta); padding: 0 calc(2.83 * var(--ds-acta-u)); vertical-align: top; text-align: left; }
body.ui-v2 .ds-acta-tabla > thead > tr > th { background: var(--ds-hoja-encabezado); text-align: center; font-weight: 700; }
body.ui-v2 .ds-acta-tabla .ds-acta-derecha { text-align: right; white-space: nowrap; }
body.ui-v2 .ds-acta-tabla .ds-acta-centro { text-align: center; }
/* tabla con anchos fijos (<col width> en %, como el Word: PRIMERO) y columnas que no se parten (SIAF, NOG) */
body.ui-v2 .ds-acta-tabla-fija { table-layout: fixed; }
body.ui-v2 .ds-acta-tabla .ds-acta-nopartir { white-space: nowrap; }
body.ui-v2 .ds-acta-firmas { display: grid; gap: 0 calc(11.3 * var(--ds-acta-u)); margin-top: calc(30 * var(--ds-acta-u)); font-size: calc(8 * var(--ds-acta-u)); text-align: center; }
body.ui-v2 .ds-acta-firmas-1 { grid-template-columns: 1fr; }
body.ui-v2 .ds-acta-firmas-2 { grid-template-columns: repeat(2, 1fr); }
body.ui-v2 .ds-acta-firmas-3 { grid-template-columns: repeat(3, 1fr); }
body.ui-v2 .ds-acta-firmas-4 { grid-template-columns: repeat(4, 1fr); }
body.ui-v2 .ds-acta-firma { break-inside: avoid; margin-top: calc(30 * var(--ds-acta-u)); }
body.ui-v2 .ds-acta-firma-linea { border-bottom: 1px solid var(--ds-hoja-tinta); margin: 0 calc(5.7 * var(--ds-acta-u)) calc(2 * var(--ds-acta-u)); }
/* §25q Acta de NEGOCIACIÓN (2026-10-01, templates/actas/form_negociacion.html, acta_negociacion_form.js): la tabla de
   precios agrupa por código en baja cuantía (fila del código y fila «Repartir con otro proveedor»), la lista de
   proveedores del acta y, en la hoja, la primera fila combinada de la tabla del SEGUNDO (SIAF · NOG). */
body.ui-v2 .ds-tabla > tbody > tr.ds-acta-fila-codigo > td { max-width: 0; background: var(--ds-encabezado-tabla); border-top: 1px solid var(--ds-borde); }
body.ui-v2 .ds-acta-fila-codigo .ds-acta-codigo-desc { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.ui-v2 .ds-tabla > tbody > tr.ds-acta-fila-repartir > td { padding-top: 0.15em; padding-bottom: 0.35em; border-top: 0; }
body.ui-v2 .ds-acta-proveedores { margin: 0; padding: 0; list-style: none; }
body.ui-v2 .ds-acta-proveedores > li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25em 0.5em; padding: 0.3em 0; border-bottom: 1px solid var(--ds-borde-suave); }
body.ui-v2 .ds-acta-proveedores > li:last-child { border-bottom: 0; }
body.ui-v2 .ds-acta-tabla > thead > tr > td.ds-acta-encima { text-align: left; font-weight: 400; }
/* §25t Fondo rotativo: cheques (Noche 2 · Paso 6, 2026-10-02; templates/fondo_rotativo/, admin/cuenta_impresion.html,
   static/js/fr_*.js). La vista del cheque y de la calibración es un <iframe> con el MISMO HTML del PDF (documento,
   con su propio estilo; se ve al 80 %); los resultados del buscador del padrón en el panel flotante del formulario. */
body.ui-v2 .ds-fr-vista { padding: var(--ds-e3); background: var(--ds-fondo); border-radius: 0 0 calc(var(--ds-radio-tarjeta) - 1px) calc(var(--ds-radio-tarjeta) - 1px); }
body.ui-v2 .ds-fr-vista > iframe { display: block; width: 100%; min-height: 19em; border: 1px solid var(--ds-borde); border-radius: var(--ds-radio-campo); background: var(--ds-superficie); }
body.ui-v2 .ds-fr-vista-calibracion > iframe { min-height: 24em; }
body.ui-v2 .ds-fr-vista-hoja > iframe { min-height: 46em; }   /* la hoja Carta completa (cheque y voucher), al 72 % */
/* Cuentas y chequeras (2026-10-06): el rango completo de la chequera y sus disponibles en UNA línea, nunca cortado
   (la columna, .ds-col-ajustada, mide lo que pide este texto) */
body.ui-v2 .ds-fr-chequera { white-space: nowrap; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-flotante-item {
    display: block;
    width: 100%;
    padding: var(--ds-e2) var(--ds-e4);
    border: 0;
    border-bottom: 1px solid var(--ds-borde-suave);
    background: var(--ds-superficie);
    color: var(--ds-texto);
    font-size: var(--ds-tam-tabla);
    line-height: 1.38462;
    text-align: left;
}
body.ui-v2 .ds-flotante-item:last-child { border-bottom: 0; }
body.ui-v2 .ds-flotante-item:hover, body.ui-v2 .ds-flotante-item:focus-visible { background: var(--ds-hover); }
body.ui-v2 .ds-flotante-vacio { margin: 0; padding: var(--ds-e4); color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-margen-arriba { margin-top: var(--ds-e3); }
body.ui-v2 .ds-fr-letras { font-weight: 500; letter-spacing: 0.01em; overflow-wrap: anywhere; }
body.ui-v2 .ds-fr-monto { max-width: 14ch; }
body.ui-v2 .ds-fr-beneficiario-fijo > .ds-campo-lectura { margin-bottom: var(--ds-e1); }
/* la cuenta («Banrural 3-033-00001-1») entera en la lista de cheques: el tope de 16ch de las columnas de contenido la
   cortaba en el número, que es justo lo que distingue una cuenta de otra */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > tbody > tr > td.ds-fr-col-cuenta .ds-celda-texto { --ds-texto-max: 22ch; }
/* 2026-10-05: con «Cobrado» la lista suma una columna; la cuenta deja el piso de «larga» (14em) —su texto entero sigue
   entrando con el tope de 26ch— y «Cobrado» (una fecha o «Sin cobrar») baja el piso de la fecha */
body.ui-v2 :is(.ui-tabla, .ds-tabla) > :is(thead, tbody) > tr > :is(th, td).ds-fr-col-cobrado { --ds-col-min: 5.5em; }
/* Cheque con el FORMATO REAL (2026-10-05): formulario por líneas (renglón → partida con su saldo en gris, concepto y
   monto), el número del cheque en GRANDE y la barra fija del pie con el TOTAL en grande y su monto en letras. */
body.ui-v2 .ds-texto-aviso { color: var(--ds-aviso); }
body.ui-v2 .ds-fr-buscar-fila { display: flex; flex-wrap: wrap; gap: var(--ds-e2); align-items: flex-start; }
body.ui-v2 .ds-fr-buscar-fila > .ds-flotante-ancla { flex: 1 1 18em; min-width: 0; }
body.ui-v2 .ds-fr-lineas { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--ds-e3); }
body.ui-v2 .ds-fr-linea { padding: var(--ds-e3) var(--ds-e4); border: 1px solid var(--ds-borde); border-radius: var(--ds-radio-campo); background: var(--ds-superficie); }
body.ui-v2 .ds-fr-linea-cabeza { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--ds-e2); }
body.ui-v2 .ds-fr-linea-numero { font-size: var(--ds-tam-etiqueta); font-weight: 600; color: var(--ds-texto-2); }
body.ui-v2 .ds-fr-linea-grilla {
    display: grid;
    grid-template-columns: minmax(12em, 1fr) minmax(16em, 1.6fr);
    gap: var(--ds-e3) var(--ds-e4);
}
body.ui-v2 .ds-fr-campo-concepto { grid-column: 1 / 2; }
body.ui-v2 .ds-fr-linea-grilla > .ds-fr-campo-concepto { grid-column: 1 / -1; }
body.ui-v2 .ds-fr-campo-monto > .ds-fr-monto { max-width: 14ch; }
body.ui-v2 .ds-fr-selector { text-align: left; min-height: var(--ds-alto-control); white-space: normal; overflow-wrap: anywhere; }
body.ui-v2 .ds-fr-selector:disabled { color: var(--ds-texto-3); }
body.ui-v2 .ds-fr-opciones { top: calc(100% + var(--ds-e1)); }
body.ui-v2 .ds-fr-opcion { display: flex; align-items: baseline; justify-content: space-between; gap: var(--ds-e3); }
body.ui-v2 .ds-fr-opcion[aria-selected="true"] { font-weight: 600; }
body.ui-v2 .ds-fr-opcion:disabled { color: var(--ds-texto-3); }
body.ui-v2 .ds-fr-saldo { flex: 0 0 auto; color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); font-variant-numeric: tabular-nums; white-space: nowrap; }
body.ui-v2 .ds-fr-lineas-pie { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ds-e3); margin-top: var(--ds-e3); }
body.ui-v2 .ds-fr-imprimir { display: flex; flex-direction: column; gap: var(--ds-e4); }
body.ui-v2 .ds-fr-numero { display: flex; flex-direction: column; align-items: flex-start; gap: var(--ds-e1); padding: var(--ds-e3) var(--ds-e4); border: 1px solid var(--ds-borde); border-radius: var(--ds-radio-campo); background: var(--ds-fondo); }
body.ui-v2 .ds-fr-numero-rotulo { font-size: var(--ds-tam-cuerpo); color: var(--ds-texto-2); }
body.ui-v2 .ds-fr-numero-grande { font-size: 2.6em; line-height: 1.1; font-weight: 700; letter-spacing: 0.06em; font-variant-numeric: tabular-nums; color: var(--ds-texto); }
body.ui-v2 .ds-fr-numero-campo { max-width: 12ch; font-size: 1.15em; letter-spacing: 0.04em; }
body.ui-v2 .ds-fr-pie { justify-content: space-between; }
body.ui-v2 .ds-fr-total { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.1em var(--ds-e3); flex: 1 1 24em; min-width: 0; }
body.ui-v2 .ds-fr-total-rotulo { font-size: var(--ds-tam-cuerpo); color: var(--ds-texto-2); }
body.ui-v2 .ds-fr-total-monto { font-size: 1.85em; line-height: 1.15; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ds-texto); }
body.ui-v2 .ds-fr-total-letras { flex-basis: 100%; font-size: var(--ds-tam-etiqueta); font-weight: 500; color: var(--ds-texto-2); overflow-wrap: anywhere; }
body.ui-v2 .ds-fr-segmentos { margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: 0.15em var(--ds-e3); font-size: var(--ds-tam-etiqueta); }
body.ui-v2 .ds-fr-segmentos dt { font-weight: 500; color: var(--ds-texto-2); }
body.ui-v2 .ds-fr-segmentos dd { margin: 0; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-fr-concepto { white-space: pre-line; }
body.ui-v2 .ds-fr-chequera-libres { font-size: var(--ds-tam-etiqueta); color: var(--ds-texto-2); overflow-wrap: anywhere; }
@media (max-width: 720px) {
    body.ui-v2 .ds-fr-linea-grilla { grid-template-columns: minmax(0, 1fr); }
}
/* §25u Fondo rotativo: AJUSTAR IMPRESIÓN (2026-10-05; templates/fondo_rotativo/ajuste.html, static/js/fr_ajuste.js).
   La hoja se dibuja a ESCALA REAL (unidades mm del navegador) con el escaneo del cheque real de fondo, semitransparente;
   el texto que se imprimirá va en el color de acento encima (para distinguirlo del escaneo) y cada ÁREA tiene su caja para elegirla
   y arrastrarla. */
body.ui-v2 .ds-fr-ajuste { display: grid; grid-template-columns: minmax(22rem, 1fr) calc(215.9mm + 2 * var(--ds-e3) + 2px); gap: var(--ds-e4); align-items: start; }   /* Paso 7 (revisión): la vista a la derecha solo desde 1400 px, con la hoja Carta ENTERA (215.9 mm) sin recortar; la tabla cede */
body.ui-v2 .ds-fr-ajuste-vista { min-width: 0; }
body.ui-v2 #tabla-ajuste th.ds-col-media { white-space: nowrap; min-width: 8.5em; }
body.ui-v2 #tabla-ajuste > :is(thead, tbody) > tr > :is(th, td) { padding-left: var(--ds-e2); padding-right: var(--ds-e2); }
body.ui-v2 .ds-fr-ajuste-cuenta { max-width: 32em; margin-bottom: var(--ds-e3); }
body.ui-v2 .ds-fr-ajuste-nombre { padding: 0; border: 0; background: none; color: var(--ds-texto); font: inherit; font-weight: 500; text-align: left; }
body.ui-v2 .ds-fr-ajuste-nombre:hover { color: var(--ds-acento-oscuro); text-decoration: underline; }
body.ui-v2 #tabla-ajuste tr.ds-fr-ajuste-elegida > * { background: var(--ds-acento-claro); }
body.ui-v2 #tabla-ajuste tr.ds-fr-ajuste-con-error .ds-fr-ajuste-nombre { color: var(--ds-error); }
body.ui-v2 #tabla-ajuste input.ds-fr-ajuste-movido { font-weight: 600; color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-fr-ajuste-marco { overflow: auto; max-height: 78vh; padding: var(--ds-e3); background: var(--ds-fondo); border-radius: 0 0 calc(var(--ds-radio-tarjeta) - 1px) calc(var(--ds-radio-tarjeta) - 1px); }
body.ui-v2 .ds-fr-ajuste-hoja { position: relative; width: 215.9mm; height: 218mm; overflow: hidden; background: var(--ds-superficie); border: 1px solid var(--ds-borde); }
body.ui-v2 .ds-fr-ajuste-escaneo { position: absolute; left: 0; top: 0; width: 215.9mm; height: 279.4mm; opacity: .42; pointer-events: none; user-select: none; }
body.ui-v2 .ds-fr-ajuste-hoja.sin-escaneo .ds-fr-ajuste-escaneo { display: none; }
body.ui-v2 .ds-fr-ajuste-textos > .t { position: absolute; margin: 0; white-space: nowrap; line-height: 1.117; font-family: Arial, Helvetica, sans-serif; color: var(--ds-acento-oscuro); pointer-events: none; }
body.ui-v2 .ds-fr-ajuste-textos > .t-negrita { font-weight: bold; }
body.ui-v2 .ds-fr-ajuste-textos > .t-derecha { text-align: right; }
body.ui-v2 .ds-fr-ajuste-textos > .t-centro { text-align: center; }
body.ui-v2 .ds-fr-ajuste-textos > .ds-fr-ajuste-mueve { color: var(--ds-acento-oscuro); }
body.ui-v2 .ds-fr-ajuste-caja { position: absolute; border: 1px dashed transparent; border-radius: 2px; cursor: grab; touch-action: none; }
body.ui-v2 .ds-fr-ajuste-caja:hover { border-color: var(--ds-acento-borde); background: var(--ds-acento-tenue); }
body.ui-v2 .ds-fr-ajuste-caja:focus-visible { outline: 2px solid var(--ds-acento); outline-offset: 1px; }
body.ui-v2 .ds-fr-ajuste-caja.elegida { border: 1.5px solid var(--ds-acento); background: var(--ds-acento-claro); }
body.ui-v2 .ds-fr-ajuste-caja.con-error { border: 1.5px solid var(--ds-error); background: var(--ds-error-tenue); }
body.ui-v2 .ds-fr-ajuste-caja.arrastrando { cursor: grabbing; }
body.ui-v2 .ds-fr-ajuste-caja > span { position: absolute; left: 0; bottom: 100%; padding: 0 0.35em; font-size: var(--ds-tam-etiqueta); line-height: 1.5; white-space: nowrap; color: var(--ds-texto-sobre-relleno); background: var(--ds-acento); border-radius: 2px 2px 0 0; display: none; }
body.ui-v2 .ds-fr-ajuste-caja.elegida > span, body.ui-v2 .ds-fr-ajuste-caja:hover > span { display: block; }
/* sin lugar para las dos lado a lado (menos de 1280 px): la vista DEBAJO de la tabla (Paso 7; antes arriba y desde 1680 px) */
@media (max-width: 1399.98px) {
    body.ui-v2 .ds-fr-ajuste { grid-template-columns: minmax(0, 1fr); }   /* angosto: la vista DEBAJO de la tabla */
}
/* §25v Fondo rotativo: A-04 SIAF «Orden para rendir fondo rotativo» (2026-10-07; templates/fondo_rotativo/a04_*.html,
   static/js/fr_a04_form.js). Cada línea del SIAF es una tarjetita como las del cheque (.ds-fr-linea): descripción a
   todo el ancho y debajo unidad, cantidad, precio, total, IVA (con sus dos atajos) y líquido; los TOTALES y la casilla
   de confirmación del IVA viven en el pie fijo (.ds-fr-pie), siempre visibles. Una línea sin cantidad va atenuada. */
body.ui-v2 .ds-a04-linea-grilla {
    display: grid; gap: var(--ds-e2) var(--ds-e3);
    grid-template-columns: minmax(8em, 1.2fr) minmax(6em, 0.7fr) minmax(8em, 0.9fr) minmax(7em, 0.8fr) minmax(12em, 1.4fr) minmax(7em, 0.8fr);
    align-items: start;
}
body.ui-v2 .ds-a04-linea-grilla > .ds-a04-campo-desc { grid-column: 1 / -1; }
body.ui-v2 .ds-a04-num { max-width: 16ch; }
body.ui-v2 .ds-a04-campo-iva .ds-a04-num { margin-bottom: var(--ds-e1); }
body.ui-v2 .ds-a04-atajos { display: flex; flex-wrap: wrap; gap: var(--ds-e1); }
body.ui-v2 .ds-a04-atajos > .ds-btn[aria-pressed="true"] { border-color: var(--ds-borde-hover); background: var(--ds-neutro-activo); }
body.ui-v2 .ds-a04-linea.ds-a04-sin-cantidad { background: var(--ds-fondo); }
body.ui-v2 .ds-a04-linea.ds-a04-sin-cantidad :is(textarea, [data-unidad], [data-precio], [data-iva], .ds-a04-atajos) { opacity: 0.6; }
body.ui-v2 .ds-a04-liquido-linea { font-weight: 600; }
body.ui-v2 .ds-a04-totales { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--ds-e1) var(--ds-e5); flex: 1 1 30em; min-width: 0; }
body.ui-v2 .ds-a04-total { white-space: nowrap; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-a04-total > strong { font-size: 1.2em; }
body.ui-v2 .ds-a04-liquido > strong { font-size: 1.6em; }
body.ui-v2 .ds-a04-confirma { flex-basis: 100%; margin: 0; display: flex; align-items: center; gap: var(--ds-e2); font-weight: 500; }
body.ui-v2 .ds-a04-confirma > .form-check-input { margin: 0; float: none; }
body.ui-v2 .ds-a04-lineas-ficha td.ds-a04-desc { white-space: pre-line; }
@media (max-width: 900px) {
    body.ui-v2 .ds-a04-linea-grilla { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

/* §25v Configuración por unidad fuera de Administración (Noche 3 · Paso 3, 2026-10-11): <fieldset disabled> sin marco para
   las pantallas de solo lectura (Actas → Configuración, Cheques → Ajustes → Firmas A-04) y la grilla de «Ajustes» de Cheques. */
body.ui-v2 .ds-fieldset-plano { border: 0; padding: 0; margin: 0; min-width: 0; }
body.ui-v2 .ds-ajustes-grilla { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); gap: var(--ds-e4); }
body.ui-v2 .ds-ajustes-grilla .ds-tarjeta { height: 100%; }
body.ui-v2 .ds-ajustes-acciones { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ds-e3); margin-top: var(--ds-e3); }
/* ---------------------------------------------------------------------------------------------------------------
   §25w Borrado definitivo seguro (Noche 3 · Paso 4, 2026-10-11): lista de la cascada, aviso de números legales y mensaje
   del formulario de confirmación (templates/borrado/). Solo tokens del sistema.
   --------------------------------------------------------------------------------------------------------------- */
body.ui-v2 .ds-borrado-lista { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--ds-e1); }
body.ui-v2 .ds-borrado-paso { display: flex; align-items: baseline; gap: var(--ds-e2); padding: 0.3em 0; border-bottom: 1px solid var(--ds-borde-suave); }
body.ui-v2 .ds-borrado-paso:last-child { border-bottom: 0; }
body.ui-v2 .ds-borrado-cantidad { min-width: 3.5em; text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ds-error); }
body.ui-v2 .ds-borrado-texto { flex: 1 1 auto; min-width: 0; }
body.ui-v2 .ds-borrado-numeros-fila { display: block; font-size: 0.9em; color: var(--ds-texto-2); }
body.ui-v2 .ds-borrado-mensaje { margin: var(--ds-e2) 0; padding: 0.6em 0.9em; border-radius: var(--ds-radio-campo); background: var(--ds-error-fondo); color: var(--ds-error); border: 1px solid var(--ds-error-borde); }
body.ui-v2 .ds-borrado-mensaje-bien { background: var(--ds-exito-fondo); color: var(--ds-exito); border-color: var(--ds-exito-borde); }


/* --- Seguridad (Noche 3 · Paso 6): códigos de recuperación y de restablecimiento, enlace y casilla del login --- */
body.ui-v2 .ds-codigos { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--ds-e2) var(--ds-e5); margin: 0 0 var(--ds-e4); padding: 0 0 0 var(--ds-e5); }
body.ui-v2 .ds-codigos li { padding: var(--ds-e1) 0; }
body.ui-v2 .ds-codigos code, body.ui-v2 .ds-codigo-grande code { font-size: 1.15em; letter-spacing: 0.06em; color: var(--ds-texto); user-select: all; }
body.ui-v2 .ds-codigo-grande { margin: 0 0 var(--ds-e4); font-size: 1.6em; }
body.ui-v2 .ds-login-recordar { margin-bottom: var(--ds-e4); }
body.ui-v2 .ds-login-enlace { margin: var(--ds-e4) 0 0; text-align: center; font-size: var(--ds-tam-cuerpo); }
@media (max-width: 575.98px) { body.ui-v2 .ds-codigos { grid-template-columns: 1fr; } }
@media print { body.ui-v2 .ds-form-acciones { display: none; } }

/* ---------------------------------------------------------------------------------------------------------------
   §25x Módulo Cheques (Noche 3 · Paso 7, 2026-10-11): separador del submenú del riel, estado y cheque en la lista de A-04
   y el AJUSTE DE IMPRESIÓN rediseñado (tabla tipo Excel). Solo tokens del sistema.
   --------------------------------------------------------------------------------------------------------------- */
body.ui-v2 .ds-riel-sub-separador { list-style: none; height: 0; margin: var(--ds-e1) var(--ds-e3); border-top: 1px solid var(--ds-borde-suave); }
body.ui-v2 .ds-fr-a04-cheque { display: block; font-size: var(--ds-tam-etiqueta); }
/* Ajuste de impresión (tabla tipo Excel): una fila de 36 px (2.57 em de 14 px), celdas numéricas con cifras tabulares */
body.ui-v2 #tabla-ajuste > :is(tbody, tfoot) > tr > :is(th, td) { height: 2.7692em; padding-top: 0; padding-bottom: 0; vertical-align: middle; }
body.ui-v2 #tabla-ajuste thead th { white-space: nowrap; }
body.ui-v2 #tabla-ajuste .ds-fr-ajuste-flecha { color: var(--ds-acento-oscuro); font-weight: 600; }
body.ui-v2 #tabla-ajuste .form-control.ds-fr-ajuste-celda { width: 4.8em; min-width: 0; min-height: 0; height: 2.3em; padding: 0 0.5em; text-align: right; font-variant-numeric: tabular-nums; }
body.ui-v2 #tabla-ajuste tr.ds-fr-ajuste-con-error > :is(th, td) { background: var(--ds-error-tenue); }
body.ui-v2 #tabla-ajuste tr.ds-fr-ajuste-con-error input.ds-fr-ajuste-celda { border-color: var(--ds-error); }
body.ui-v2 #tabla-ajuste > tfoot > tr > :is(th, td) { border-top: 2px solid var(--ds-borde); background: var(--ds-fondo); font-weight: 600; }
body.ui-v2 .ds-fr-ajuste-linea { margin: var(--ds-e2) var(--ds-e3) var(--ds-e3); font-size: var(--ds-tam-etiqueta); color: var(--ds-texto-2); }
body.ui-v2 .ds-fr-ajuste-linea-error { color: var(--ds-error); }

/* ---------------------------------------------------------------------------------------------------------------
   §25y Verificación en dos pasos (decisiones-3, 2026-10-12; templates/auth/verificar_2fa.html, activar_2fa.html,
   _qr_2fa.html, perfil_2fa.html): el QR (SVG de app/qr.py, blanco con su zona de silencio) junto a la clave para
   escribir a mano y el enlace otpauth; el campo del código en cifras grandes y separadas. Solo tokens del sistema.
   --------------------------------------------------------------------------------------------------------------- */
body.ui-v2 .ds-login-ancho .ds-login-tarjeta { max-width: 36em; }
body.ui-v2 .ds-qr-2fa { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ds-e4); margin: 0 0 var(--ds-e5); }
body.ui-v2 .ds-qr-imagen { flex: none; margin: 0; padding: var(--ds-e2); background: var(--ds-superficie); border: 1px solid var(--ds-borde); border-radius: var(--ds-radio-campo); line-height: 0; }
body.ui-v2 .ds-qr-imagen svg { display: block; width: 14.5em; height: auto; max-width: 100%; }
body.ui-v2 .ds-qr-datos { flex: 1 1 14em; min-width: 0; }
body.ui-v2 .ds-qr-rotulo { display: block; margin: 0 0 var(--ds-e1); color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); line-height: 1.33; }
body.ui-v2 .ds-qr-clave { margin: 0 0 var(--ds-e3); }
body.ui-v2 .ds-qr-clave code { color: var(--ds-texto); font-size: 1.05em; letter-spacing: 0.08em; word-spacing: 0.2em; user-select: all; overflow-wrap: anywhere; }
body.ui-v2 .form-control.ds-qr-uri { font-size: var(--ds-tam-etiqueta); color: var(--ds-texto-2); }
body.ui-v2 .form-control.ds-codigo-2fa { max-width: 9.5em; font-size: 1.3em; letter-spacing: 0.3em; text-align: center; font-variant-numeric: tabular-nums; }
body.ui-v2 .ds-2fa-recuperacion { margin: var(--ds-e4) 0 0; }
body.ui-v2 .ds-2fa-recuperacion form { margin-top: var(--ds-e3); }
/* Activación en TRES pasos y dispositivos de confianza (2026-10-13; auth/_activar_2fa_pasos.html, _codigos_repuesto.html,
   _casilla_confiar.html, perfil_dispositivos.html; static/js/activar_2fa.js). El QR arriba y la clave PLEGADA debajo; los
   pasos 1 y 2 en la misma página (el JS esconde el que no toca con `hidden`); en la tarjeta del inicio de sesión los botones
   de un paso van en una fila. Al imprimir el paso 3 solo sale la tarjeta de los códigos. */
body.ui-v2 .ds-2fa-pasos > .ds-pasos, body.ui-v2 .ds-2fa-codigos > .ds-pasos { margin: 0 0 var(--ds-e5); }
body.ui-v2 .ds-2fa-paso-titulo { margin: 0 0 var(--ds-e1); color: var(--ds-texto); font-size: 16px; font-weight: 600; line-height: 1.5; }
body.ui-v2 .ds-2fa-linea { margin: 0 0 var(--ds-e4); color: var(--ds-texto-2); font-size: var(--ds-tam-cuerpo); line-height: 1.42858; }
body.ui-v2 .ds-2fa-paso + .ds-2fa-paso { margin-top: var(--ds-e5); }
body.ui-v2 .ds-2fa-con-js .ds-2fa-paso + .ds-2fa-paso { margin-top: 0; }
body.ui-v2 .ds-qr-2fa { flex-direction: column; align-items: stretch; gap: var(--ds-e3); }
body.ui-v2 .ds-qr-imagen { align-self: center; }
body.ui-v2 .ds-qr-2fa > .ds-qr-datos { flex: 0 0 auto; }   /* en columna, el `flex-basis: 14em` de antes sería ALTO: dejaba un hueco bajo el plegable cerrado */
body.ui-v2 .ds-qr-2fa > .ds-plegable-chico { margin-top: 0; }
body.ui-v2 .ds-qr-2fa > .ds-plegable-chico[open] { padding-bottom: var(--ds-e2); }
body.ui-v2 .ds-2fa-acciones { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ds-e2); }
body.ui-v2 .ds-login-tarjeta .ds-2fa-acciones .ds-btn { width: auto; flex: 1 1 0; }
body.ui-v2 .ds-2fa-confiar { margin: 0 0 var(--ds-e4); }
body.ui-v2 .ds-2fa-confiar .form-check-label { font-size: var(--ds-tam-cuerpo); }
body.ui-v2 .ds-2fa-confiar .ds-ayuda-texto { margin: var(--ds-e1) 0 0; }
body.ui-v2 .ds-codigos-encabezado { margin: 0 0 var(--ds-e2); color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); line-height: 1.33; }
body.ui-v2 .ds-codigos-acciones { margin-top: 0; }
body.ui-v2 .ds-codigos-guardados { margin: var(--ds-e4) 0 0; }
body.ui-v2 .ds-codigos-guardados .form-check-label { font-size: var(--ds-tam-cuerpo); }
@media print {
    body.ui-v2.ds-imprime-codigos * { visibility: hidden; }
    body.ui-v2.ds-imprime-codigos .ds-codigos-tarjeta, body.ui-v2.ds-imprime-codigos .ds-codigos-tarjeta * { visibility: visible; }
    body.ui-v2.ds-imprime-codigos .ds-codigos-tarjeta { position: fixed; left: 0; top: 0; width: 100%; padding: 1.5cm; background: var(--ds-superficie); }
    body.ui-v2.ds-imprime-codigos .ds-codigos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}


/* ==========================================================================
   Reportería estándar (Noche 4 · Paso 2; docs/reglas/reporteria.md): botón «Reporte ▾» de las listas
   ========================================================================== */
body.ui-v2 .ds-reporte { display: inline-flex; }
body.ui-v2 .ds-reporte .ds-reporte-flecha { font-size: 0.85em; margin-left: calc(-1 * var(--ds-e1)); }
body.ui-v2 .ds-reporte-menu { min-width: 15rem; }
body.ui-v2 .ds-reporte-todo { display: flex; align-items: center; gap: var(--ds-e2); margin: 0; padding: var(--ds-e1) var(--ds-e3);
    color: var(--ds-texto-2); font-size: var(--ds-tam-etiqueta); cursor: pointer; white-space: nowrap; }
body.ui-v2 .ds-reporte-todo .form-check-input { margin: 0; }
body.ui-v2 .ds-reporte-generando > .ds-btn { cursor: progress; }

/* Ventana por defecto de las listas grandes (Noche 4 · Paso 3c) */
body.ui-v2 .ds-ventana { display: flex; align-items: center; gap: var(--ds-e1); margin: 0 0 var(--ds-e2); color: var(--ds-texto-2);
    font-size: var(--ds-tam-etiqueta); }
body.ui-v2 .ds-ventana a { margin-left: var(--ds-e1); }

/* Ficha del SIAF sin el A-01 incrustado (2026-10-18, regla única de los PDF): la tarjeta con el botón ocupa lo justo */
body.ui-v2 .ds-ficha-visor.ds-ficha-pdf { height: auto; min-height: 0; }


/* 26. Trabajos en segundo plano (2026-10-18; static/js/trabajos.js) ========== */
/* Aviso flotante ABAJO A LA IZQUIERDA (junto al riel): los avisos de UI.estado
   van a la derecha y no se tapan. Cada trabajo es una tarjeta .ds-estado. */
body.ui-v2 .ds-trabajos {
    position: fixed;
    left: calc(var(--ds-ancho-riel) + 24px);
    bottom: 24px;
    z-index: 1085;
    display: flex;
    flex-direction: column;
    gap: var(--ds-e2);
    max-width: min(380px, calc(100vw - 32px));
    pointer-events: none;
}
body.ui-v2 .ds-trabajos[hidden] { display: none; }
body.ui-v2 .ds-trabajo { min-width: 260px; max-width: 380px; align-items: flex-start; }
body.ui-v2 .ds-trabajo .ds-estado-texto { display: flex; flex-direction: column; gap: 2px; }
body.ui-v2 .ds-trabajo-titulo { font-weight: 600; }
body.ui-v2 .ds-trabajo-linea { color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-trabajo-aviso { color: var(--ds-aviso); }
body.ui-v2 .ds-trabajo-descargar { align-self: flex-start; margin-top: var(--ds-e2); }
body.ui-v2 .ds-trabajo-enlace { font-size: var(--ds-tam-tabla); }
body.ui-v2 .ds-trabajo .ds-estado-icono .spinner-border { width: 16px; height: 16px; border-width: 2px; }
@media (max-width: 767.98px) {
    body.ui-v2 .ds-trabajos { left: 16px; right: 16px; bottom: auto; top: 64px; max-width: none; }
    body.ui-v2 .ds-trabajo { min-width: 0; max-width: none; }
}
@media print { body.ui-v2 .ds-trabajos { display: none; } }

/* §24i-H · Inicio de sesión (Noche 5 · 1, 2026-10-21). Dos columnas: panel izquierdo azul marino y, a la derecha, el
   formulario con campos de 48 px y esquinas de 12 px, con entrada escalonada. Por debajo de 900 px el panel se oculta
   y la marca va sobre el formulario. Respeta prefers-reduced-motion.
   §24i-C · Panel «Cumbre» (2026-10-23): logo (40 px) y nombre arriba a la izquierda; centrada en el panel COMPLETO, una
   «K» de tres barras (42 %, 70 % y 100 % de 360 px) que crecen escalonadas (scaleY, 0.8 s), ya crecidas se inclinan
   juntas (skewX 0 → −24°, 1.9 s, rectas el primer 45 %), siguen lo que se escribe (--avance, static/js/login.js) y, con
   los dos campos llenos, la corinto brilla. El mouse sobre el panel suma ±5° de inclinación (capa «giro»). */
body.ui-v2.ds-login-h .ds-login-dos {
    flex-direction: row;
    align-items: stretch;
    justify-content: flex-start;
    padding: 0;
}
body.ui-v2.ds-login-h .ds-login-panel {
    position: relative;
    display: flex;
    flex: 0 0 clamp(420px, 46vw, 600px);
    flex-direction: column;
    justify-content: flex-start;
    width: clamp(420px, 46vw, 600px);
    min-height: 100vh;
    padding: 48px 56px;
    overflow: hidden;
    background: var(--ds-login-fondo);
    color: var(--ds-blanco);
}
body.ui-v2.ds-login-h .ds-login-panel-marca { position: relative; z-index: 1; display: flex; align-items: center; gap: 14px; font-size: 20px; letter-spacing: -0.02em; }
body.ui-v2.ds-login-h .ds-login-panel-marca b { font-weight: 700; }
body.ui-v2.ds-login-h .ds-login-logo { flex: none; width: 40px; height: 40px; object-fit: contain; }   /* logo_sistema_oscuro.svg sobre el azul marino */
body.ui-v2.ds-login-h .ds-login-cumbre {
    --avance: 0.5;
    position: absolute;
    top: 50%;
    left: 50%;
    width: 300px;
    height: 360px;
    transform: translate(-50%, -50%);
    pointer-events: none;
}
body.ui-v2.ds-login-h .ds-login-cumbre-giro,
body.ui-v2.ds-login-h .ds-login-cumbre-centra,
body.ui-v2.ds-login-h .ds-login-cumbre-inclina { width: 100%; height: 100%; transform-origin: bottom; }
body.ui-v2.ds-login-h .ds-login-cumbre-giro { transition: transform 0.35s ease-out; }
/* skewX(−24°) desde la base corre la punta tan 24° × 360 px × avance ≈ 160 px × avance a la derecha: «centra» corre la K
   la mitad de eso a la izquierda (al inclinarse y al cambiar de altura) para que quede al centro y no se salga del panel */
body.ui-v2.ds-login-h .ds-login-cumbre-centra {
    transform: translateX(calc(var(--avance) * -80px));
    transition: transform 0.55s cubic-bezier(0.3, 0.8, 0.2, 1);
    animation: ds-cumbre-centra 1.9s cubic-bezier(0.2, 0.8, 0.2, 1) backwards;
}
body.ui-v2.ds-login-h .ds-login-cumbre-inclina {
    display: flex;
    align-items: flex-end;
    gap: 24px;
    animation: ds-cumbre-inclina 1.9s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
body.ui-v2.ds-login-h .ds-login-cumbre-crece {
    display: flex;
    flex: 1 1 0;
    align-items: flex-end;
    height: 100%;
    transform-origin: bottom;
    animation: ds-cumbre-crece 0.8s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
body.ui-v2.ds-login-h .ds-login-cumbre-crece:nth-child(2) { animation-delay: 0.12s; }
body.ui-v2.ds-login-h .ds-login-cumbre-crece:nth-child(3) { animation-delay: 0.24s; }
body.ui-v2.ds-login-h .ds-login-cumbre-barra {
    display: block;
    width: 100%;
    height: calc(var(--alto) * var(--avance));
    border-radius: 6px;
    background: var(--ds-login-cumbre-1);
    transition: height 0.55s cubic-bezier(0.3, 0.8, 0.2, 1);
}
body.ui-v2.ds-login-h .ds-login-cumbre-crece:nth-child(1) .ds-login-cumbre-barra { --alto: 42%; }
body.ui-v2.ds-login-h .ds-login-cumbre-crece:nth-child(2) .ds-login-cumbre-barra { --alto: 70%; background: var(--ds-login-cumbre-2); }
body.ui-v2.ds-login-h .ds-login-cumbre-crece:nth-child(3) .ds-login-cumbre-barra { --alto: 100%; background: var(--ds-login-cumbre-3); }
body.ui-v2.ds-login-h .ds-login-cumbre-llena .ds-login-cumbre-crece:nth-child(3) .ds-login-cumbre-barra {
    animation: ds-cumbre-brillo 1.8s ease-in-out infinite;
}
@keyframes ds-cumbre-crece { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes ds-cumbre-inclina { 0%, 45% { transform: skewX(0deg); } 100% { transform: skewX(-24deg); } }
@keyframes ds-cumbre-centra { 0%, 45% { transform: translateX(0); } 100% { transform: translateX(calc(var(--avance) * -80px)); } }
@keyframes ds-cumbre-brillo {
    0%, 100% { box-shadow: 0 0 18px var(--ds-login-cumbre-brillo-suave); }
    50% { box-shadow: 0 0 38px var(--ds-login-cumbre-brillo-fuerte); }
}
body.ui-v2.ds-login-h .ds-login-formulario {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: var(--ds-e6) var(--ds-e4);
}
body.ui-v2.ds-login-h .ds-login-marca-chica { display: none; }
body.ui-v2.ds-login-h .ds-login-tarjeta { max-width: 420px; border-radius: 16px; }
body.ui-v2.ds-login-h .ds-login-control { min-height: 48px; border-radius: 12px; padding-left: 14px; padding-right: 14px; }
body.ui-v2.ds-login-h .ds-login-clave { position: relative; }
body.ui-v2.ds-login-h .ds-login-clave .ds-login-control { padding-right: 48px; }
body.ui-v2.ds-login-h .ds-login-ojo {
    position: absolute;
    top: 0;
    right: 0;
    width: 48px;
    height: 48px;
    border: 0;
    background: transparent;
    color: var(--ds-texto-2);
    font-size: 20px;
    border-radius: 12px;
    cursor: pointer;
}
body.ui-v2.ds-login-h .ds-login-ojo:hover, body.ui-v2.ds-login-h .ds-login-ojo:focus-visible { color: var(--ds-texto); outline: 2px solid var(--ds-foco, var(--ds-login-barra-viva)); outline-offset: -2px; }
body.ui-v2.ds-login-h .ds-login-tarjeta .ds-btn { min-height: 48px; border-radius: 12px; }
body.ui-v2.ds-login-h .ds-login-paso { opacity: 0; translate: 0 8px; animation: ds-login-paso-entra 360ms ease forwards; }
body.ui-v2.ds-login-h .ds-login-paso:nth-of-type(1) { animation-delay: 120ms; }
body.ui-v2.ds-login-h .ds-login-paso:nth-of-type(2) { animation-delay: 200ms; }
body.ui-v2.ds-login-h .ds-login-paso:nth-of-type(3) { animation-delay: 280ms; }
body.ui-v2.ds-login-h .ds-login-paso:nth-of-type(4) { animation-delay: 360ms; }
body.ui-v2.ds-login-h .ds-login-enlace.ds-login-paso { animation-delay: 440ms; }
@keyframes ds-login-paso-entra { to { opacity: 1; translate: 0 0; } }
/* panel angosto (420…552 px): la K al 75 % para que, inclinada, quepa */
@media (max-width: 1199.98px) {
    body.ui-v2.ds-login-h .ds-login-cumbre { transform: translate(-50%, -50%) scale(0.75); }
}
@media (max-width: 899.98px) {
    body.ui-v2.ds-login-h .ds-login-panel { display: none; }
    body.ui-v2.ds-login-h .ds-login-marca-chica { display: flex; }
}
/* sin movimiento: la K aparece ya inclinada a su altura, sin transiciones ni brillo que palpite */
@media (prefers-reduced-motion: reduce) {
    body.ui-v2.ds-login-h .ds-login-cumbre-crece { animation: none; transform: none; }
    body.ui-v2.ds-login-h .ds-login-cumbre-inclina { animation: none; transform: skewX(-24deg); }
    body.ui-v2.ds-login-h .ds-login-cumbre-centra { animation: none; transition: none; }
    body.ui-v2.ds-login-h .ds-login-cumbre-giro { transition: none; }
    body.ui-v2.ds-login-h .ds-login-cumbre-barra { transition: none; }
    body.ui-v2.ds-login-h .ds-login-cumbre-llena .ds-login-cumbre-crece:nth-child(3) .ds-login-cumbre-barra {
        animation: none;
        box-shadow: 0 0 28px var(--ds-login-cumbre-brillo-fuerte);
    }
    body.ui-v2.ds-login-h .ds-login-paso { animation: none; opacity: 1; translate: 0; }
}

/* Noche 5 · 6 · Compras: «Filtros ▾» plegable de la barra (tabla.js barra.plegable) y el panel «Trámite del SIAF» */
body.ui-v2 .tb-plegable { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; flex-basis: 100%; }
body.ui-v2 .tb-plegable[hidden] { display: none; }
body.ui-v2 .tb-plegar-n { min-width: 18px; padding: 0 5px; border-radius: 9px; background: var(--ds-acento); color: var(--ds-blanco); font-size: 11px; line-height: 18px; text-align: center; }
body.ui-v2 .tb-plegar-n[hidden] { display: none; }
body.ui-v2 :is(.ui-tabla, .ds-tabla).cs-tabla-tramite { --ds-accion-ancho: 10.5em; }   /* «Pago y modalidad», el paso más largo */
body.ui-v2 .cs-tabla-tramite tbody tr[data-cs-fila] { cursor: pointer; }
body.ui-v2 .cs-tabla-tramite tbody tr[data-cs-fila]:focus-visible { outline: 2px solid var(--ds-acento); outline-offset: -2px; }
body.ui-v2 .cs-panel-cabeza { display: grid; gap: 4px; padding-bottom: var(--ds-e3); margin-bottom: var(--ds-e3); border-bottom: 1px solid var(--ds-borde); }
body.ui-v2 .cs-panel-cabeza .ds-acciones-fila { margin-top: 4px; }
body.ui-v2 .cs-pasos { list-style: none; margin: 0; padding: 0; counter-reset: paso; display: grid; gap: var(--ds-e3); }
body.ui-v2 .cs-paso { display: grid; grid-template-columns: 28px 1fr; gap: 10px; }
body.ui-v2 .cs-paso-num { counter-increment: paso; width: 28px; height: 28px; border-radius: 50%; border: 1.5px solid var(--ds-borde-fuerte); color: var(--ds-texto-2); font-size: 12px; font-weight: 600; line-height: 25px; text-align: center; }
body.ui-v2 .cs-paso-num::before { content: counter(paso); }
body.ui-v2 .cs-paso-hecho .cs-paso-num { background: var(--ds-exito); border-color: var(--ds-exito); color: var(--ds-blanco); }
body.ui-v2 .cs-paso-hecho .cs-paso-num::before { content: "✓"; }
body.ui-v2 .cs-paso-actual .cs-paso-num { border-color: var(--ds-acento); color: var(--ds-acento-oscuro); }
body.ui-v2 .cs-paso-titulo { margin: 3px 0 2px; font-weight: 600; }
body.ui-v2 .cs-paso-texto { color: var(--ds-texto-2); font-size: var(--ds-tam-tabla); }
body.ui-v2 .cs-paso-lista { margin: 4px 0 0; padding: 0; list-style: none; display: grid; gap: 4px; font-size: var(--ds-tam-tabla); }
body.ui-v2 .cs-paso-lista li { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
body.ui-v2 .cs-paso-acciones { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
body.ui-v2 .cs-paso-form { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 6px; }
body.ui-v2 .cs-paso-form .ds-campo { margin: 0; }
body.ui-v2 .cs-panel-mas { margin-top: var(--ds-e4); padding-top: var(--ds-e3); border-top: 1px solid var(--ds-borde); display: flex; flex-wrap: wrap; gap: 6px; }
body.ui-v2 .cs-panel .ds-popover-detalle { margin-top: 4px; }

/* §24k · Franja de entorno («BETA · datos de prueba», 2026-10-24; templates/_franja_entorno.html, IGSS_AVISO_ENTORNO).
   Es el PRIMER elemento del body y se queda pegada arriba; el body lleva ds-con-franja para que el riel, la barra y las
   páginas de alto completo le dejen sus 26 px. Solo tokens (fondo de error y texto blanco). Sin franja, nada cambia. */
body.ui-v2 { --ds-franja-alto: 0px; }
body.ui-v2.ds-con-franja { --ds-franja-alto: 26px; }
body.ui-v2 .ds-franja-entorno {
    position: sticky;
    top: 0;
    z-index: 2000;
    height: var(--ds-franja-alto);
    padding: 0 12px;
    line-height: var(--ds-franja-alto);
    text-align: center;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    background: var(--ds-error);
    color: var(--ds-blanco);
}
body.ui-v2.ds-con-franja .ds-riel { top: var(--ds-franja-alto); height: calc(100vh - var(--ds-franja-alto)); }
body.ui-v2.ds-con-franja .ds-barra { top: calc(var(--ds-e2) + var(--ds-franja-alto)); }
body.ui-v2.ds-con-franja .ds-app,
body.ui-v2.ds-con-franja.ds-pagina-sola,
body.ui-v2.ds-con-franja .ds-login-panel,
body.ui-v2.ds-con-franja .ds-login-tarjeta { min-height: calc(100vh - var(--ds-franja-alto)); }
