/*
 * Tokens del design system "Executive Precision".
 * Fuente: docs/06-design-system.md, norma única y vigente. Los VALORES DE COLOR
 * vienen, desde la tanda A de la v3, del frontmatter de docs/06-design-system3-stitch.md
 * ("Executive Precision Vibrant"). Manda el frontmatter y no la prosa de ese documento: los
 * dos se contradicen y el frontmatter es lo que Stitch compiló a las maquetas aprobadas
 * (docs/06-design-system.md §10.2).
 *
 * Se declaran aquí una vez y NUNCA se repite un hexadecimal suelto en un componente:
 * cambiar la marca tiene que ser tocar este fichero.
 *
 * TANDA A (v3): SOLO cambian valores de color. Ni un nombre de variable, ni la tipografía
 * (tanda B), ni la escala de espaciado (--space-*, que lee gantt.js). La familia `tertiary`
 * del frontmatter de Stitch (#311fca y derivados) NO se declara: decisión del usuario,
 * §8.3 del design system — el azul sigue siendo lo único saturado de la interfaz.
 *
 * ESTADO (tanda 84, cierre del bloque de migración): ESTE FICHERO YA NO TIENE BLOQUE HEREDADO.
 * Los alias v1 de espaciado (--space-xs..--space-3xl) y de sombra (--shadow-sm/--shadow-md) se
 * han retirado, y las escalas de radio y de altura de control se han alineado con el
 * frontmatter de la v2. Lo que queda declarado aquí ES la escala, sin sinónimos.
 *
 * LO ÚNICO QUE SE LEE DESDE JAVASCRIPT, y por tanto lo único que no puede renombrarse sin
 * tocar un .js en el mismo turno:
 *   - gantt.js  -> --space-2 (cssPx, dos veces, sangrado por profundidad del árbol). Hasta esta
 *                  tanda leía --space-sm; se ha cambiado a la vez que se retiraba el alias,
 *                  porque separarlo habría dejado el Gantt en su valor de reserva SIN FALLAR
 *                  el build ni los tests.
 *   - charts.js -> diez tokens de COLOR (--secondary-container, --on-surface,
 *                  --surface-container-high y los cinco --status-*). En la tanda A de la v3
 *                  cambian de VALOR, nunca de nombre, así que charts.js NO se toca. Sus
 *                  hexadecimales de reserva quedan desactualizados a propósito: solo se
 *                  usarían si el token desapareciera de esta hoja.
 */

:root {
    /* Superficies */
    --surface: #f8f9ff;
    --surface-dim: #cbdbf5;
    --surface-container-lowest: #ffffff;
    --surface-container-low: #eff4ff;
    --surface-container: #e5eeff;
    --surface-container-high: #dce9ff;
    --surface-container-highest: #d3e4fe;

    /* Texto */
    --on-surface: #0b1c30;
    --on-surface-variant: #434655;
    --inverse-surface: #213145;
    --inverse-on-surface: #eaf1ff;

    /* Trazos */
    --outline: #747686;
    --outline-variant: #c4c5d7;

    /* Marca.
       Historia de --primary: #000000 (v1) -> #0f172a (v2, tanda 72) -> #0037b0 (v3, tanda A).
       Este último es EL cambio de carácter de la v3: la marca deja de ser un casi-negro y pasa
       a ser azul. Revertirlo es esta línea.
       --primary solo se usa como TINTA sobre superficie clara (enlace en hover, pestaña activa,
       icono): 9,6:1 sobre --surface, de sobra.
       --primary-container SÍ se usa como fondo con --on-primary (blanco) encima —avatar de la
       topbar, idioma activo, barra de fase del Gantt— y con #1d4ed8 da 6,6:1.
       ATENCIÓN: --primary-container está duplicado en C# en Documents/BoardPackColors.cs para
       el PDF del board pack, que no puede leer esta hoja. Se ha actualizado en el mismo commit;
       si vuelve a cambiar aquí, cambia allí o el PDF se queda con la marca vieja. */
    --primary: #0037b0;
    --on-primary: #ffffff;
    --primary-container: #1d4ed8;
    --on-primary-container: #cad3ff;

    /* Acción. El azul es lo único saturado de la interfaz: marca dónde se pulsa.
       DESVIACIÓN DELIBERADA del frontmatter de Stitch, la única de la tanda A: allí
       --secondary-container es #5bb8fe, un azul claro pensado para llevar
       --on-secondary-container (#00476e) encima. Aquí ese token se usa como FONDO DE HOVER de
       lo pulsable, siempre con --on-secondary (blanco): .button--primary:hover,
       .sidebar__cta:hover y el botón "siguiente" del tutorial. Blanco sobre #5bb8fe da 2,1:1 y
       el botón principal se habría vuelto ilegible al pasar el ratón. #0a76b4 es un escalón
       más claro de --secondary (#006398) dentro de la misma familia y mantiene 4,9:1.
       Si algún día se adopta el valor literal de Stitch, hay que cambiar antes esos tres
       consumidores a --on-secondary-container, que hoy no existe. */
    --secondary: #006398;
    --on-secondary: #ffffff;
    --secondary-container: #0a76b4;
    --secondary-fixed: #cce5ff;
    --secondary-fixed-dim: #93ccff;
    --on-secondary-fixed: #001d31;

    /* Error */
    --error: #ba1a1a;
    --on-error: #ffffff;
    --error-container: #ffdad6;
    --on-error-container: #93000a;

    /*
     * Semáforo de estado. No viene del design system: son los cinco estados canónicos de
     * RF-14 y necesitan color propio, porque es lo primero que lee la junta. Por eso la tanda A
     * de la v3 NO los ha tocado: son semántica de producto, no marca. Se revisó su contraste
     * contra las superficies nuevas (--surface #f8f9ff, --surface-container-low #eff4ff) y
     * ninguno baja de 4,5:1, así que no había motivo para moverlos.
     */
    --status-pending: #76777d;
    --status-progress: #2170e4;
    --status-blocked: #ba1a1a;
    --status-review: #b26a00;
    --status-done: #1b6b3a;

    /*
     * Semáforo de juicio humano (RF-33): tres colores, no cinco — es una escala distinta de
     * la de arriba, no un sinónimo. Alcance/plazo/coste/calidad/riesgo se puntúan en
     * verde/ámbar/rojo, nunca en los cinco estados canónicos de una tarea. Vienen de la maqueta
     * de junta de la tanda 1 (.dot-green/.dot-amber/.dot-red), hoy en docs/design-refs/, y los
     * reutiliza el generador del board pack (Documents/BoardPackColors.cs en la AdminApp, que no
     * puede leer esta hoja porque QuestPDF no ejecuta CSS: es una de las superficies de
     * docs/06-design-system.md §12).
     */
    --traffic-green: #0f7a45;
    --traffic-amber: #b45309;
    /* --traffic-red se declara más abajo, en el bloque v2, con su propio nombre y el mismo
       valor que --error: son dos conceptos distintos y conviene poder escribir el que se
       quiere decir. */

    /* --- Tipografía (tanda B de la v3) -------------------------------------------------
     * Familia de "Executive Precision Vibrant": Plus Jakarta Sans para texto Y para etiquetas.
     * Ese sistema usa una sola familia; el par Inter/Geist de la v2 existía para distinguir
     * texto de etiqueta, y esa distinción la sigue marcando el peso (550/600 en --text-label y
     * --text-overline), no la familia. --font-label se conserva como variable porque dos tokens
     * la consumen y porque deja la puerta abierta a volver a separarlas.
     *
     * SE ADOPTA LA FAMILIA, NO LA ESCALA: los tamaños de Stitch (cuerpo 13px, etiqueta 11px, un
     * nivel de 10px) reintroducirían el defecto por el que existió la v2, donde 11px era el
     * tamaño más usado de toda la aplicación. El suelo de contenido sigue en 14px.
     *
     * --font-mono NO se toca: Plus Jakarta Sans no tiene variante monoespaciada y hay columnas
     * de código WBS e importe que dependen de que las cifras alineen. */
    --font-sans: "Plus Jakarta Sans", "Segoe UI", system-ui, -apple-system, sans-serif;
    --font-label: "Plus Jakarta Sans", "Segoe UI", system-ui, -apple-system, sans-serif;
    --font-mono: "Geist Mono", "Cascadia Mono", Consolas, monospace;

    /*
     * Espaciado, radios, sombras y alturas de control viven ahora en el bloque v2 de más abajo,
     * que es la única escala del producto. Aquí arriba solo quedan color, tipografía y las
     * medidas de chasis que no son escala (ancho de sidebar, alto de topbar).
     */

    /* 288px desde la Tanda C de la v3: con los rótulos de grupo y trece destinos, 256 apretaba. */
    --sidebar-width: 288px;
    /*
     * Carril de solo iconos cuando el sidebar está colapsado (encargo puntual, demo).
     * No sale de la escala de espaciado porque --sidebar-width tampoco lo hace: es un ancho
     * de componente, no un hueco entre elementos. 72px deja sitio de sobra al icono de 20px
     * más un margen visible a cada lado dentro del padding reducido que aplica layout.css
     * cuando el sidebar lleva la clase de colapsado.
     */
    --sidebar-width-collapsed: 72px;
    --topbar-height: 64px;

    /*
     * Marca de producto (OmmiFX). Medidas de chasis, no escala: el lockup y el isotipo son
     * ficheros SVG con proporción fija (224x64 y 64x64), así que lo único que se fija es su
     * altura y el ancho sale solo. Viven aquí y no en brand.css por el mismo motivo que
     * --sidebar-width: es una medida del armazón que varias hojas necesitan citar.
     *
     * 32px iguala la altura del cuadrado de marca del carril y deja el lockup en ~112px de
     * ancho, que entra de sobra en el sidebar de 288px. La OnePage usa 30px para el mismo
     * lockup: es la misma lectura óptica, no un tamaño distinto.
     */
    --brand-lockup-height: 32px;
    --brand-mark-size: 32px;
    /*
     * Un escalón más en las dos superficies previas a la aplicación —acceso y error—, donde la
     * marca no es un elemento de chasis compitiendo con veinte destinos, sino lo único que hay
     * que mirar. Es el tamaño que ya tenía .auth__brand antes de existir estos tokens.
     */
    --brand-lockup-height-lg: 40px;

    /*
     * Marca del TENANT en la cabecera del carril, JUNTO a su nombre y no en su lugar.
     *
     * Aquí el fichero lo sube el cliente y su proporción es desconocida: puede ser un cuadrado
     * de 200x200 (el caso real con el que se probó) y puede ser un lockup de 6:1 que ya lleve
     * el nombre dibujado dentro. El servidor no puede distinguirlos —no sabe si la imagen
     * contiene texto—, así que la cabecera tiene que aguantar los dos sin preguntarlo.
     *
     * Por eso no hay un tamaño: hay dos topes y un mínimo.
     *
     *   --mark-height     tope de altura. Con `width`/`height` en auto, el navegador conserva
     *                     la proporción y manda el tope que se alcance primero. 40px es
     *                     --control-md y la altura que ya usa el lockup del producto en las
     *                     superficies previas a la aplicación: a 32px un logotipo cuadrado se
     *                     leía como un favicon, que es justo la queja que abrió este ajuste.
     *                     Sí, son 8px más que el isotipo de OmmiFX de la barra: las dos marcas
     *                     se distinguen por PAPEL y no por tamaño (ver brand.css) —el color de
     *                     marca es del producto y el logo del cliente vive dentro de su
     *                     recuadro neutro—, así que 40px no le disputa nada a nadie.
     *   --mark-max-width  tope de anchura. 160px es lo más ancho que cabe en la fila del carril
     *                     (199px de contenido) dejando aire: un lockup apaisado se ve de verdad
     *                     en vez de encogerse a una franja de 15px de alto.
     *   --name-min-width  el ancho por debajo del cual el nombre NO comparte fila. Es lo que
     *                     hace adaptativa la composición sin que nadie mida la imagen: es la
     *                     base de flex del nombre, y cuando la marca no deja ese hueco, el
     *                     nombre baja solo a la fila siguiente con los 199px enteros.
     *
     * El umbral sale de la aritmética, no de una segunda regla: 199 - 12 de hueco - 112 deja
     * 75px de caja para la marca, o sea ~65px de imagen, que a 40px de alto es 1,6:1. Hasta ahí
     * marca y nombre van uno al lado del otro; más apaisada que eso, se apilan. Que es
     * exactamente lo que quiere cada uno de los dos casos.
     */
    --brand-tenant-mark-height: 40px;
    --brand-tenant-mark-max-width: 160px;
    --brand-tenant-name-min-width: 112px;

    /* ====================================================================================
     * BLOQUE DE ESCALA -- docs/06-design-system.md
     *
     * Bloque único de escala desde la tanda 84: aquí viven espaciado, radio, sombra, tipografía,
     * z-index, movimiento, breakpoints, alturas de control y densidad. No hay sinónimos en
     * ninguna otra parte del fichero.
     * ==================================================================================== */

    /* --- Color: escalones que la v1 no tenía (§2 de la v2). Solo altas. ----------------
     * Ninguno de estos cuatro existe en el frontmatter de Stitch, así que en la tanda A de la
     * v3 se han REENTONADO a mano hacia el azul de la paleta nueva en vez de copiarse:
     *   --surface-bright   sí está en Stitch (#f8f9ff), aunque allí coincide con --surface.
     *   --on-surface-muted #5f6274, entre --on-surface-variant y --outline. 5,7:1 sobre --surface.
     *   --outline-subtle   #e2e8f6, más claro que --outline-variant: divisor de tabla.
     *   --secondary-hover  #004b73, el on-secondary-fixed-variant de Stitch: oscurece --secondary.
     * Los nueve semánticos de abajo (warning/success/info) tampoco están en Stitch y se
     * conservan tal cual: son significado, no marca. */
    --surface-bright: #f8f9ff;
    --on-surface-muted: #5f6274;   /* el gris más claro admitido sobre --surface (§7) */
    --outline-subtle: #e2e8f6;     /* divisor de tabla y borde de tarjeta (§5.3, §5.4) */
    --secondary-hover: #004b73;

    /* Semánticos que faltaban. --error/--error-container ya estaban arriba. */
    --warning: #b45309;
    --warning-container: #fef0e0;
    --on-warning-container: #7a3800;
    --success: #0f7a45;
    --success-container: #dcf4e6;
    --on-success-container: #0a5230;
    --info: #0058be;
    --info-container: #dae7ff;
    --on-info-container: #00305f;

    /* El semáforo de RF-33 gana nombre propio para el rojo. Hasta ahora se reutilizaba
       --error a propósito; el alias explícito evita que una pantalla nueva escriba
       var(--error) donde quiere decir "juicio en rojo", que son dos conceptos distintos. */
    --traffic-red: #ba1a1a;

    /* --- Tipografía: los 9 escalones cerrados (§2.2) -----------------------------------
     *
     * Cada escalón se publica de tres formas, porque los tres usos son reales:
     *   --text-X          atajo completo para  font: var(--text-body-md);
     *   --text-X-size     cuando solo hace falta el tamaño (p. ej. dentro de otro shorthand)
     *   --text-X-lh       cuando solo hace falta el interlineado
     * letter-spacing y text-transform NO caben en el shorthand `font`, así que van aparte
     * como --tracking-X y se aplican a mano donde el escalón los pide.
     *
     * Los cuatro superiores son fluidos con clamp(): min = móvil 360px, max = escritorio
     * 1440px. Los cinco inferiores son fijos a propósito -- un cuerpo de tabla que cambia de
     * tamaño con el ancho de la ventana es exactamente lo que hace que una tabla larga se lea
     * inestable.
     *
     * Suelo de contenido: --text-body-md = 14px. Los 11px quedan SOLO para --text-overline
     * (§2.2). La sustitución de los 20 tamaños a mano por estos nueve es la fase 2, no esta. */
    --text-display-size: clamp(28px, 1.6rem + 1.4vw, 40px);
    --text-display-lh: 1.15;
    --text-display: 700 var(--text-display-size)/var(--text-display-lh) var(--font-sans);
    --tracking-display: -.02em;

    --text-title-xl-size: clamp(22px, 1.25rem + .8vw, 28px);
    --text-title-xl-lh: 1.2;
    --text-title-xl: 650 var(--text-title-xl-size)/var(--text-title-xl-lh) var(--font-sans);
    --tracking-title-xl: -.015em;

    --text-title-lg-size: clamp(18px, 1.05rem + .4vw, 21px);
    --text-title-lg-lh: 1.3;
    --text-title-lg: 600 var(--text-title-lg-size)/var(--text-title-lg-lh) var(--font-sans);
    --tracking-title-lg: -.01em;

    --text-title-md-size: 16px;
    --text-title-md-lh: 1.4;
    --text-title-md: 600 var(--text-title-md-size)/var(--text-title-md-lh) var(--font-sans);

    --text-body-lg-size: 15px;
    --text-body-lg-lh: 1.55;
    --text-body-lg: 400 var(--text-body-lg-size)/var(--text-body-lg-lh) var(--font-sans);

    --text-body-md-size: 14px;
    --text-body-md-lh: 1.5;
    --text-body-md: 400 var(--text-body-md-size)/var(--text-body-md-lh) var(--font-sans);

    --text-body-sm-size: 13px;
    --text-body-sm-lh: 1.45;
    --text-body-sm: 400 var(--text-body-sm-size)/var(--text-body-sm-lh) var(--font-sans);

    --text-label-size: 12px;
    --text-label-lh: 1.35;
    --text-label: 550 var(--text-label-size)/var(--text-label-lh) var(--font-label);
    --tracking-label: .02em;

    --text-overline-size: 11px;
    --text-overline-lh: 1.3;
    --text-overline: 600 var(--text-overline-size)/var(--text-overline-lh) var(--font-label);
    --tracking-overline: .06em;

    --text-mono-size: 13px;
    --text-mono-lh: 1.5;
    --text-mono: 400 var(--text-mono-size)/var(--text-mono-lh) var(--font-mono);

    /* --- Espaciado numérico de 4px (§2.3) ----------------------------------------------
     *
     * Sustituye a la nomenclatura xs/sm/md/lg, que no escala: cuando hace falta un valor entre
     * md y lg acaba apareciendo un 6px suelto. Los alias viejos SE RETIRARON en la tanda 84 y
     * sus 529 consumidores se reescribieron a esta escala con la equivalencia exacta, así que
     * el cambio fue de nombre y no de píxel:
     *     --space-xs  -> --space-1   (4px)
     *     --space-sm  -> --space-2   (8px)   <-- el que lee gantt.js, cambiado en el mismo turno
     *     --space-md  -> --space-4   (16px)
     *     --space-lg  -> --space-6   (24px)
     *     --space-xl  -> --space-8   (32px)
     *     --space-2xl -> --space-12  (48px)
     *     --space-3xl -> --space-16  (64px)
     * Los escalones 0.5, 3, 5 y 10 (2, 12, 20 y 40px) no tenían equivalente viejo: son justo
     * los que antes se escribían a mano. */
    --space-0-5: 2px;
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 20px;
    --space-6: 24px;
    --space-8: 32px;
    --space-10: 40px;
    --space-12: 48px;
    --space-16: 64px;

    /* Márgenes laterales de página por corte (§2.3). */
    --gutter-mobile: 16px;
    --gutter-tablet: 24px;
    --gutter-desktop: 32px;

    /* --- Radios: escala alineada con el frontmatter de la v2 (tanda 84) -----------------
     *
     * La divergencia que la tanda 72 dejó anotada QUEDA RESUELTA, y así se resolvió:
     *
     * El diagnóstico no era "los valores están mal", era que TODA la escala estaba corrida un
     * escalón hacia abajo respecto a la v2: el código llamaba --radius a 2px (la v2 llama a eso
     * sm), --radius-lg a 4px (la v2 llama a eso DEFAULT) y --radius-xl a 8px (la v2 llama a eso
     * lg). Y la prueba de que el corrimiento era de NOMBRE y no de gusto está en §5.4 de la v2:
     * pide tarjeta con radio --radius-lg, y la tarjeta de este producto se dibuja hoy a 8px,
     * que es exactamente lo que la v2 llama lg.
     *
     * Decisión: se alinean los VALORES a la v2 y, en el mismo turno, se corren los 95
     * consumidores un escalón para arriba (--radius -> --radius-sm, --radius-lg -> --radius,
     * --radius-xl -> --radius-lg). Resultado: la escala pasa a ser la de la v2, sin sinónimos,
     * y ninguna caja cambia de radio ni un píxel. Lo que se gana no es aspecto: es que
     * --radius-lg vuelva a valer 8 para quien lo escriba mañana leyendo §5.4.
     *
     * ÚNICA excepción deliberada, y sí cambia el aspecto: --radius-full pasa de 12px a 9999px.
     * "full" tiene que significar full. A 12px una píldora de --control-xs (24px de alto) ya
     * salía redonda por casualidad, pero cualquier cosa más alta -- .error-panel__visual,
     * .assign-panel__add, .create-card__icon -- salía con las esquinas romas en vez de
     * circular. Los 19 consumidores se revisaron uno a uno y los 19 son chip, contador, punto,
     * asa o círculo: ninguno es una tarjeta que fuera a quedar con forma de cápsula.
     *
     * El aviso de la v1 ("una esquina de 14px se lee como aplicación de consumo") sigue en pie
     * y por eso NO se ha subido el radio de ninguna tarjeta ni de ningún botón. */
    /* --- Tanda B de la v3 ---------------------------------------------------------------
     * Los VALORES pasan a la escala de "Executive Precision Vibrant" (sm 0.25rem /
     * DEFAULT 0.5rem / md 0.75rem / lg 1rem / xl 1.5rem / full), sin renombrar ninguna variable
     * ni tocar ninguno de los 140 consumidores.
     *
     * Por qué la escala sube un escalón y no se queda donde estaba: la prosa de ese sistema se
     * contradice a sí misma igual que hacía con la paleta ("rounded-lg / 0.5rem" en el texto,
     * pero lg: 1rem en su configuración). Manda la configuración, por el mismo criterio ya
     * aplicado en la tanda A: es lo que su renderizador compiló y, por tanto, lo que se ve en
     * las maquetas aprobadas. Consecuencia visible y querida: la tarjeta (--radius-lg) pasa de
     * 8px a 16px y el botón/input (--radius) de 4px a 8px, que es justo lo que ese sistema pide
     * para "Inputs, Buttons, and Surface Cards".
     *
     * Esto deroga a propósito el aviso de la v1 ("una esquina de 14px se lee como aplicación de
     * consumo"), que era una regla de la marca anterior, no una ley.
     *
     * --radius-none (celdas de tabla) y --radius-full (píldoras) no cambian: los dos extremos ya
     * coincidían. --radius-2xl no tiene equivalente en Stitch, cuyo tope es xl: se extrapola un
     * escalón (32px) para que la hoja inferior de móvil y el diálogo conserven su relación con
     * --radius-xl. */
    --radius-none: 0;
    --radius-sm: 4px;
    --radius: 8px;
    --radius-md: 12px;
    --radius-lg: 16px;
    --radius-xl: 24px;
    --radius-2xl: 32px;
    --radius-full: 9999px;

    /* --- Elevación: 5 niveles (§2.4) ---------------------------------------------------
     * La profundidad de este sistema es tonal y de trazo; la sombra solo aparece cuando algo
     * flota DE VERDAD sobre el contenido.
     *
     * Tanda 84: --shadow-sm/--shadow-md quedan RETIRADOS y sus 13 consumidores pasan al
     * escalón de valor equivalente (--shadow-sm -> --elev-1, --shadow-md -> --elev-2). La
     * diferencia entre el par viejo y el nuevo es de opacidad y de tinte de la sombra
     * (rgba(25,28,30) -> rgba(15,23,42), el mismo giro que --primary), no de geometría: una
     * box-shadow nunca ocupa sitio en el flujo, así que ninguna caja se mueve. Cuatro de esos
     * consumidores son del Gantt (.gantt__bar, .gantt__zoom-btn, .portfolio-gantt__bar) y por
     * eso se dice explícitamente: se les cambia la sombra, no la posición. */
    /* Tanda B de la v3: las sombras pasan a las de "Executive Precision Vibrant", teñidas de
     * azul rgba(29, 78, 216, ...) en vez de la pizarra rgba(15, 23, 42, ...) de la v2. Ese azul
     * es --primary-container, así que la sombra deja de ser gris neutro y toma el mismo tinte
     * frío que la marca. Ese sistema solo define tres niveles (contenedor, flyout, modal):
     * --elev-4 se extrapola del tercero conservando su proporción, para los dos consumidores
     * que lo usan. La geometría crece (más desenfoque y más desplazamiento negativo), pero una
     * box-shadow nunca ocupa sitio en el flujo: ninguna caja se mueve. */
    --elev-0: none;
    --elev-1: 0 1px 3px 0 rgba(29, 78, 216, .04), 0 1px 2px -1px rgba(29, 78, 216, .04);
    --elev-2: 0 4px 6px -1px rgba(29, 78, 216, .06), 0 2px 4px -2px rgba(29, 78, 216, .06);
    --elev-3: 0 20px 25px -5px rgba(29, 78, 216, .08), 0 8px 10px -6px rgba(29, 78, 216, .04);
    --elev-4: 0 32px 48px -12px rgba(29, 78, 216, .12), 0 12px 16px -8px rgba(29, 78, 216, .06);

    /* --- z-index: escala cerrada (§2.5) ------------------------------------------------
     * Ningún valor fuera de esta lista. Los 11 valores inventados que hay hoy (1, 2, 4, 5, 20,
     * 40, 50, 60, 900) se mapean al escalón más cercano en las fases 2 y 3.
     * Cuidado ya anotado para la tanda 74: presentation.css (modo presentación de la junta)
     * va a --z-overlay, POR DEBAJO de --z-dialog; si sube, un diálogo abierto durante una
     * presentación queda tapado. */
    --z-base: 0;
    --z-raised: 10;
    --z-sticky: 100;
    --z-drawer: 200;
    --z-overlay: 300;
    --z-dialog: 400;
    --z-popover: 500;
    --z-toast: 600;
    --z-tooltip: 700;

    /* --- Movimiento (§2.6) -------------------------------------------------------------
     * Cuatro duraciones y cuatro curvas. Regla: lo que entra decelera, lo que sale acelera, y
     * nada dura más de 320ms salvo una hoja móvil completa. El respeto a
     * prefers-reduced-motion es una única regla global en base.css. */
    --duration-instant: 80ms;
    --duration-fast: 140ms;
    --duration-base: 200ms;
    --duration-slow: 320ms;
    --ease-standard: cubic-bezier(.2, 0, 0, 1);
    --ease-decelerate: cubic-bezier(0, 0, 0, 1);
    --ease-accelerate: cubic-bezier(.3, 0, 1, 1);
    --ease-spring: cubic-bezier(.34, 1.4, .64, 1);

    /* --- Breakpoints (§4.1) ------------------------------------------------------------
     *
     * AVISO: una custom property NO se puede usar dentro de @media -- la consulta se evalúa
     * antes de resolver variables. Estos tokens NO son consumibles por una media query; están
     * aquí como fuente única de verdad de los seis valores, para que quien escriba una
     * @media copie el número correcto y no invente un 620px o un 1100px más (hoy hay siete
     * breakpoints ad-hoc). Sí son consumibles desde JavaScript por getPropertyValue, que es la
     * otra forma legítima de leerlos.
     *
     * Se escribe para 360px y se AÑADE hacia arriba con min-width. Toda regla max-width en un
     * fichero nuevo es un error de revisión, salvo el colapso del sidebar. */
    --bp-xs: 360px;   /* base, punto de partida: no es un breakpoint */
    --bp-sm: 480px;   /* móvil grande */
    --bp-md: 768px;   /* tablet vertical. FRONTERA TÁCTIL <-> PUNTERO */
    --bp-lg: 1024px;  /* portátil pequeño. Aparece el sidebar fijo */
    --bp-xl: 1280px;  /* escritorio */
    --bp-2xl: 1600px; /* escritorio ancho */

    /* Frontera derivada, NO un séptimo breakpoint: --bp-xl más la holgura de una barra de
     * scroll clásica. Una @media casa contra el ancho del VIEWPORT, pero el contenido dispone
     * del ancho del CLIENTE, que es 15-17px menor cuando hay barra visible. La tabla de datos
     * completa (§5.3) necesita casi todo el hueco disponible, así que a 1280 exactos aparecía
     * en un contenedor 15px más estrecho del que la consulta suponía y desbordaba 4px -- medido
     * en un navegador real al cerrar la tanda 82, justo en el ancho al que corre la suite E2E.
     * Único consumidor: el bloque de tabla completa de components.css. */
    --bp-xl-table: 1304px;

    /* --- Alturas de control (§4.4) ------------------------------------------------------
     *
     * Misma historia que los radios y misma corrección en la tanda 84: la escala estaba
     * corrida un escalón. El código llamaba --control-sm a 24px y --control-md a 32px,
     * mientras la v2 llama xs a 24, sm a 32 y md a 40. Se han corrido los 41 consumidores
     * (--control-sm -> --control-xs, --control-md -> --control-sm) sin cambiar ni un píxel de
     * altura, y --control-md recupera su valor correcto de 40px.
     *
     * Todo lo que sea "pastilla" se fija con height, NUNCA con padding. El motivo: en un
     * contenedor flex sin align-items un chip se ESTIRA a la altura de la fila, y uno estrecho
     * como «Todas» acaba cuadrado mientras el resto son píldoras.
     *
     * --control-xs (24px) y --control-sm (32px) significan "chip o badge NO pulsable": están
     * por debajo del mínimo táctil de 44px y no se usan en nada clicable. Lo pulsable usa:
     *     botón pequeño / píldora  --control-sm  (32px) -> --control-touch bajo md
     *     botón principal          --field       (40px) -> --field-touch (48px) bajo md
     *     campo de formulario      --field              -> --field-touch
     *     icono suelto             --control-sm         -> --control-touch */
    --control-xs: 24px;
    --control-sm: 32px;
    --control-md: 40px;
    --control-lg: 48px;
    --control-touch: 44px;  /* mínimo táctil absoluto bajo --bp-md */
    --field: 40px;
    --field-touch: 48px;

    /* --- Densidad (§4.5) ---------------------------------------------------------------
     * La respuesta correcta a "necesito ver más filas" es este interruptor, no bajar la fuente
     * a 11px. El interruptor de usuario y su persistencia en localStorage son de una tanda
     * posterior: aquí solo se declaran las variables.
     *
     * MOBILE-FIRST desde la tanda 84, y con eso este fichero se queda sin ninguna max-width.
     * El valor BASE es el táctil: 56px, porque 360px es el punto de partida y una fila de 44px
     * es incómoda de acertar con el pulgar. La densidad de puntero se AÑADE en md, que es la
     * frontera dedo/ratón. Antes esto estaba escrito al revés, con una @media (max-width: 767px)
     * declarada en su día como "la única admitida"; la inversión estaba prometida en el propio
     * comentario para cuando la fase 4 terminase, y la fase 4 terminó en la tanda 83. */
    --density-row: 56px;
    --density-cell-y: var(--space-4);
}

/*
 * Densidad de puntero y su variante compacta. Las DOS van dentro de la misma consulta a
 * propósito: [data-density="compact"] tiene la misma especificidad que :root, así que suelto
 * ganaría también en móvil por ir después, y una fila de 36px con el pulgar no se acierta.
 * Escrito así, el interruptor compacto solo existe donde hay ratón -- que es exactamente el
 * comportamiento que tenía antes de invertir la consulta, sin cambio de píxel a ningún ancho.
 */
@media (min-width: 768px) {
    :root {
        --density-row: 44px;
        --density-cell-y: var(--space-3);
    }

    /* Activada con [data-density="compact"] en <html> o en un contenedor. */
    [data-density="compact"] {
        --density-row: 36px;
        --density-cell-y: var(--space-2);
    }
}
