/* ========================================
   SISTEMA DE ESTILOS GLOBAL - CGT ADMINISTRADOR
   Diseño profesional y consistente en todo el sitio
   ======================================== */

/* ========================================
   TIPOGRAFÍA — Source Sans 3 (autohospedada, wwwroot/fonts/)
   Fuente variable (eje wght 200-900) en un solo archivo woff2, subset
   "latin" (cubre español: tildes, ñ, ü). Ver Docs/design-system/
   SISTEMA-DISENO.md para la escala de tamaños y el resto de tokens
   tipográficos, definidos en :root más abajo.
   ======================================== */
@font-face {
    font-family: 'Source Sans 3';
    src: url('/fonts/SourceSans3-Variable.woff2') format('woff2-variations'),
         url('/fonts/SourceSans3-Variable.woff2') format('woff2');
    font-weight: 200 900;
    font-style: normal;
    font-display: swap;
}

/* ========================================
   RESET Y BASE
   ======================================== */
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

:root {
    /* ========================================
       CAPA 1 — PRIMITIVAS (sin significado)
       Sistema de diseño CGT — ver Docs/design-system/SISTEMA-DISENO.md
       y Docs/design-system/MAPEO-COLORES.md para el detalle y la
       justificación de cada valor. Todavía apuntan a la paleta ACTUAL
       (predominantemente púrpura) — el repintado a Propuesta C (gris
       carbón dominante) es una fase posterior y no cambia ningún
       nombre de token, solo el valor de estas primitivas.
       ======================================== */

    /* Escala de grises — 11 pasos, ancla exacta en --gris-900 = #2D3436 */
    --gris-50: #fbfbfc;
    --gris-100: #f2f4f5;
    --gris-200: #e0e4e5;
    --gris-300: #c7cfd1;
    --gris-400: #a5b0b4;
    --gris-500: #829297;
    --gris-600: #697a7f;
    --gris-700: #525f63;
    --gris-800: #3c4648;
    --gris-900: #2d3436;
    --gris-950: #151819;

    /* Púrpura — acento de marca actual */
    --purpura-50: #faf8ff;
    --purpura-100: #ede8f8;
    --purpura-200: #ddd6f5;
    --purpura-500: #667eea;
    --purpura-600: #5568d3;
    --purpura-700: #764ba2;
    --purpura-800: #5a4a8a;
    --purpura-900: #3d3060;

    /* Rojo — único rojo del sistema (destructivo/error) */
    --rojo-50: #fff0f0;
    --rojo-100: #f8d7da;
    --rojo-600: #dc3545;
    --rojo-700: #c82333;
    --rojo-900: #721c24;

    /* Verde — éxito/activo (verde CGT) */
    --verde-50: #f0faf0;
    --verde-100: #d4edda;
    --verde-400: #a8e063;
    --verde-600: #56ab2f;
    --verde-900: #155724;

    /* Naranja / Amarillo — advertencia/inactivo. Provisional: ver caso
       "requiere criterio" en MAPEO-COLORES.md (#ffc107 compite con
       #f2994a por el mismo rol; se conserva el que hoy está declarado
       como oficial hasta que se resuelva cuál es "amarillo CGT"). */
    --naranja-300: #f2c94c;
    --naranja-500: #f2994a;
    --amarillo-100: #fff3cd;
    --amarillo-900: #856404;

    /* Azul / Cian — utilidad "info", sin rol de producto propio */
    --azul-500: #2196f3;
    --azul-900: #004085;
    --cyan-400: #21cbf3;

    /* Absolutos y overlays — no son colores de superficie, son la base
       de las sombras y veladuras rgba() del inventario */
    --negro-absoluto: #000000;
    --blanco-absoluto: #ffffff;

    /* Overlays — modificadores de opacidad sobre negro/blanco puro,
       documentados desde la fase de tokens pero implementados recién
       tras el piloto de Censo (ver §3.8 de SISTEMA-DISENO.md; estaban
       en la documentación pero nunca se habían declarado aquí). Pasos
       de 5%, cubriendo el rango real de alphas del inventario
       (MAPEO-COLORES.md, familia "grises"). Uso: veladuras, scrims,
       sombras que no encajan en la escala --shadow-* con nombre. */
    --overlay-oscuro-5: rgba(0, 0, 0, 0.05);
    --overlay-oscuro-10: rgba(0, 0, 0, 0.10);
    --overlay-oscuro-15: rgba(0, 0, 0, 0.15);
    --overlay-oscuro-20: rgba(0, 0, 0, 0.20);
    --overlay-oscuro-25: rgba(0, 0, 0, 0.25);
    --overlay-oscuro-30: rgba(0, 0, 0, 0.30);
    --overlay-oscuro-35: rgba(0, 0, 0, 0.35);
    --overlay-oscuro-40: rgba(0, 0, 0, 0.40);
    --overlay-oscuro-45: rgba(0, 0, 0, 0.45);
    --overlay-oscuro-50: rgba(0, 0, 0, 0.50);
    --overlay-oscuro-55: rgba(0, 0, 0, 0.55);

    --overlay-claro-10: rgba(255, 255, 255, 0.10);
    --overlay-claro-15: rgba(255, 255, 255, 0.15);
    --overlay-claro-20: rgba(255, 255, 255, 0.20);
    --overlay-claro-25: rgba(255, 255, 255, 0.25);
    --overlay-claro-30: rgba(255, 255, 255, 0.30);
    --overlay-claro-35: rgba(255, 255, 255, 0.35);
    --overlay-claro-40: rgba(255, 255, 255, 0.40);
    --overlay-claro-45: rgba(255, 255, 255, 0.45);
    --overlay-claro-50: rgba(255, 255, 255, 0.50);
    --overlay-claro-55: rgba(255, 255, 255, 0.55);
    --overlay-claro-60: rgba(255, 255, 255, 0.60);
    --overlay-claro-65: rgba(255, 255, 255, 0.65);
    --overlay-claro-70: rgba(255, 255, 255, 0.70);
    --overlay-claro-75: rgba(255, 255, 255, 0.75);
    --overlay-claro-80: rgba(255, 255, 255, 0.80);
    --overlay-claro-85: rgba(255, 255, 255, 0.85);
    --overlay-claro-90: rgba(255, 255, 255, 0.90);

    /* ========================================
       PRIMITIVAS CGT — Propuesta C
       Único rojo/verde/amarillo del sistema, según decisión ya tomada
       (consolidación de los 5 casos "requiere criterio" principales de
       MAPEO-COLORES.md: los dos verdes, ámbar+naranja, el tercer rojo
       de validación y el acento de Educación se absorben aquí). Los
       pasos 50/100/700/900 se derivan del ancla oficial (600) con una
       fórmula de tinte/sombra consistente entre las tres familias —
       ver §6.1 de SISTEMA-DISENO.md para los valores exactos y los
       ratios de contraste de cada uno.
       ======================================== */
    --rojo-cgt-50: #fbf4f5;
    --rojo-cgt-100: #f5d6d9;
    --rojo-cgt-600: #e83747;   /* ancla oficial: rojo CGT */
    --rojo-cgt-700: #d21324;
    --rojo-cgt-900: #860914;

    --verde-cgt-50: #f5f9f6;
    --verde-cgt-100: #dcefde;
    --verde-cgt-600: #3cb54b;  /* ancla oficial: verde CGT */
    --verde-cgt-700: #2e933a;
    --verde-cgt-900: #1b5e23;

    --amarillo-cgt-50: #fcfaf3;
    --amarillo-cgt-100: #f9f1d2;
    --amarillo-cgt-600: #ffcb05; /* ancla oficial: amarillo CGT */
    --amarillo-cgt-700: #d0a500;
    --amarillo-cgt-900: #826700;

    /* Tipografía — Source Sans 3 autohospedada (wwwroot/fonts/), con
       fallback a la pila de sistema. Escala de tamaños derivada de los
       clústeres reales de font-size del inventario (327 apariciones
       combinadas entre rem/px equivalentes) — ver SISTEMA-DISENO.md. */
    --fuente-base: 'Source Sans 3', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

    --texto-xs: 0.75rem;     /* 12px — absorbe el clúster .70–.78rem (candidatos: 34+20+17+12 apariciones) */
    --texto-sm: 0.875rem;    /* 14px — el tamaño más usado del inventario (62 directas + clúster .8–.95rem) */
    --texto-base: 1rem;      /* 16px — cuerpo por defecto */
    --texto-md: 1.125rem;    /* 18px */
    --texto-lg: 1.25rem;     /* 20px */
    --texto-xl: 1.5rem;      /* 24px */
    --texto-2xl: 2rem;       /* 32px — 2º valor más usado del inventario (32 apariciones) */
    --texto-3xl: 3rem;       /* 48px — cifras/stats grandes */

    --peso-normal: 400;
    --peso-medio: 500;
    --peso-semibold: 600;    /* el peso dominante del inventario (156 apariciones) */
    --peso-bold: 700;

    --interlineado-ajustado: 1;       /* iconos, badges, texto de una línea */
    --interlineado-titulo: 1.1;       /* títulos y cifras grandes */
    --interlineado-normal: 1.5;       /* cuerpo de texto */
    --interlineado-relajado: 1.75;    /* párrafos largos, alertas */

    --interletra-normal: 0;
    --interletra-amplia: 0.5px;       /* labels en mayúscula — valor dominante del inventario (32 apariciones) */

    --fuente-numeros-tabulares: tabular-nums;

    /* Tamaños de ícono/avatar — escala separada de --texto-*, agregada
       tras el piloto de Censo (ver §5.2 de SISTEMA-DISENO.md). La
       escala tipográfica está pensada para TEXTO (tope 48px) y no
       cubría glifos de ícono (bi bi-*) ni iniciales de avatar grandes
       (24/28/36/64/72px reales en Censo) sin forzar recortes visibles
       (el caso más notorio: el placeholder de avatar de VerAfiliado se
       recortaba de 72 a 48px). En rem, igual que --texto-*, para que
       los íconos también escalen con la preferencia de fuente del
       usuario (son glifos de una fuente de íconos, no imágenes). */
    --icono-xs: 1rem;      /* 16px — íconos en botones/badges pequeños */
    --icono-sm: 1.25rem;   /* 20px — íconos de fila estándar */
    --icono-md: 1.5rem;    /* 24px — headers de card/sección */
    --icono-lg: 1.75rem;   /* 28px */
    --icono-xl: 2.25rem;   /* 36px — íconos destacados (stat cards) */
    --icono-2xl: 4rem;     /* 64px — íconos de estado vacío */
    --icono-3xl: 4.5rem;   /* 72px — iniciales de avatar grande sin foto */

    /* ========================================
       CAPA 2 — SEMÁNTICAS (con propósito) — Propuesta C
       Los componentes deben usar SOLO estos tokens, nunca primitivas
       directamente. Ninguno de estos tokens tiene consumidores en
       páginas existentes todavía (no se migró ningún componente en
       esta fase) — la única página que los usa es /design-system
       (Components/Pages/Admin/DesignSystem.razor), el prototipo visual
       de esta propuesta. Ver §6 de SISTEMA-DISENO.md para los ratios
       de contraste WCAG AA de cada combinación texto/fondo.
       ======================================== */

    /* Superficie */
    --surface-page: var(--gris-100);
    --surface-card: var(--blanco-absoluto);
    --surface-sunken: var(--gris-50);
    --surface-disabled: var(--gris-100);
    --surface-overlay-scrim: rgba(0, 0, 0, 0.5);

    /* Texto */
    --text-heading: var(--gris-900);
    --text-body: var(--gris-900);
    --text-secondary: var(--gris-700);
    --text-muted: var(--gris-600);
    --text-inverso: var(--blanco-absoluto);
    --text-link: var(--gris-900);
    --text-link-hover: var(--gris-700);

    /* Acción — primaria en gris carbón (regla de Propuesta C: las
       acciones van en gris, los colores CGT quedan para elementos NO
       accionables). Hover aclara, activo/pressed oscurece. */
    --color-accion-primaria: var(--gris-900);
    --color-accion-primaria-hover: var(--gris-800);
    --color-accion-primaria-activo: var(--gris-950);
    --color-accion-secundaria-fondo: var(--gris-100);
    --color-accion-secundaria-fondo-hover: var(--gris-200);
    --color-accion-secundaria-texto: var(--gris-900);
    --color-accion-secundaria-borde: var(--gris-300);
    --color-deshabilitado-fondo: var(--gris-100);
    --color-deshabilitado-texto: var(--gris-400);
    --color-deshabilitado-borde: var(--gris-200);

    /* Foco — NUNCA rojo (rojo queda reservado para destructivo). Sigue
       a la acción primaria: anillo gris carbón translúcido. */
    --color-foco: var(--gris-900);
    --color-foco-anillo: rgba(45, 52, 54, 0.25);

    /* Acentos semánticos (no accionables) — únicos rojo/verde/amarillo
       del sistema. Ver §6.2 de SISTEMA-DISENO.md para el detalle
       completo de ratios; resumen de las 3 excepciones no obvias:

       1) "-superficie" (fondo sólido de botón/badge lleno): en verde y
          amarillo el ancla 600 es demasiado clara para texto blanco
          (2.66:1 y 1.52:1, ambos reprueban incluso AA-large de 3:1),
          así que la superficie sólida lleva texto oscuro
          (--color-*-superficie-texto = gris-900, que sí pasa: 4.77:1 y
          8.33:1). En rojo el ancla 600 tampoco alcanza 4.5:1 con texto
          blanco (4.14:1) ni con gris-900 (3.06:1), así que la
          superficie sólida usa el escalón 700 (5.44:1 con blanco).

       2) --color-exito usa el escalón 700, NO el ancla 600: como color
          de ícono/borde/texto sobre blanco, verde-cgt-600 da 2.66:1 —
          reprueba incluso el mínimo de 3:1 para elementos no-texto
          (WCAG 1.4.11). verde-cgt-700 sí pasa (3.92:1).

       3) --color-advertencia SÍ usa el ancla 600 (es la única forma de
          que se vea "amarillo CGT" y no un mostaza oscuro), pero NO
          hay ningún escalón de amarillo que pase 3:1 sobre blanco como
          ícono/texto (600=1.52:1, 700=2.32:1 — ambos reprueban; recién
          900=5.40:1 pasa, y a esa luminosidad ya no lee como amarillo
          brillante). Consecuencia de diseño: --color-advertencia NUNCA
          se usa como color de ícono/texto/borde suelto sobre blanco —
          solo como superficie con texto oscuro encima
          (--color-advertencia-superficie-texto), o en usos puramente
          decorativos sin función informativa por sí solos (la franja
          tricolor de marca).

       --color-destructivo (rojo, 600) sí es seguro como ícono/borde
       sobre blanco: 4.14:1, pasa el mínimo de 3:1 para no-texto. */
    --color-exito: var(--verde-cgt-700);
    --color-exito-superficie: var(--verde-cgt-600);
    --color-exito-superficie-texto: var(--gris-900);
    --color-exito-fondo: var(--verde-cgt-100);
    --color-exito-texto: var(--verde-cgt-900);

    --color-destructivo: var(--rojo-cgt-600);
    --color-destructivo-superficie: var(--rojo-cgt-700);
    --color-destructivo-superficie-hover: var(--rojo-cgt-900);
    --color-destructivo-superficie-texto: var(--blanco-absoluto);
    --color-destructivo-fondo: var(--rojo-cgt-100);
    --color-destructivo-texto: var(--rojo-cgt-900);

    --color-advertencia: var(--amarillo-cgt-600);
    --color-advertencia-superficie: var(--amarillo-cgt-600);
    --color-advertencia-superficie-texto: var(--gris-900);
    --color-advertencia-fondo: var(--amarillo-cgt-100);
    --color-advertencia-texto: var(--amarillo-cgt-900);

    /* Neutro/info — para contenido informativo que NO es un estado
       (éxito/advertencia/destructivo): badges sin semántica de estado
       (género, edad), alertas informativas. Propuesta C deliberadamente
       no reserva un acento de color para "información" (§6.3) — este es
       el nombre formal de un patrón que ya existía sin nombre (el
       piloto de Censo y la alerta informativa de /design-system usaban
       --gris-100/--gris-700 directo). Misma forma que
       --color-exito/-fondo/-texto: "--color-neutro" es el tono medio
       para ícono/borde, "-fondo/-texto" es el par pastel. */
    --color-neutro: var(--gris-700);
    --color-neutro-fondo: var(--gris-100);
    --color-neutro-texto: var(--gris-900);
    /* Superficie sólida (botón/relleno) — el caso que la nota original de
       esta familia dejó pendiente ("si aparece un botón neutro, agregar
       -superficie siguiendo el mismo patrón"): apareció al resolver
       .btn-info/.bg-info hacia neutro (pasada final de coherencia).
       gris-700 con texto blanco da 6.61:1, sobre el mínimo de 4.5:1 para
       texto normal, no solo el 3:1 de no-texto. */
    --color-neutro-superficie: var(--gris-700);
    --color-neutro-superficie-texto: var(--blanco-absoluto);

    /* Badges de jerarquía — para taxonomías categóricas (no de estado) con
       más de dos valores, como TipoUsuario (6 roles). Los badges de estado
       de arriba (éxito/advertencia/destructivo) están reservados a
       significado de estado; usarlos para distinguir categorías sin carga
       valorativa introduce ruido semántico — §10.3 de SISTEMA-DISENO.md ya
       rechazó ese patrón para el sidebar por el mismo motivo. Resuelve el
       hallazgo #7 de AJUSTES-PENDIENTES.md.

       Escala de --gris-* graduada, 1 = mayor jerarquía/autoridad (más
       oscuro) a 6 = nivel base (más claro) — el gris ya es "la estructura
       del sistema" en el resto de la paleta, así que una escala de grises
       para jerarquía es consistente con ese lenguaje, no un color nuevo.

       Los 11 pasos de --gris-* son una rampa continua (pensada para
       gradaciones finas, no swatches categóricos): dos pasos consecutivos
       cualquiera solo difieren ~1.1–1.5:1 entre sí, casi imperceptible
       (ver AJUSTES-PENDIENTES.md #7 para el detalle). Solo 700/800/900/950
       alcanzan 4.5:1 con texto blanco, y solo 50/100/200/300/400 alcanzan
       4.5:1 con texto --gris-900 — 500/600 no llegan a AA con ningún par
       de los dos. De esos 9 pasos utilizables, --badge-jerarquia-1/2/3
       (950/800/700) y -4/5/6 (400/300/50) son la combinación de 3+3 con
       mayor separación mínima entre pasos elegidos (par más cercano:
       jerarquia-2/3, 1.47:1 — igual se distinguen entre sí, y el texto de
       cada badge ya es distinto, el color solo acelera el reconocimiento).
       Nombrados por posición, no por rol: sirven a cualquier taxonomía
       jerárquica futura, no solo a TipoUsuario. */
    --badge-jerarquia-1: var(--gris-950);
    --badge-jerarquia-1-texto: var(--text-inverso);
    --badge-jerarquia-2: var(--gris-800);
    --badge-jerarquia-2-texto: var(--text-inverso);
    --badge-jerarquia-3: var(--gris-700);
    --badge-jerarquia-3-texto: var(--text-inverso);
    --badge-jerarquia-4: var(--gris-400);
    --badge-jerarquia-4-texto: var(--gris-900);
    --badge-jerarquia-5: var(--gris-300);
    --badge-jerarquia-5-texto: var(--gris-900);
    --badge-jerarquia-6: var(--gris-50);
    --badge-jerarquia-6-texto: var(--gris-900);

    /* Bordes */
    --borde-sutil: var(--gris-200);
    --borde-input: var(--gris-200);
    --borde-input-foco: var(--color-foco);
    --borde-fuerte: var(--gris-400);

    /* Marca — la marca aparece en detalles de alta visibilidad y baja
       superficie (franjas, bordes de acento, iconografía), nunca como
       fondo grande. Ver §6.3 de SISTEMA-DISENO.md. */
    --marca-franja: linear-gradient(90deg,
        var(--rojo-cgt-600) 0%, var(--rojo-cgt-600) 33.33%,
        var(--amarillo-cgt-600) 33.33%, var(--amarillo-cgt-600) 66.66%,
        var(--verde-cgt-600) 66.66%, var(--verde-cgt-600) 100%);
    /* Indicador de menú activo — decisión fijada: borde izquierdo
       tricolor, tres segmentos apilados en vertical (no un solo rojo).
       Mismo patrón de cortes duros que --marca-franja, en vertical.
       Uso: background de un ::before absoluto de 4px sobre el borde
       izquierdo (NO border-image: con un ancho explícito se aplica a
       los cuatro lados, no solo al izquierdo — ver NavMenu.razor.css
       y /design-system, sección "Detalles de marca", para el detalle
       del bug que descartó esa técnica). */
    --menu-activo-borde: linear-gradient(to bottom,
        var(--rojo-cgt-600) 0 33.33%,
        var(--amarillo-cgt-600) 33.33% 66.66%,
        var(--verde-cgt-600) 66.66% 100%);

    /* Sidebar — decisión final tras comparar Propuesta A/B/C y variantes
       de intensidad en /design-system (§6.3/§8 de SISTEMA-DISENO.md):
       degradado sutil de carbón (A7b), sin puntos de color por sección.
       El tinte del ítem activo es un rojo CGT fijo y muy tenue (12% de
       opacidad) — no depende de a qué sección pertenezca el ítem, para
       no introducir un color con significado de estado (rojo) donde no
       señala ningún estado real. */
    --sidebar-fondo: linear-gradient(180deg, var(--gris-800) 0%, var(--gris-950) 100%);
    --menu-activo-fondo: color-mix(in srgb, var(--rojo-cgt-600) 12%, transparent);

    /* ========================================
       COLORES PRINCIPALES (legacy, en uso — ver §1.2 de
       SISTEMA-DISENO.md). REAPUNTADAS a la Propuesta C tras migrar
       app.css (ver §1.3): --primary-gradient/--primary-color/
       --primary-dark y --gray-* cambian de valor AQUÍ, en su propia
       declaración — esto es un cambio global inmediato que afecta a
       los 43 módulos sin migrar todavía que las consumen (es la
       decisión explícita de esta fase, no un efecto colateral).
       --success/warning/danger/info/secondary-gradient NO se tocan:
       las clases que los usaban en este archivo (.btn-success, etc.)
       se reescribieron para apuntar directo a los tokens semánticos
       nuevos, así que ya no dependen de estas variables — pero se
       conservan con su valor original porque otros módulos sin migrar
       las siguen usando directamente y esta fase no decidió tocar la
       familia éxito/advertencia/destructivo/secundario a nivel de
       variable (solo primary y gray, ver reporte de la tarea).
       ======================================== */
    --primary-gradient: linear-gradient(135deg, var(--gris-800) 0%, var(--gris-900) 100%);
    --primary-color: var(--color-accion-primaria);
    --primary-dark: var(--color-accion-primaria-hover);

    /* Colores de estado */
    --success-gradient: linear-gradient(135deg, var(--verde-600) 0%, var(--verde-400) 100%);
    --warning-gradient: linear-gradient(135deg, var(--naranja-500) 0%, var(--naranja-300) 100%);
    --danger-gradient: linear-gradient(135deg, var(--rojo-600) 0%, var(--rojo-700) 100%);
    /* Sin consumidores tras resolver la familia "info" hacia
       --color-neutro-* (pasada final de coherencia) — se conserva
       definida, sin usar, por el mismo criterio de no romper nada que
       referencie el nombre fuera de este archivo. */
    --info-gradient: linear-gradient(135deg, var(--azul-500) 0%, var(--cyan-400) 100%);
    --secondary-gradient: linear-gradient(135deg, #6c757d 0%, #5a6268 100%);

    /* Colores neutros (legacy — REAPUNTADOS a --gris-* tras migrar
       app.css, ver §1.3 de SISTEMA-DISENO.md. Cambio global inmediato:
       afecta a los 43 módulos sin migrar que usan var(--gray-*)
       directamente. Cada paso apunta al más cercano de la escala
       nueva por distancia de color, no por índice — --gray-400/500
       ambos caen más cerca de un --gris-* distinto al que sugeriría
       su número (ver MAPEO-COLORES.md, familia "grises"). */
    --gray-50: var(--gris-50);
    --gray-100: var(--gris-100);
    --gray-200: var(--gris-200);
    --gray-300: var(--gris-300);
    --gray-400: var(--gris-500);
    --gray-500: var(--gris-700);
    --gray-600: var(--gris-700);
    --gray-700: var(--gris-900);
    --gray-800: var(--gris-950);

    /* Espaciados (legacy, en px — DEPRECADOS a favor de --espacio-* desde
       el cierre de brechas post-piloto Censo, ver §3.9 de
       SISTEMA-DISENO.md. Se conservan con su valor exacto sin cambios
       porque tienen 46 usos reales en app.css que no se tocan en esta
       fase — pero ningún código nuevo/migrado debe usarlos: usar la
       tabla de equivalencia de §3.9 para snappear al paso --espacio-*
       más cercano. */
    --spacing-xs: 5px;
    --spacing-sm: 10px;
    --spacing-md: 15px;
    --spacing-lg: 20px;
    --spacing-xl: 30px;
    --spacing-2xl: 40px;

    /* Espaciado — escala OFICIAL en rem, derivada de los valores reales
       de padding/margin del inventario (múltiplos de 0.25rem con uso
       real, sin pasos inventados). Extendida tras el piloto de Censo
       (ver §3.9 de SISTEMA-DISENO.md) con --espacio-10/15/20 para cubrir
       40/60/80px, que antes solo alcanzaba la escala legacy --spacing-*.
       El número de cada paso es literalmente cuántos cuartos de rem
       representa (--espacio-N = N × 0.25rem), así que --espacio-9/10/11
       existen conceptualmente aunque solo se declaran los que tienen uso
       real — no hay ambigüedad si hace falta agregar --espacio-9 después. */
    --espacio-1: 0.25rem;
    --espacio-2: 0.5rem;
    --espacio-3: 0.75rem;
    --espacio-4: 1rem;
    --espacio-5: 1.25rem;
    --espacio-6: 1.5rem;
    --espacio-7: 1.75rem;
    --espacio-8: 2rem;
    --espacio-10: 2.5rem;
    --espacio-12: 3rem;
    --espacio-15: 3.75rem;
    --espacio-20: 5rem;

    /* Bordes (legacy — se conservan sin cambios) */
    --border-radius-sm: 6px;
    --border-radius-md: 8px;
    --border-radius-lg: 12px;
    --border-radius-xl: 16px;
    --border-radius-full: 50%;

    /* Radios — escala nueva, agrega los pasos frecuentes en el
       inventario que no tenían token (4px, 10px, 20px) */
    --radio-4: 4px;
    --radio-6: var(--border-radius-sm);
    --radio-8: var(--border-radius-md);
    --radio-10: 10px;
    --radio-12: var(--border-radius-lg);
    --radio-16: var(--border-radius-xl);
    --radio-20: 20px;
    --radio-full: 9999px;

    /* Sombras (legacy — se conservan sin cambios) */
    --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.08);
    --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.1);
    --shadow-lg: 0 6px 16px rgba(0, 0, 0, 0.12);
    --shadow-xl: 0 8px 24px rgba(0, 0, 0, 0.15);
    --shadow-accion-primaria: 0 4px 12px rgba(102, 126, 234, 0.4);

    /* Transiciones (legacy — se conservan sin cambios) */
    --transition-fast: 0.15s ease;
    --transition-normal: 0.3s ease;
    --transition-slow: 0.5s ease;

    /* Z-index — escala semántica, ver §3.11 de SISTEMA-DISENO.md */
    --z-base: 1;
    --z-dropdown: 20;
    --z-sticky: 999;
    --z-nav: 1000;
    --z-nav-dropdown: 1002;
    --z-modal-backdrop: 1040;
    --z-modal: 1050;
    --z-modal-nested: 1060;
    --z-toast: 2000;
    --z-overlay-carga: 9998;
    --z-overlay-critico: 9999;
}

/* Clase reutilizable para cifras: toda columna de moneda o cantidad
   debe usarla para que los dígitos alineen en columna (ancho fijo por
   dígito) en vez del ancho proporcional por defecto. Nueva, sin
   consumidores en páginas existentes todavía. */
.cifras-tabulares {
    font-variant-numeric: var(--fuente-numeros-tabulares);
}

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    font-size: 14px;
    color: var(--gray-700);
    background-color: var(--gray-50);
}

/* ========================================
   BREADCRUMBS ESTILIZADOS
   ======================================== */
.breadcrumb {
    background: var(--surface-card);
    padding: var(--espacio-3) var(--espacio-5);
    border-radius: var(--radio-8);
    box-shadow: var(--shadow-sm);
    margin-bottom: var(--espacio-5);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
}

.breadcrumb-item {
    display: flex;
    align-items: center;
    font-size: var(--texto-sm);
}

.breadcrumb-item + .breadcrumb-item::before {
    content: "›";
    color: var(--gray-400);
    padding: 0 var(--espacio-3);
    font-size: var(--texto-md);
}

.breadcrumb-item a {
    color: var(--primary-color);
    text-decoration: none;
    transition: var(--transition-fast);
    font-weight: 500;
}

.breadcrumb-item a:hover {
    color: var(--primary-dark);
    text-decoration: underline;
}

.breadcrumb-item.active {
    color: var(--gray-600);
    font-weight: 600;
}

/* ========================================
   TÍTULOS Y HEADERS
   ======================================== */
h1, h2, h3, h4, h5, h6 {
    color: var(--gray-700);
    font-weight: var(--peso-bold);
    margin-bottom: var(--espacio-4);
}

h1 {
    font-size: var(--texto-2xl);
    display: flex;
    align-items: center;
    gap: var(--espacio-3);
}

h2 {
    font-size: var(--texto-xl);
    display: flex;
    align-items: center;
    gap: var(--espacio-3);
}

h3 {
    font-size: var(--texto-lg);
}

h4 {
    font-size: var(--texto-md);
}

h1 i, h2 i, h3 i, h4 i {
    color: var(--primary-color);
}

/* ========================================
   CARDS Y CONTENEDORES
   ======================================== */
.card {
    background: var(--surface-card);
    border-radius: var(--radio-12);
    box-shadow: var(--shadow-md);
    border: none;
    margin-bottom: var(--espacio-5);
    transition: var(--transition-normal);
}

.card:hover {
    box-shadow: var(--shadow-lg);
    transform: translateY(-2px);
}

.card-header {
    background: var(--primary-gradient);
    color: var(--text-inverso);
    padding: var(--espacio-4) var(--espacio-5);
    border-radius: var(--radio-12) var(--radio-12) 0 0;
    font-weight: var(--peso-semibold);
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.card-body {
    padding: var(--espacio-5);
}

.card-footer {
    background: var(--gray-50);
    padding: var(--espacio-4) var(--espacio-5);
    border-radius: 0 0 var(--radio-12) var(--radio-12);
}

/* ========================================
   BOTONES ESTILIZADOS
   ======================================== */
.btn {
    padding: var(--espacio-3) var(--espacio-5);
    border: none;
    border-radius: var(--radio-8);
    font-weight: var(--peso-semibold);
    cursor: pointer;
    transition: var(--transition-normal);
    display: inline-flex;
    align-items: center;
    gap: var(--espacio-2);
    text-decoration: none;
    font-size: var(--texto-sm);
}

.btn:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

.btn:active {
    transform: translateY(0);
}

/* Botón primario — decisión fijada (ver /design-system, sección 3):
   carbón sólido, NO degradado (a diferencia de card-header/table
   thead/spinner, que sí heredan --primary-gradient con su nuevo valor
   carbón). Estados hover/activo explícitos, mismo patrón que
   .ds-btn-primario de la guía. */
.btn-primary {
    background: var(--color-accion-primaria);
    color: var(--text-inverso);
}

.btn-primary:hover {
    background: var(--color-accion-primaria-hover);
}

.btn-primary:active {
    background: var(--color-accion-primaria-activo);
}

.btn-success {
    background: var(--color-exito-superficie);
    color: var(--color-exito-superficie-texto);
}

.btn-warning {
    background: var(--color-advertencia-superficie);
    color: var(--color-advertencia-superficie-texto);
}

/* Destructivo — decisión fijada: SIEMPRE outline, nunca relleno (un
   destructivo sólido le gana peso visual a la acción primaria). */
.btn-danger {
    background: transparent;
    border: 1px solid var(--color-destructivo);
    color: var(--color-destructivo);
}

.btn-danger:hover {
    background: var(--color-destructivo-fondo);
}

/* La familia "info" (azul/cian) se absorbe en --color-neutro-* — mismo
   criterio ya usado en .badge-info/.alert-info: la Propuesta C no
   reserva un acento cromático para "información", así que no se
   inventa un color nuevo (decisión de sistema, pasada final de
   coherencia, hallazgo #3/#4 de AJUSTES-PENDIENTES.md). */
.btn-info {
    background: var(--color-neutro-superficie);
    color: var(--color-neutro-superficie-texto);
}

.btn-info:hover {
    background: var(--color-neutro-texto);
}

.btn-secondary {
    background: var(--color-accion-secundaria-fondo);
    color: var(--color-accion-secundaria-texto);
}

.btn-secondary:hover {
    background: var(--color-accion-secundaria-fondo-hover);
}

.btn-outline-primary {
    background: transparent;
    border: 2px solid var(--color-accion-primaria);
    color: var(--color-accion-primaria);
}

.btn-outline-primary:hover {
    background: var(--color-accion-primaria);
    color: var(--text-inverso);
}

.btn-sm {
    padding: var(--espacio-1) var(--espacio-3);
    font-size: var(--texto-sm);
}

.btn-lg {
    padding: var(--espacio-3) var(--espacio-6);
    font-size: var(--texto-base);
}

/* ========================================
   BADGES
   ======================================== */
.badge {
    padding: var(--espacio-1) var(--espacio-3);
    border-radius: var(--radio-20);
    font-size: var(--texto-xs);
    font-weight: var(--peso-semibold);
    text-transform: uppercase;
    letter-spacing: var(--interletra-amplia);
    display: inline-block;
}

/* "Primario" no es un estado de éxito/advertencia/destructivo — es
   carbón sólido, y a diferencia de esos tres SÍ funciona con texto
   blanco (12.68:1), así que no necesita el patrón pastel. */
.badge-primary {
    background: var(--color-accion-primaria);
    color: var(--text-inverso);
}

/* Patrón pastel (fondo -100 + texto -900) — decisión fijada en
   /design-system, sección 4 "Badges": verde/amarillo CGT no soportan
   texto blanco en ningún escalón reconocible como el color de marca. */
.badge-success, .badge-activo {
    background: var(--color-exito-fondo);
    color: var(--color-exito-texto);
}

.badge-warning, .badge-inactivo {
    background: var(--color-advertencia-fondo);
    color: var(--color-advertencia-texto);
}

.badge-danger, .badge-fallecido {
    background: var(--color-destructivo-fondo);
    color: var(--color-destructivo-texto);
}

/* Sin estado de éxito/advertencia/destructivo ni color de marca propio
   (info/secondary) — familia --color-neutro-*, ver §3.4 de
   SISTEMA-DISENO.md. */
.badge-info,
.badge-secondary {
    background: var(--color-neutro-fondo);
    color: var(--color-neutro-texto);
}

/* Badges de jerarquía — categoría, no estado (nunca rojo/verde/amarillo
   CGT, reservados a éxito/advertencia/destructivo). Ver el token
   --badge-jerarquia-* arriba para la elección de escalones y sus ratios
   de contraste; §3.4 de SISTEMA-DISENO.md documenta cuándo usar esta
   familia en vez del patrón pastel de estado. 1 = mayor jerarquía
   (fondo más oscuro), 6 = nivel base (fondo más claro). */
.badge-jerarquia-1 {
    background: var(--badge-jerarquia-1);
    color: var(--badge-jerarquia-1-texto);
}

.badge-jerarquia-2 {
    background: var(--badge-jerarquia-2);
    color: var(--badge-jerarquia-2-texto);
}

.badge-jerarquia-3 {
    background: var(--badge-jerarquia-3);
    color: var(--badge-jerarquia-3-texto);
}

.badge-jerarquia-4 {
    background: var(--badge-jerarquia-4);
    color: var(--badge-jerarquia-4-texto);
}

.badge-jerarquia-5 {
    background: var(--badge-jerarquia-5);
    color: var(--badge-jerarquia-5-texto);
}

.badge-jerarquia-6 {
    background: var(--badge-jerarquia-6);
    color: var(--badge-jerarquia-6-texto);
}

/* ========================================
   TABLAS PROFESIONALES
   ======================================== */
.table-responsive {
    overflow-x: auto;
    border-radius: var(--radio-8);
    box-shadow: var(--shadow-sm);
}

.table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--texto-sm);
}

/* Carbón sólido — NO el degradado heredado de --primary-gradient.
   Resuelve además el fallo de contraste que reportó el piloto de
   Censo: el extremo claro del degradado púrpura daba 3.66:1 con texto
   blanco (bajo el mínimo de 4.5:1 para texto normal); el carbón da
   12.68:1. */
.table thead {
    background: var(--color-accion-primaria);
    color: var(--text-inverso);
}

.table th {
    padding: var(--espacio-3);
    text-align: left;
    font-weight: var(--peso-semibold);
    font-size: var(--texto-sm);
    text-transform: uppercase;
    letter-spacing: var(--interletra-amplia);
    white-space: nowrap;
}

.table th:first-child {
    border-radius: var(--radio-8) 0 0 0;
    padding-left: var(--espacio-5);
}

.table th:last-child {
    border-radius: 0 var(--radio-8) 0 0;
    padding-right: var(--espacio-5);
}

.table tbody tr {
    border-bottom: 1px solid var(--gray-100);
    transition: var(--transition-fast);
}

.table tbody tr:hover {
    background-color: var(--gray-50);
}

.table tbody tr:last-child {
    border-bottom: none;
}

.table td {
    padding: var(--espacio-3);
    vertical-align: middle;
}

.table td:first-child {
    padding-left: var(--espacio-5);
}

.table td:last-child {
    padding-right: var(--espacio-5);
}

/* ========================================
   FORMULARIOS ESTILIZADOS
   ======================================== */
.form-label {
    display: block;
    font-weight: var(--peso-semibold);
    color: var(--gray-600);
    margin-bottom: var(--espacio-1);
    font-size: var(--texto-sm);
}

.form-control,
.form-select {
    width: 100%;
    padding: var(--espacio-3) var(--espacio-3);
    border: 1px solid var(--gray-200);
    border-radius: var(--radio-6);
    font-size: var(--texto-sm);
    transition: var(--transition-fast);
}

/* Foco carbón — decisión fijada: NUNCA púrpura/rojo, sigue a la acción
   primaria (ver §3.3 de SISTEMA-DISENO.md). El box-shadow de foco era
   un rgba() de púrpura hardcodeado, no una variable. */
.form-control:focus,
.form-select:focus {
    outline: none;
    border-color: var(--borde-input-foco);
    box-shadow: 0 0 0 3px var(--color-foco-anillo);
}

.form-control:disabled,
.form-select:disabled {
    background-color: var(--gray-100);
    cursor: not-allowed;
}

.form-control-sm {
    padding: var(--espacio-1) var(--espacio-3);
    font-size: var(--texto-sm);
}

.form-control-lg {
    padding: var(--espacio-3) var(--espacio-4);
    font-size: var(--texto-base);
}

/* ========================================
   VALIDACIONES
   ======================================== */
/* #26b050/#e50000 son un TERCER verde/rojo fuera de la familia CGT
   (MAPEO-COLORES.md los deja como "requiere criterio" — #e50000 en
   particular, sin resolver a nivel de sistema). Se migran al verde/rojo
   CGT ya oficiales porque dejarlos hardcodeados contradice el objetivo
   de esta migración; queda como decisión tomada bajo este alcance, no
   como resolución formal del caso "requiere criterio" — reportado en
   la entrega de esta tarea. */
.valid.modified:not([type=checkbox]) {
    border-color: var(--color-exito);
    outline: 1px solid var(--color-exito);
}

.invalid {
    border-color: var(--color-destructivo);
    outline: 1px solid var(--color-destructivo);
}

.validation-message {
    color: var(--color-destructivo-texto);
    font-size: var(--texto-xs);
    margin-top: var(--espacio-1);
    display: block;
}

/* ========================================
   ALERTAS
   ======================================== */
.alert {
    padding: var(--espacio-4) var(--espacio-5);
    border-radius: var(--radio-8);
    margin-bottom: var(--espacio-5);
    display: flex;
    align-items: center;
    gap: var(--espacio-3);
    font-size: var(--texto-sm);
}

.alert i {
    font-size: var(--icono-sm);
}

/* Fondo pastel plano (no degradado rgba) + borde de acento — mismo
   patrón que /design-system, sección 8 "Alertas". */
.alert-success {
    background: var(--color-exito-fondo);
    border-left: 4px solid var(--color-exito);
    color: var(--color-exito-texto);
}

.alert-danger {
    background: var(--color-destructivo-fondo);
    border-left: 4px solid var(--color-destructivo);
    color: var(--color-destructivo-texto);
}

.alert-warning {
    background: var(--color-advertencia-fondo);
    border-left: 4px solid var(--color-advertencia);
    color: var(--color-advertencia-texto);
}

/* Sin color CGT propio para "información" — familia --color-neutro-*,
   igual que la alerta informativa de /design-system. */
.alert-info {
    background: var(--color-neutro-fondo);
    border-left: 4px solid var(--color-neutro);
    color: var(--color-neutro-texto);
}

/* ========================================
   LOADING / SPINNER
   ======================================== */
/* display: inline-block es necesario para que .text-center (que solo
   centra contenido inline) pueda centrar el spinner -- sin esto, el
   <div> quedaba en su display de bloque por defecto (ancho completo,
   pegado al borde izquierdo) en cada "Cargando..." del sitio, mientras
   el texto de abajo sí se veía centrado (es contenido inline dentro de
   su <p>). El color ya es --primary-color (carbón), nunca negro puro. */
.spinner-border {
    display: inline-block;
    border: 4px solid var(--gray-100);
    border-top: 4px solid var(--primary-color);
    border-radius: var(--radio-full);
    width: 40px;
    height: 40px;
    animation: spin 1s linear infinite;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

.text-center {
    text-align: center;
}

.py-5 {
    padding-top: var(--espacio-10);
    padding-bottom: var(--espacio-10);
}

/* ========================================
   UTILIDADES
   ======================================== */
.text-muted {
    color: var(--gray-400);
}

.text-primary {
    color: var(--primary-color);
}

/* Tokens -texto (no los "-superficie"/-solos): esta clase se usa sobre
   texto arbitrario, que necesita 4.5:1 — verde/rojo/amarillo CGT en su
   ancla no alcanzan ese mínimo (ver §3.4 de SISTEMA-DISENO.md). */
.text-success {
    color: var(--color-exito-texto);
}

.text-danger {
    color: var(--color-destructivo-texto);
}

.text-warning {
    color: var(--color-advertencia-texto);
}

.mb-1 { margin-bottom: var(--espacio-1); }
.mb-2 { margin-bottom: var(--espacio-3); }
.mb-3 { margin-bottom: var(--espacio-4); }
.mb-4 { margin-bottom: var(--espacio-5); }
.mb-5 { margin-bottom: var(--espacio-8); }

.mt-1 { margin-top: var(--espacio-1); }
.mt-2 { margin-top: var(--espacio-3); }
.mt-3 { margin-top: var(--espacio-4); }
.mt-4 { margin-top: var(--espacio-5); }
.mt-5 { margin-top: var(--espacio-8); }

.p-1 { padding: var(--espacio-1); }
.p-2 { padding: var(--espacio-3); }
.p-3 { padding: var(--espacio-4); }
.p-4 { padding: var(--espacio-5); }
.p-5 { padding: var(--espacio-8); }

.d-flex { display: flex; }
.align-items-center { align-items: center; }
.justify-content-between { justify-content: space-between; }
.justify-content-center { justify-content: center; }
.gap-1 { gap: var(--espacio-1); }
.gap-2 { gap: var(--espacio-3); }
.gap-3 { gap: var(--espacio-4); }

/* ========================================
   FORMULARIOS - LAYOUT Y SECCIONES
   ======================================== */
.form-page-container {
    max-width: 900px;
    margin: 0 auto;
    padding: var(--espacio-6) 0;
}

.form-page-header {
    margin-bottom: var(--espacio-6);
}

.form-page-header h2 {
    margin-bottom: var(--espacio-2);
}

.form-section {
    border: 1px solid var(--gray-200);
    border-radius: var(--radio-8);
    margin-bottom: var(--espacio-5);
    overflow: hidden;
}

/* Fondo/borde neutros — no lleva el lavado púrpura hardcodeado del
   original (una superficie grande no lleva acento de marca, §6.3 de
   SISTEMA-DISENO.md). color: var(--primary-color) ya hereda carbón. */
.form-section-header {
    background: var(--surface-sunken);
    border-bottom: 2px solid var(--borde-sutil);
    padding: var(--espacio-3) var(--espacio-5);
    display: flex;
    align-items: center;
    gap: var(--espacio-2);
    font-weight: var(--peso-semibold);
    font-size: var(--texto-sm);
    color: var(--primary-color);
    text-transform: uppercase;
    letter-spacing: var(--interletra-amplia);
}

.form-section-header i {
    font-size: var(--icono-xs);
}

.form-section-body {
    padding: var(--espacio-5);
    background: var(--surface-card);
    display: flex;
    flex-direction: column;
    gap: var(--espacio-4);
}

.form-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--espacio-4) var(--espacio-5);
}

.form-grid-1 {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--espacio-4);
}

.form-grid-3 {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--espacio-4) var(--espacio-5);
}

.form-grid-4 {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--espacio-4) var(--espacio-5);
}

.field-span-2 {
    grid-column: span 2;
}

.field-span-full {
    grid-column: 1 / -1;
}

.form-field {
    display: flex;
    flex-direction: column;
}

.form-actions {
    display: flex;
    align-items: center;
    gap: var(--espacio-3);
    padding: var(--espacio-5);
    background: var(--gray-50);
    border-top: 1px solid var(--gray-200);
    border-radius: 0 0 var(--radio-12) var(--radio-12);
    flex-wrap: wrap;
}

.input-group {
    display: flex;
    align-items: stretch;
}

.input-group-text {
    display: flex;
    align-items: center;
    padding: var(--espacio-2) var(--espacio-3);
    font-size: var(--texto-sm);
    background-color: var(--gray-50);
    border: 1px solid var(--gray-200);
    border-right: none;
    border-radius: var(--radio-6) 0 0 var(--radio-6);
    color: var(--gray-500);
}

.input-group .form-control {
    flex: 1;
    border-radius: var(--radio-6) 0 0 var(--radio-6);
}

.input-group-text + .form-control {
    border-left: none;
    border-radius: 0 !important;
}

.input-group .form-control:last-child {
    border-radius: 0 var(--radio-6) var(--radio-6) 0 !important;
}

.input-group .btn {
    border-radius: 0 var(--radio-6) var(--radio-6) 0;
    padding: var(--espacio-2) var(--espacio-3);
    transform: none;
    box-shadow: none;
}

.input-group .btn:hover {
    transform: none;
    box-shadow: none;
    opacity: 0.85;
}

@media (max-width: 768px) {
    .form-page-container {
        padding: 1rem 0;
    }

    .form-grid,
    .form-grid-3,
    .form-grid-4 {
        grid-template-columns: 1fr;
    }

    .field-span-2,
    .field-span-full {
        grid-column: span 1;
    }
}

@media (min-width: 769px) and (max-width: 992px) {
    .form-grid-4 {
        grid-template-columns: repeat(2, 1fr);
    }

    .form-grid-3 {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* ========================================
   UTILIDADES ADICIONALES
   ======================================== */

/* Texto */
.text-end { text-align: right; }
.text-start { text-align: left; }
.text-info { color: var(--color-neutro-texto); }
.text-white { color: white; }

/* Tipografía */
.fw-bold { font-weight: var(--peso-bold); }
.fw-semibold { font-weight: var(--peso-semibold); }
.fw-normal { font-weight: var(--peso-normal); }
.small { font-size: 0.875em; }
.fs-2 { font-size: var(--texto-2xl); }
.fs-4 { font-size: var(--texto-xl); }
.display-6 { font-size: var(--texto-3xl); font-weight: var(--peso-normal); }

/* Márgenes direccionales */
.me-1 { margin-right: var(--espacio-1); }
.me-2 { margin-right: var(--espacio-3); }
.me-3 { margin-right: var(--espacio-4); }
.ms-1 { margin-left: var(--espacio-1); }
.ms-2 { margin-left: var(--espacio-3); }
.ms-3 { margin-left: var(--espacio-4); }
.mx-auto { margin-left: auto; margin-right: auto; }

/* Padding */
.p-0 { padding: 0 !important; }
.px-4 { padding-left: var(--espacio-5); padding-right: var(--espacio-5); }

/* Dimensiones */
.h-100 { height: 100%; }
.w-100 { width: 100%; }

/* Bordes y sombras */
.rounded-circle { border-radius: var(--radio-full) !important; }
.rounded { border-radius: var(--radio-8); }
.border-0 { border: none !important; }
.shadow-sm { box-shadow: var(--shadow-sm) !important; }

/* Fondos */
.bg-white { background-color: var(--surface-card) !important; }
.bg-light { background-color: var(--gray-50) !important; }
.bg-secondary { background-color: var(--gray-500) !important; }
.bg-success { background-color: var(--color-exito-superficie) !important; }
.bg-danger { background-color: var(--color-destructivo-superficie) !important; }
.bg-info { background-color: var(--color-neutro-superficie) !important; }
.bg-primary { background: var(--primary-gradient) !important; }
.bg-opacity-10 { opacity: 1; }

/* Flex adicional */
.flex-column { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }
.align-self-center { align-self: center; }

/* Botones outline faltantes */
.btn-outline-secondary {
    background: transparent;
    border: 2px solid var(--gray-400);
    color: var(--gray-500);
}

.btn-outline-secondary:hover {
    background: var(--color-accion-secundaria-fondo);
    color: var(--color-accion-secundaria-texto);
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

.btn-outline-danger {
    background: transparent;
    border: 2px solid var(--color-destructivo);
    color: var(--color-destructivo);
}

.btn-outline-danger:hover {
    background: var(--color-destructivo-fondo);
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

/* verde-cgt-600 no alcanza 4.5:1 con texto blanco (2.66:1) — el hover
   usa la superficie sólida con texto oscuro, mismo patrón que
   .btn-success (ver §3.4 de SISTEMA-DISENO.md). */
.btn-outline-success {
    background: transparent;
    border: 2px solid var(--color-exito);
    color: var(--color-exito);
}

.btn-outline-success:hover {
    background: var(--color-exito-superficie);
    color: var(--color-exito-superficie-texto);
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

/* Progress bar */
.progress {
    background-color: var(--gray-200);
    border-radius: var(--radio-full);
    overflow: hidden;
    height: 8px;
}

.progress-bar {
    height: 100%;
    transition: width var(--transition-normal);
    background: var(--primary-gradient);
}

/* Variantes de estado: sin migrar a nivel de variable en esta fase
   (--success/danger/warning-gradient no se tocaron, ver §1.3 de
   SISTEMA-DISENO.md) — siguen en la paleta legacy hasta que se decida
   si esta clase compuesta entra en el mismo alcance que .btn-*/.badge-*.
   .bg-info es la excepción: la familia "info" sí se resolvió en esta
   pasada (absorbida en --color-neutro-*, ver .btn-info arriba), así que
   se adelanta también acá — sin degradado, consistente con el resto de
   los tokens ya migrados del sistema. */
.progress-bar.bg-info { background: var(--color-neutro-superficie); }
.progress-bar.bg-success { background: var(--success-gradient); }
.progress-bar.bg-danger { background: var(--danger-gradient); }
.progress-bar.bg-warning { background: var(--warning-gradient); }

/* Flex utilities */
.flex-grow-1 { flex-grow: 1; }
.flex-shrink-0 { flex-shrink: 0; }

/* Additional backgrounds */
.bg-warning { background-color: var(--color-advertencia-superficie) !important; }
/* #fd7e14 (naranja Bootstrap suelto) sin token propio — MAPEO-COLORES.md
   lo deja como "requiere criterio". Forzado al más cercano ya oficial
   (mismo criterio que Censo con casos análogos), pendiente de decisión
   formal — ver reporte de esta tarea. */
.bg-orange { background-color: var(--color-advertencia-superficie) !important; }

/* Additional text */
.text-dark { color: var(--gray-700) !important; }

/* Form select sizes */
.form-select-sm {
    padding: var(--espacio-1) var(--espacio-8) var(--espacio-1) var(--espacio-2);
    font-size: var(--texto-sm);
}

/* Button outline warning — amarillo-cgt-600 no alcanza 3:1 como borde/
   texto (1.52:1, ver §3.4 de SISTEMA-DISENO.md), así que el borde/texto
   usa el escalón 900 (5.40:1) y el hover llena con la superficie
   sólida + texto oscuro, mismo patrón que .btn-warning. */
.btn-outline-warning {
    background: transparent;
    border: 2px solid var(--color-advertencia-texto);
    color: var(--color-advertencia-texto);
}

.btn-outline-warning:hover {
    background: var(--color-advertencia-superficie);
    color: var(--color-advertencia-superficie-texto);
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

/* ========================================
   SISTEMA DE GRILLA (row / col / container)
   Backfill de hallazgo #13 (AJUSTES-PENDIENTES.md): el proyecto nunca
   cargó Bootstrap real, así que estas clases nunca tuvieron una
   definición propia. Reimplementación acotada a lo que el proyecto
   usa de verdad (auditado por grep sobre Components/), no la
   especificación completa de Bootstrap. Técnica de gutter con
   variable CSS + padding en los hijos directos de .row (no gap:
   combinar gap con flex-basis en % desbordaría el ancho del row) —
   mismo patrón que usa Bootstrap real.
   ======================================== */
.container {
    width: 100%;
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 var(--espacio-4);
}

.container-fluid {
    width: 100%;
    margin: 0 auto;
    padding: 0 var(--espacio-4);
}

.row {
    --grilla-gutter: var(--espacio-6);
    display: flex;
    flex-wrap: wrap;
    margin-left: calc(var(--grilla-gutter) / -2);
    margin-right: calc(var(--grilla-gutter) / -2);
}

/* width:100% de base (apilado a ancho completo) para cualquier hijo
   directo de .row, igual que Bootstrap real -- necesario para
   elementos que solo llevan una clase con prefijo de breakpoint (p.ej.
   "col-md-6 col-lg-5" sin un .col/.col-N base, como en
   CambiarPassword.razor): por debajo de md ninguna regla de columna
   aplica, y sin este fallback el elemento quedaría sin ancho definido. */
.row > * {
    flex-shrink: 0;
    width: 100%;
    padding-left: calc(var(--grilla-gutter) / 2);
    padding-right: calc(var(--grilla-gutter) / 2);
}

.g-2 { --grilla-gutter: var(--espacio-2); }
.g-3 { --grilla-gutter: var(--espacio-3); }
.g-4 { --grilla-gutter: var(--espacio-4); }

/* Utilidad de gap genérica (no ligada al gutter de .row) — usada sobre
   contenedores flex sueltos, no sobre .row. */
.gap-4 { gap: var(--espacio-4); }

.col {
    flex: 1 0 0%;
}

.col-auto {
    flex: 0 0 auto;
    width: auto;
}

.col-2  { flex: 0 0 auto; width: 16.6667%; }
.col-5  { flex: 0 0 auto; width: 41.6667%; }
.col-6  { flex: 0 0 auto; width: 50%; }
.col-12 { flex: 0 0 auto; width: 100%; }

@media (min-width: 576px) {
    .col-sm-5 { flex: 0 0 auto; width: 41.6667%; }
    .col-sm-7 { flex: 0 0 auto; width: 58.3333%; }
}

@media (min-width: 768px) {
    .col-md-2  { flex: 0 0 auto; width: 16.6667%; }
    .col-md-3  { flex: 0 0 auto; width: 25%; }
    .col-md-4  { flex: 0 0 auto; width: 33.3333%; }
    .col-md-6  { flex: 0 0 auto; width: 50%; }
    .col-md-8  { flex: 0 0 auto; width: 66.6667%; }
    .col-md-9  { flex: 0 0 auto; width: 75%; }
    .col-md-10 { flex: 0 0 auto; width: 83.3333%; }
    .col-md-12 { flex: 0 0 auto; width: 100%; }
}

@media (min-width: 992px) {
    .col-lg-4 { flex: 0 0 auto; width: 33.3333%; }
    .col-lg-5 { flex: 0 0 auto; width: 41.6667%; }
}

@media (min-width: 1200px) {
    .col-xl-4 { flex: 0 0 auto; width: 33.3333%; }
}

/* ========================================
   MODAL — wrapper de posicionamiento
   Backfill de hallazgo #13. Solo el overlay y el contenedor centrado
   (.modal-content/-header/-body ya están resueltos donde se usan, con
   sus propios overrides locales — no se tocan acá). El color de fondo
   del overlay se fija inline por archivo (--overlay-oscuro-55, ya
   establecido); .modal solo aporta el posicionamiento fijo. .fade/.show
   se renderizan siempre juntos (el modal es condicional por @if de
   Blazor, no se alterna por clase), así que solo garantizan opacidad
   plena sin transición visible.
   ======================================== */
.modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 1050;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: var(--espacio-8) var(--espacio-4);
    overflow-y: auto;
}

.modal-dialog {
    width: 100%;
    max-width: 500px;
    margin: 0 auto;
}

.fade {
    transition: opacity 0.15s linear;
    opacity: 1;
}

.fade:not(.show) {
    opacity: 0;
}

/* ========================================
   FORM-CHECK / FORM-SWITCH
   Backfill de hallazgo #13. Checkbox nativo restilizado (appearance:
   none) en vez de pseudo-elementos sobre el propio <input> (soporte
   cross-browser poco confiable) — mismo enfoque que usa Bootstrap
   real, con radial-gradient para el punto del thumb en vez de un SVG
   con color hardcodeado, para que todo color siga saliendo de tokens.
   El color de estado activo (--color-accion-primaria) ya lo fijan
   localmente varios formularios (Directivas/Sindicatos/Usuarios
   Crear/Editar) vía .form-check-input:checked -- esta base solo cubre
   el layout/interacción del toggle que a esos archivos les faltaba.
   ======================================== */
.form-check {
    display: block;
    min-height: var(--espacio-6);
    padding-left: 1.5em;
    margin-bottom: var(--espacio-2);
}

.form-check .form-check-input {
    float: left;
    margin-left: -1.5em;
}

.form-check-input {
    width: 1em;
    height: 1em;
    margin-top: 0.25em;
    vertical-align: top;
    background-color: var(--surface-card);
    border: 1px solid var(--borde-input);
    border-radius: var(--radio-4);
    appearance: none;
    cursor: pointer;
    transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
}

.form-check-input:checked {
    background-color: var(--color-accion-primaria);
    border-color: var(--color-accion-primaria);
}

.form-check-input:focus {
    outline: none;
    box-shadow: 0 0 0 3px var(--color-foco-anillo);
}

.form-check-label {
    cursor: pointer;
}

.form-switch {
    padding-left: 2.75em;
}

.form-switch .form-check-input {
    width: 2.5em;
    height: 1.25em;
    margin-left: -2.75em;
    border-radius: var(--radio-full);
    background-color: var(--gris-300);
    border-color: var(--gris-300);
    background-image: radial-gradient(circle 0.4em, var(--blanco-absoluto) 100%, transparent 100%);
    background-position: 0.15em center;
    background-repeat: no-repeat;
    transition: background-position 0.15s ease-in-out, background-color 0.15s ease-in-out;
}

.form-switch .form-check-input:checked {
    background-position: calc(100% - 0.15em) center;
}

.form-text {
    display: block;
    font-size: var(--texto-sm);
    color: var(--text-muted);
    margin-top: var(--espacio-1);
}

/* ========================================
   VARIANTES DE TABLA
   Backfill de hallazgo #13. Mismos tokens que el thead ya migrado en
   todo el sistema (--gris-50 + --text-secondary, NO un encabezado
   carbón) para que las filas moduladoras no choquen visualmente.
   ======================================== */
.table-hover tbody tr:hover {
    background-color: var(--surface-sunken);
}

.table-light td,
.table-light th {
    background-color: var(--gris-50);
}

.table-secondary td,
.table-secondary th {
    background-color: var(--gris-100);
}

.table-sm th,
.table-sm td {
    padding: var(--espacio-1) var(--espacio-2);
}

/* ========================================
   POSICIONAMIENTO / TOAST
   Backfill de hallazgo #13. Sin color propio -- solo posicionamiento,
   igual que .d-flex/.mb-3/.gap-3 (utilidades estructurales sin
   !important en este archivo; el !important queda reservado para las
   utilidades de color, que sí necesitan ganarle a selectores más
   específicos como .card-header).
   ======================================== */
.position-fixed { position: fixed; }
.position-absolute { position: absolute; }
.position-relative { position: relative; }
.bottom-0 { bottom: 0; }
.end-0 { right: 0; }

.toast-body {
    padding: var(--espacio-3) var(--espacio-4);
}

/* ========================================
   BLAZOR ERROR BOUNDARY
   ======================================== */
.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

.blazor-error-boundary::after {
    content: "An error has occurred."
}

/* ========================================
   RESPONSIVE
   ======================================== */
@media (max-width: 768px) {
    h1 { font-size: var(--texto-xl); }
    h2 { font-size: var(--texto-lg); }
    h3 { font-size: var(--texto-md); }

    .btn {
        padding: var(--espacio-2) var(--espacio-4);
        font-size: var(--texto-sm);
    }

    .card-header,
    .card-body,
    .card-footer {
        padding: var(--espacio-4);
    }
}

@media (max-width: 576px) {
    :root {
        font-size: var(--texto-sm);
    }

    h1 { font-size: var(--texto-lg); }
    h2 { font-size: var(--texto-md); }

    .table th,
    .table td {
        padding: var(--espacio-2);
    }
}
/* Layout principal - Estilos críticos para el sidebar.
   .page es ahora siempre columna (franja de marca + .page-body, ver
   MainLayout.razor.css) — el rol de alternar fila/columna según el
   breakpoint pasó a .page-body. Esta regla !important tenía el
   selector viejo (.page) y forzaba fila en escritorio incluso encima
   de la franja, empujando sidebar+contenido a la derecha en vez de
   debajo — bug corregido apuntando al selector correcto. */
.page {
    position: relative;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

@media (min-width: 641px) {
    .page-body {
        flex-direction: row !important;
    }

    .sidebar {
        width: 250px !important;
        min-width: 250px !important;
        max-width: 250px !important;
        height: 100vh !important;
        position: sticky !important;
        top: 0 !important;
        flex-shrink: 0 !important;
        overflow-y: auto;
    }

    main {
        flex: 1 !important;
        min-width: 0 !important;
        width: calc(100% - 250px) !important;
    }
}