/* ============================================================
   SIGA Design System — Warm Coral
   Inspired by "TheGem Mobile App Landing": cálido, limpio, luminoso
   Modo claro por defecto, modo oscuro = warm brown
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap');

/* ============================================================
   TOKENS (light theme = default)
   ============================================================ */
:root {
    /* Fondos */
    --bg-primary:    #FFFFFF;
    --bg-secondary:  #FDF5F0;
    --bg-tertiary:   #F8F0EB;
    --bg-sidebar:    #FFFFFF;
    --bg-header:     #FFFFFF;
    --bg-page:       var(--bg-secondary);

    /* Texto */
    --text-primary:    #1a1a1a;
    --text-secondary:  #716867;
    /* Era #a39e9d → 2.65:1 sobre blanco (AA exige 4.5). #76706E da 4.87:1.
       El techo lo pone --text-secondary (5.41:1): si el terciario fuera MÁS
       oscuro que el secundario se invertiría la jerarquía visual, así que el
       rango disponible es 4.5–5.41 y se toma el punto medio. */
    --text-tertiary:   #76706E;
    --text-muted:      var(--text-tertiary);

    /* Acento coral.
       ⚠️ DOS tokens, y no uno, porque son DOS TRABAJOS DISTINTOS:
         --accent        rellenos, puntos, barras, íconos, bordes.
         --accent-texto  CUALQUIER texto en coral sobre fondo claro.
       `#FF6B4A` es un color de relleno: medido sobre el render da **2,82:1
       sobre blanco** y **2,62:1 sobre el crema #FDF5F0** — no llega ni al 3:1
       de elementos no textuales, mucho menos al 4,5:1 de texto. No hay que
       cambiar la marca; hay que dejar de usar el mismo valor para las dos
       cosas. `#C53616` conserva el hue exacto (11°) bajando la luminosidad:
       5,37:1 sobre blanco y 4,98:1 sobre crema.
       En OSCURO no hace falta: #FF6B4A ya da 6,43:1 sobre #1a1512. */
    --accent:           #FF6B4A;
    --accent-texto:     #C53616;
    --accent-hover:     #E85A3A;
    --accent-light:     #FFF0ED;
    --accent-secondary: #FFB347;

    /* HUE de las sombras cálidas — ÚNICA FUENTE.
       hsl(20 27.3% 21.6%) reproduce EXACTAMENTE rgb(70,50,40), que es el
       marrón que ya usaba --shadow-glass de Aurora. Antes había dos marrones
       distintos y dos escalas de elevación compitiendo; ahora Aurora deriva
       --shadow-glass de este token en vez de llevar su propio hex.
       ⚠️ No confundir con --shadow (rgba(113,104,103,.08)), que es la escala
       del tema CLÁSICO y se conserva tal cual: cambiarla movería el aspecto
       de toda la app, que no es lo que se pide acá. */
    --sombra-hsl: 20deg 27.3% 21.6%;

    /* Estados */
    --success: #22c55e;
    --warning: #f59e0b;
    --danger:  #ef4444;
    --info:    #3b82f6;

    /* ---- Colores de ESTADO para NÚMEROS de KPI ----
       Se conserva el código de color; se corrigen los tonos. Medidos sobre la
       superficie glass RESUELTA (82 % compuesto sobre el fondo real), no sobre
       blanco puro: a 32px/600 califican como texto grande (3:1), pero sobre
       glass el fondo efectivo varía y ese margen no existe. Objetivo ≥4,5:1
       en los 4 modos, tomando el paso MÁS CERCANO al color de marca que
       cumple, para no ensuciar la paleta más de lo necesario.
       En CLARO ya cumplían rojo/azul/violeta/índigo; en OSCURO ya cumplían
       ámbar/verde/naranja/cian. Cada tema ajusta sólo la otra mitad. */
    --estado-ambar:   #AC5F05;   /* 4,70 Aurora · 4,79 clásico */
    --estado-verde:   #12843C;   /* 4,72 · 4,81 */
    --estado-naranja: #C84B0A;   /* 4,61 · 4,69 */
    --estado-rojo:    #DC2626;   /* 4,77 · 4,83 — el de marca ya cumple */
    --estado-azul:    #2563EB;   /* 5,10 · 5,17 — ya cumple */
    --estado-violeta: #7C3AED;   /* 5,62 · 5,70 — ya cumple */
    --estado-indigo:  #4F46E5;   /* 6,20 · 6,29 — ya cumple */
    --estado-cian:    #0A7AAD;   /* 4,66 · 4,75 */
    /* Un contador en CERO no es una alerta: va en tinta neutra. */
    --estado-neutro:  var(--text-secondary);
    /* ⚠️ Estos ocho son tonos de TEXTO — la tinta del NÚMERO de un KPI
       (siga_kpi_tinta). Ya NO se usan como relleno de ícono: ver el bloque
       "COLOR DE ÍCONO DE KPI" acá abajo, que es otra escala y otro trabajo. */

    /* Superficie apagada genérica. ⚠️ Se declara UNA sola vez por tema, acá y
       en [data-theme="dark"]. El puente de Aurora la remapeaba a --surface-2,
       que en claro es #FFFFFF: el ícono de un contador en cero quedaba blanco
       sobre tarjeta blanca, 1,01:1. Esa línea del puente se eliminó. */
    --surface-muted: #EFEAE7;

    /* ---- COLOR DE ÍCONO DE KPI: agrupa por FAMILIA, no por estado ----
       Cinco colores para todos los módulos. El color de un ícono NUNCA cambia
       con el dato (sólo se apaga en cero), y por eso no puede leerse como
       estado: el estado implica cambio. El estado lo dicen la tinta del número
       (--estado-*), el borde is-alerta y el texto.

       La paleta pasó los seis checks del validador (banda de luminosidad, piso
       de croma, separación bajo protanopia/deuteranopia, piso de visión normal
       y contraste) en claro Y en oscuro, con separación mínima ΔE 11,0 bajo
       deuteranopia y 19,5 en visión normal. Es la MISMA en los dos modos: las
       variantes aclaradas para oscuro colapsan azul y violeta a ΔE 1,7.
       ⚠️ No sacar el verde aunque colisione con el hue de "éxito": sin él,
       azul y violeta caen a ΔE 2,9. Es estructural.

       Los nombres vienen del caso de COM, que es donde se diseñaron; el
       criterio general para los otros módulos es:
         dinero      → dinero, valor, volumen facturado
         clientes    → personas y terceros (asociados, candidatos, contactos)
         contratos   → documentos formales con vigencia (contratos, acuerdos,
                       acreditaciones, exámenes, planillas)
         puestos     → lugares, cobertura, inventario físico
         compromisos → trabajo pendiente, obligaciones, plazos, tickets     */
    --kpi-dinero:      #2A6FC9;
    --kpi-clientes:    #6B4FC0;
    --kpi-contratos:   #7A8A1F;
    --kpi-puestos:     #0E8F63;
    --kpi-compromisos: #C74F86;

    /* TINTE del disco y ARO del borde. Lo que hacía que la franja se viera
       "viva" no era el token: era el disco relleno saturado de 48px. El mismo
       token al 8 % es un lavado suave. Bajar la saturación del token en vez
       del tinte rompe la paleta (5 de 5 bajo el piso de croma).

       En CLARO el tinte y el glifo son el mismo color, así que subir el tinte
       acerca el disco al glifo y les baja el contraste entre sí — que es la
       única medición que la norma exige (WCAG G207). Barrido en claro: 8 %
       deja el mínimo en 3,46 y 18 % en 3,09. El 14 % da 3,24 con el disco más
       perceptible (1,17:1 contra la tarjeta, frente a 1,09 al 8 %), y ése es
       el punto elegido.

       El disco se arma mezclando el color con `--kpi-velo`. En CLARO el velo
       es transparente: el tinte se compone directo contra la tarjeta y aclara
       el disco. En OSCURO el velo es negro — ver el bloque del tema oscuro,
       donde está la razón.

       El ARO de 1px del propio color acompaña al relleno: entre los dos el
       disco se percibe sin necesidad de subir la intensidad. Es decorativo —
       la norma no le exige nada. */
    --kpi-tinte: 14%;
    --kpi-velo:  transparent;
    --kpi-aro:   40%;

    /* Estado APAGADO (contador en cero). Cálido, de la familia del crema: un
       gris neutro se lee como "elemento roto", y un cero que desaparece es
       peor que un cero que alarma — el usuario no sabe si la métrica existe o
       si el sistema se rompió. */
    --kpi-apagado-bg:  #E8E1DB;
    --kpi-apagado-ink: #6B635C;

    /* Bordes y sombras */
    --border:        #F0E8E4;
    --border-hover:  #E0D5D0;
    --shadow:        rgba(113, 104, 103, 0.08);
    --shadow-sm:     0 1px 2px var(--shadow);
    --shadow-md:     0 2px 12px var(--shadow);
    --shadow-lg:     0 8px 24px rgba(113, 104, 103, 0.12);
    --shadow-xl:     0 16px 40px rgba(113, 104, 103, 0.16);

    /* Tipografía */
    --font-sans: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

    /* Espaciado */
    --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;

    /* Radius */
    --radius-sm:   8px;
    --radius-md:   12px;
    --radius-lg:   16px;
    --radius-xl:   20px;
    --radius-2xl:  24px;
    --radius-pill: 999px;

    /* Transiciones */
    --t-fast:   0.15s ease;
    --t-normal: 0.3s ease;
    --t-slow:   0.5s ease;

    /* Layout */
    --sidebar-w:           260px;
    --sidebar-w-collapsed: 60px;
    --header-h:            64px;

    /* === Tokens legacy (compatibilidad con clases existentes) === */
    --color-primary:        var(--accent);
    --color-primary-light:  var(--accent);
    --color-primary-dark:   var(--accent-hover);
    --color-accent:         var(--accent);
    --color-accent-bright:  var(--accent-hover);
    --color-success:        var(--success);
    --color-warning:        var(--warning);
    --color-danger:         var(--danger);
    --color-info:           var(--info);

    --glass-bg:             var(--bg-primary);
    --glass-bg-strong:      var(--bg-primary);
    --glass-bg-hover:       var(--bg-secondary);
    --glass-border:         var(--border);
    --glass-border-strong:  var(--border-hover);
    --glass-shadow:         var(--shadow-md);
    --glass-blur:           none;

    --glow-accent:          0 0 0 3px rgba(255, 107, 74, 0.18);
    --glow-danger:          0 0 0 3px rgba(239, 68, 68, 0.18);

    --logo-cooserviunidos: url('../img/cooserviunidos-light.png');
}

/* ============================================================
   DARK THEME (warm brown, NOT cool blue)
   ============================================================ */
[data-theme="dark"] {
    --bg-primary:    #1a1512;
    --bg-secondary:  #241e19;
    --bg-tertiary:   #2e2620;
    --bg-sidebar:    #1a1512;
    --bg-header:     #1a1512;
    --bg-page:       var(--bg-secondary);

    --text-primary:    #F5EDE8;
    --text-secondary:  #B8ADA6;
    /* Era #8A7F79 → 4.65:1 sobre el fondo oscuro: pasaba AA por 0.15. #9D948F
       lo lleva a 6.05:1, con margen y sin llegar al secundario (8.25:1). */
    --text-tertiary:   #9D948F;
    --text-muted:      var(--text-tertiary);

    --accent-light:    rgba(255, 107, 74, 0.10);
    /* En oscuro el coral de marca YA pasa AA (6,43:1 sobre #1a1512, 5,85:1
       sobre #241e19): el token de texto apunta al mismo valor. */
    --accent-texto:    #FF6B4A;

    /* Colores de estado, juego OSCURO. Mismas familias, tonos más claros:
       sobre fondo oscuro el color de marca de los fríos no llega a 4,5:1. */
    --estado-ambar:   #D97706;   /* 5,57 Aurora · 5,68 clásico — ya cumple */
    --estado-verde:   #16A34A;   /* 5,38 · 5,49 — ya cumple */
    --estado-naranja: #EA580C;   /* 4,98 · 5,09 — ya cumple */
    --estado-rojo:    #E35050;   /* 4,65 · 4,75 */
    --estado-azul:    #4A7EEE;   /* 4,65 · 4,75 */
    --estado-violeta: #9A66F1;   /* 4,69 · 4,79 */
    --estado-indigo:  #7A73EB;   /* 4,61 · 4,71 */
    --estado-cian:    #0EA5E9;   /* 6,40 · 6,53 — ya cumple */

    /* Superficie apagada genérica: oscura acá. Con el #EFEAE7 heredado del
       modo claro quedaba gris claro sobre gris claro. */
    --surface-muted: var(--bg-tertiary);

    /* ---- ÍCONO DE KPI ----
       Los CINCO colores de familia NO cambian entre temas (ver :root). Lo que
       cambia es CÓMO se arma el disco.

       ⚠️ EL VELO NEGRO, que es la pieza no obvia. En claro el disco se aclara
       hacia la tarjeta y todo funciona. En oscuro NO: aclarar el disco lo
       acerca al glifo (que es el color pleno) y les baja el contraste entre
       sí. Medido en Aurora oscuro, el peor de los cuatro modos: `clientes`
       daba 2,70:1 al 8 % y sólo 2,87:1 con el disco en 0 — o sea que ni
       apagando el tinte del todo llegaba a 3:1. El techo estaba en el color,
       no en el porcentaje.
       La salida NO es aclarar el token: probado, `#7D64C8` sube el contraste a
       3,48 pero hunde la separación azul↔violeta bajo protanopia de ΔE 9,4 a
       2,0 — el mismo color para quien no distingue rojo. Cambiar un fallo de
       contraste por uno de daltonismo no es arreglar nada.
       La salida es oscurecer el DISCO en vez de aclararlo: mezclando el color
       con un velo negro, el disco queda por debajo de la tarjeta y el glifo
       gana contraste contra él. Con velo .70 el mínimo de los cinco sube a
       3,32 y de paso el disco se vuelve perceptible (1,16:1 contra la
       tarjeta, contra 1,06 que daba el tinte claro).
       El PORCENTAJE del tinte no cambia entre temas —los dos van al 14 %—:
       lo único que se invierte es hacia dónde se mezcla. */
    --kpi-velo: rgba(0, 0, 0, 0.70);
    --kpi-apagado-bg:  #37322E;
    --kpi-apagado-ink: #B0A79F;

    --border:        rgba(240, 232, 228, 0.10);
    --border-hover:  rgba(240, 232, 228, 0.20);
    --shadow:        rgba(0, 0, 0, 0.20);
    --shadow-md:     0 2px 12px var(--shadow);
    --shadow-lg:     0 8px 24px rgba(0, 0, 0, 0.30);
    --shadow-xl:     0 16px 40px rgba(0, 0, 0, 0.40);

    --glass-bg:             var(--bg-primary);
    --glass-bg-strong:      var(--bg-secondary);
    --glass-bg-hover:       var(--bg-tertiary);

    --logo-cooserviunidos: url('../img/cooserviunidos-dark.png');
}

/* ============================================================
   RESET & BASE
   ============================================================ */
*,
*::before,
*::after { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }

body {
    font-family: var(--font-sans);
    font-size: 15px;
    font-weight: 400;
    line-height: 1.7;
    color: var(--text-primary);
    background: var(--bg-page);
    min-height: 100vh;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

img, svg { max-width: 100%; display: block; }
button, input, select, textarea { font: inherit; color: inherit; }

a {
    /* --accent-texto, no --accent: el coral de relleno da 2,82:1 sobre
       blanco y esto es TEXTO. Afecta a todos los enlaces de la app. */
    color: var(--accent-texto);
    text-decoration: none;
    transition: color var(--t-fast);
}
a:hover { color: var(--accent-hover); }

/* Tipografía */
h1 { font-size: 32px; font-weight: 700; line-height: 1.2;  letter-spacing: -0.02em; color: var(--text-primary); }
h2 { font-size: 24px; font-weight: 600; line-height: 1.3;  letter-spacing: -0.01em; }
h3 { font-size: 18px; font-weight: 600; line-height: 1.4;  }
h4 { font-size: 16px; font-weight: 600; line-height: 1.45; }

p, .text-body { font-size: 15px; color: var(--text-secondary); }

small, .text-small { font-size: 12px; font-weight: 500; color: var(--text-tertiary); }

code, pre, .text-mono {
    font-family: var(--font-mono);
    font-size: 13px;
}

/* ----------------------------------------------------------------
   CIFRAS TABULARES
   ----------------------------------------------------------------
   Sin tabular-nums cada dígito ocupa un ancho distinto y las columnas de
   pesos, fechas y cédulas no alinean verticalmente: comparar montos de un
   vistazo cuesta más de lo necesario. `tnum` en font-feature-settings es el
   fallback para navegadores que no soportan la propiedad de alto nivel.
   Se aplica a TODO .text-mono (dinero, fechas, cédulas, códigos) porque
   ninguno pierde nada con anchos uniformes; NO se toca la alineación acá
   para no mover de lugar las columnas de códigos tipo PTO-001.
   ---------------------------------------------------------------- */
.text-mono, .num, td.num, th.num {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}
/* Utilidad para columnas numéricas: derecha en la celda Y en su encabezado,
   que es donde se desalineaban (th a la izquierda, td a la derecha). */
.num, td.num, th.num { text-align: right; }

/* ----------------------------------------------------------------
   CÓDIGOS Y NIT EN UNA SOLA LÍNEA
   ----------------------------------------------------------------
   `PTO-001` se pintaba como "PTO- / 001" y `800200976-3` como
   "800200976- / 3" en las 5 secciones de COM con columna de código
   (medido: 105/105 puestos, 109/109 sedes, 145/145 contratos,
   249/249 contactos, 100/101 clientes).

   ⚠️ NO era `word-break: break-all` — se verificó en la página real que
   el valor computado ya era `normal`. La causa es que el guion es una
   OPORTUNIDAD DE SALTO por defecto (UAX #14): con la columna apretada a
   88px por `table-layout: auto`, el navegador parte ahí sin necesitar
   ninguna regla. Por eso el arreglo es `white-space: nowrap` y no tocar
   `word-break`, que ya estaba bien.

   No se incluye `code`/`pre` a propósito: el bug es de las columnas de
   código y acotar el selector deja el radio de impacto al mínimo.
   Verificado en producción (COM ×5, GH, CON, y dropdowns abiertos a la
   fuerza porque ocultos miden 0): 0 elementos desbordan, 0 scroll
   horizontal nuevo.

   Si algún .text-mono necesitara envolver, usar `.text-mono-wrap`: rompe
   SÓLO cuando de verdad no cabe, en vez de romper siempre como haría
   `break-all`.
   ---------------------------------------------------------------- */
.text-mono, .mono { white-space: nowrap; }
.text-mono-wrap, .mono.text-mono-wrap {
    white-space: normal;
    overflow-wrap: anywhere;
    word-break: normal;
}

.dimmed { color: var(--text-tertiary); font-weight: 400; }

/* Scrollbar suave */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
    background: var(--border-hover);
    border-radius: 5px;
    border: 2px solid transparent;
    background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--text-tertiary); }

/* gradient-text deshabilitado: ahora los titulos son color solido. */
.gradient-text {
    background: none;
    color: var(--text-primary);
    -webkit-text-fill-color: currentColor;
}

/* Acento puntual (palabra resaltada dentro de un titulo) */
.accent-text { color: var(--accent-texto); }

/* ============================================================
   GLASS-CARD (warm card)
   ============================================================ */
.glass-card {
    --m-color: var(--accent);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-md);
    transition: transform var(--t-normal),
                box-shadow var(--t-normal),
                border-color var(--t-normal);
}
.glass-card:hover {
    transform: translateY(-2px);
    border-color: var(--border-hover);
    box-shadow: var(--shadow-lg);
}
.glass-card.is-elevated {
    background: var(--bg-primary);
    box-shadow: var(--shadow-lg);
}

/* ============================================================
   BOTONES
   ============================================================ */
.glass-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: 10px 18px;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    cursor: pointer;
    text-decoration: none;
    user-select: none;
    transition: all var(--t-fast);
    white-space: nowrap;
}
.glass-btn:hover {
    background: var(--bg-secondary);
    border-color: var(--border-hover);
    color: var(--text-primary);
}
.glass-btn:active { transform: scale(0.98); }
.glass-btn:focus-visible {
    outline: none;
    box-shadow: var(--glow-accent);
    border-color: var(--accent);
}
.glass-btn:disabled,
.glass-btn[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
    transform: none;
}

.glass-btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #ffffff;
    font-weight: 600;
    border-radius: var(--radius-pill);
    padding: 11px 22px;
}
.glass-btn-primary:hover {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
    color: #ffffff;
    box-shadow: 0 4px 14px rgba(255, 107, 74, 0.30);
}
.glass-btn-primary:active { transform: scale(0.98); }

.glass-btn-secondary {
    background: transparent;
    border: 1px solid var(--accent);
    color: var(--accent-texto);
    border-radius: var(--radius-pill);
}
.glass-btn-secondary:hover {
    background: var(--accent-light);
    color: var(--accent-hover);
    border-color: var(--accent-hover);
}

.glass-btn-danger {
    background: transparent;
    border-color: var(--danger);
    color: var(--danger);
    border-radius: var(--radius-pill);
}
.glass-btn-danger:hover {
    background: var(--danger);
    color: #ffffff;
    border-color: var(--danger);
}
.glass-btn-danger:focus-visible { box-shadow: var(--glow-danger); }

.glass-btn-block { width: 100%; }
.glass-btn-sm    { padding: 6px 12px; font-size: 12px; }
.glass-btn-icon  {
    width: 36px; height: 36px;
    padding: 0;
    border-radius: var(--radius-md);
}

/* ============================================================
   INPUTS / SELECT / TEXTAREA
   ============================================================ */
.field-group { margin-bottom: var(--space-5); }

.field-label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin-bottom: var(--space-2);
}

.glass-input,
.glass-select,
.glass-textarea {
    width: 100%;
    padding: 12px 14px;
    font-family: var(--font-sans);
    font-size: 14px;
    color: var(--text-primary);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    transition: border-color var(--t-fast), box-shadow var(--t-fast), background var(--t-fast);
}
[data-theme="dark"] .glass-input,
[data-theme="dark"] .glass-select,
[data-theme="dark"] .glass-textarea {
    background: var(--bg-secondary);
}

.glass-input::placeholder,
.glass-textarea::placeholder { color: var(--text-tertiary); }

.glass-input:hover,
.glass-select:hover,
.glass-textarea:hover { border-color: var(--border-hover); }

.glass-input:focus,
.glass-select:focus,
.glass-textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(255, 107, 74, 0.18);
}

.glass-input:disabled,
.glass-select:disabled,
.glass-textarea:disabled { opacity: 0.5; cursor: not-allowed; }

.glass-textarea { min-height: 96px; resize: vertical; }

.glass-select {
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%23716867' d='M6 8L0 0h12z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 14px center;
    padding-right: 36px;
}

/* ============================================================
   ALERTS
   ============================================================ */
.glass-alert {
    padding: 12px 16px;
    border-radius: var(--radius-md);
    border: 1px solid;
    background: var(--bg-primary);
    font-size: 14px;
    line-height: 1.55;
}
.glass-alert-error   { background: #FEE2E2; border-color: #FCA5A5; color: #991b1b; }
.glass-alert-success { background: #E8F8EF; border-color: #86EFAC; color: #15803d; }
.glass-alert-warning { background: #FEF3C7; border-color: #FCD34D; color: #92400e; }
.glass-alert-info    { background: #DBEAFE; border-color: #93C5FD; color: #1e40af; }

[data-theme="dark"] .glass-alert-error   { background: rgba(239, 68, 68, 0.12); color: #fca5a5; border-color: rgba(239, 68, 68, 0.30); }
[data-theme="dark"] .glass-alert-success { background: rgba(34,197, 94, 0.12); color: #86efac; border-color: rgba(34,197, 94, 0.30); }
[data-theme="dark"] .glass-alert-warning { background: rgba(245,158, 11, 0.12); color: #fde68a; border-color: rgba(245,158, 11, 0.30); }
[data-theme="dark"] .glass-alert-info    { background: rgba(59,130,246, 0.12); color: #93c5fd; border-color: rgba(59,130,246, 0.30); }

/* ============================================================
   BADGES — pill solido, sin glow ni pulso
   ============================================================ */
.glass-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    /* 12px: a 11px/600 WCAG lo sigue tratando como texto normal (grande son
       ≥18.7px en negrita) y le exige 4.5:1. El ::before de abajo cubre 1.4.1. */
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    border-radius: var(--radius-pill);
    border: 1px solid transparent;
}
.glass-badge::before {
    content: '';
    width: 6px; height: 6px;
    border-radius: 50%;
    background: currentColor;
}
.glass-badge-success {
    background: #E8F8EF;
    color: #15803d;
}
.glass-badge-warning {
    background: #FEF3C7;
    color: #92400e;
}
.glass-badge-danger  {
    background: #FEE2E2;
    color: #991b1b;
}
.glass-badge-info    {
    background: #DBEAFE;
    color: #1e40af;
}
.glass-badge-muted   {
    background: var(--bg-secondary);
    color: var(--text-secondary);
    border-color: var(--border);
}
[data-theme="dark"] .glass-badge-success { background: rgba(34,197, 94, 0.15); color: #86efac; }
[data-theme="dark"] .glass-badge-warning { background: rgba(245,158, 11, 0.15); color: #fde68a; }
[data-theme="dark"] .glass-badge-danger  { background: rgba(239, 68, 68, 0.15); color: #fca5a5; }
[data-theme="dark"] .glass-badge-info    { background: rgba(59,130,246, 0.15); color: #93c5fd; }

/* ============================================================
   AVATAR
   ============================================================ */
.glass-avatar {
    display: inline-block;
    border-radius: 50%;
    border: 2px solid var(--accent-light);
    background: var(--bg-secondary);
    object-fit: cover;
    flex-shrink: 0;
    overflow: hidden;
}
.glass-avatar-sm { width: 32px;  height: 32px;  }
.glass-avatar-md { width: 40px;  height: 40px;  }
.glass-avatar-lg { width: 64px;  height: 64px;  }
.glass-avatar-xl { width: 120px; height: 120px; border-width: 3px; }
.glass-avatar.glass-avatar-xs { width: 28px; height: 28px; border-width: 1px; }

/* ============================================================
   TABLE
   ============================================================ */
.glass-table-wrap {
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    /* Una tabla mas ancha que su contenedor se DESPLAZA, no se corta. Con
       overflow:hidden las ultimas columnas (Estado, Adjunto, ACCIONES) quedaban
       inalcanzables: medido en ?p=gh_ficha&tab=estudios, tabla 1.561px en
       contenedor 1.134px. overflow-y:hidden conserva el recorte de las esquinas
       redondeadas, asi que el eje vertical se comporta igual que antes. */
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
}
.glass-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
}
.glass-table thead th {
    text-align: left;
    padding: 14px 16px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-secondary);
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
.glass-table tbody td {
    padding: 14px 16px;
    font-size: 14px;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
    color: var(--text-primary);
}
.glass-table tfoot td {
    padding: 14px 16px;
    font-size: 14px;
    vertical-align: middle;
    border-top: 2px solid var(--border);
    font-weight: 700;
}
.glass-table tbody tr { transition: background var(--t-fast); }
.glass-table tbody tr:hover { background: var(--bg-secondary); }
.glass-table tbody tr:last-child td { border-bottom: 0; }

/* ============================================================
   MODAL
   ============================================================ */
.glass-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(26, 21, 18, 0.50);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    display: none;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    z-index: 100;
    overflow-y: auto;
}
.glass-modal-backdrop.is-open { display: flex; }

.glass-modal {
    width: 100%;
    max-width: 560px;
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-2xl);
    padding: var(--space-6);
    box-shadow: var(--shadow-xl);
    max-height: calc(100vh - 32px);
    overflow-y: auto;
    color: var(--text-primary);
}

.glass-modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--space-5);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--border);
}
.glass-modal-header h2 { font-size: 20px; }
.glass-modal-close {
    background: transparent;
    border: 0;
    color: var(--text-tertiary);
    cursor: pointer;
    font-size: 22px;
    line-height: 1;
    padding: 4px 10px;
    border-radius: var(--radius-sm);
    transition: background var(--t-fast), color var(--t-fast);
}
.glass-modal-close:hover { background: var(--bg-secondary); color: var(--text-primary); }

.glass-modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-3);
    margin-top: var(--space-6);
    padding-top: var(--space-4);
    border-top: 1px solid var(--border);
}

.field-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
}
@media (max-width: 520px) {
    .field-row { grid-template-columns: 1fr; }
}
/* Techo de los campos de formulario EN PÁGINA (los de modal ya están topados
   por el ancho del modal). El caso medido es el form de alm_dotacion: 836px
   hoy, 1108px con el contenedor en 1760. El techo va en el CAMPO y no en el
   `.field-row` que lo contiene: topar la fila encogería el layout actual, y
   este techo tiene que ser inerte al ancho de hoy — el campo más ancho de
   todo SIGA mide 868px < 900. */
.field-row .field-group > .glass-input,
.field-row .field-group > .glass-select,
.field-row .field-group > textarea { max-width: 900px; }

/* ============================================================
   SIDEBAR
   ============================================================ */
.glass-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--sidebar-w);
    background: var(--bg-sidebar);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    z-index: 50;
    transition: width var(--t-normal), transform var(--t-normal);
}
.glass-sidebar.is-collapsed { width: var(--sidebar-w-collapsed); }

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0 var(--space-5);
    height: var(--header-h);
    border-bottom: 1px solid var(--border);
    overflow: hidden;
    text-decoration: none;
}
.sidebar-brand:hover img { opacity: 0.85; }
.sidebar-brand img {
    height: 30px;
    width: auto;
    flex-shrink: 0;
    transition: opacity var(--t-fast);
}
.sidebar-brand-text {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 1px;
    white-space: nowrap;
}

.sidebar-nav {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-4) var(--space-3);
    overflow-x: hidden;
}

.sidebar-section-label {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-tertiary);
    padding: var(--space-3) var(--space-3) var(--space-2);
    position: relative;
}
.sidebar-section-label:not(:first-child) {
    margin-top: var(--space-3);
    padding-top: var(--space-4);
    border-top: 1px solid var(--border);
}

.sidebar-link {
    --m-color: var(--accent);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 10px 12px;
    border-radius: var(--radius-md);
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
    margin-bottom: 2px;
    border-left: 3px solid transparent;
    transition: all var(--t-fast);
    white-space: nowrap;
    overflow: hidden;
}
.sidebar-link:hover {
    background: var(--accent-light);
    color: var(--accent);
}
.sidebar-link.is-active {
    background: var(--accent-light);
    color: var(--accent);
    border-left-color: var(--accent);
    font-weight: 600;
}
.sidebar-link .sidebar-link-icon {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-secondary);
    border-radius: 8px;
    color: var(--m-color);
    flex-shrink: 0;
    transition: background var(--t-fast);
}
.sidebar-link:hover .sidebar-link-icon,
.sidebar-link.is-active .sidebar-link-icon {
    background: rgba(255, 107, 74, 0.12);
}
.sidebar-link .sidebar-link-icon svg {
    width: 16px;
    height: 16px;
    stroke-width: 2;
}

.sidebar-toggle {
    border-top: 1px solid var(--border);
    padding: var(--space-3);
}
.sidebar-toggle .glass-btn { font-size: 14px; }

/* Estado collapsed */
.glass-sidebar.is-collapsed .sidebar-brand-text,
.glass-sidebar.is-collapsed .sidebar-link-text,
.glass-sidebar.is-collapsed .sidebar-section-label,
.glass-sidebar.is-collapsed .sidebar-toggle-text,
.glass-sidebar.is-collapsed .sidebar-footer-logo,
.glass-sidebar.is-collapsed .sidebar-footer-name { display: none; }
.glass-sidebar.is-collapsed .sidebar-link {
    justify-content: center;
    padding: 10px 0;
    border-left: 0;
}
.glass-sidebar.is-collapsed .sidebar-brand { padding: 0; justify-content: center; }
.glass-sidebar.is-collapsed .sidebar-brand img { height: 24px; }
.glass-sidebar.is-collapsed .sidebar-toggle .glass-btn { padding: 6px; }
.glass-sidebar.is-collapsed .sidebar-section-label:not(:first-child) { border-top: 0; }

/* ============================================================
   HEADER
   ============================================================ */
.glass-header {
    position: fixed;
    top: 0;
    left: var(--sidebar-w);
    right: 0;
    height: var(--header-h);
    background: var(--bg-header);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 var(--space-6);
    /* ⚠️ **90, y NO 40.** El encabezado tiene `backdrop-filter` (en Aurora) y es su propio
       CONTEXTO DE APILAMIENTO, así que el `z-index:60` de `.modules-dropdown`, `.user-dropdown`
       y la campana es LOCAL: no los saca del 40 del encabezado. Cualquier tarjeta de página
       por encima de 40 en el apilamiento RAÍZ les gana al conjunto — medido en producción con
       las tarjetas de ALM (50/60): `elementFromPoint` en el cruce devolvía `.alm-ter-elegido`
       y no el menú.
       La escala, de abajo hacia arriba: contenido de página (1-30) · encabezado **90** ·
       modales (100) · «Ver lista» de ALM (110) · overlay de guardado a pantalla completa
       (1200) · barra de navegación (2000).
       ⚠️ `.loading-overlay` de Aurora también dice 90, y NO choca: es `position:absolute`
       dentro de su contenedor y cubre sólo eso; el de pantalla completa es
       `.loading-overlay-fixed`, en 1200. */
    z-index: 90;
    transition: left var(--t-normal);}
.glass-sidebar.is-collapsed ~ .glass-header { left: var(--sidebar-w-collapsed); }

.header-left {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    min-width: 0;
}
.header-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.header-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.header-user {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 4px 4px 4px 14px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
}
.header-user .meta { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; }
.header-user .name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
    max-width: 180px;
}
.header-user .role {
    font-size: 11px;
    color: var(--text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.sidebar-mobile-toggle { display: none; }

/* Theme toggle: sol / luna simple */
.theme-toggle {
    width: 40px;
    height: 40px;
    padding: 0;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    color: var(--text-secondary);
    transition: all var(--t-fast);
}
.theme-toggle:hover {
    background: var(--accent-light);
    color: var(--accent);
    border-color: var(--accent);
}
.theme-toggle svg { width: 18px; height: 18px; }
.theme-toggle .icon-sun  { display: none; }
.theme-toggle .icon-moon { display: inline-flex; }
[data-theme="dark"] .theme-toggle .icon-sun  { display: inline-flex; }
[data-theme="dark"] .theme-toggle .icon-moon { display: none; }

/* ============================================================
   APP MAIN
   ============================================================ */
.app-main {
    margin-left: var(--sidebar-w);
    padding-top: calc(var(--header-h) + var(--space-6));
    padding-left: var(--space-6);
    padding-right: var(--space-6);
    padding-bottom: var(--space-8);
    min-height: 100vh;
    transition: margin-left var(--t-normal);
}
.glass-sidebar.is-collapsed ~ .app-main { margin-left: var(--sidebar-w-collapsed); }

.page-title { margin-bottom: var(--space-1); color: var(--text-primary); }
.page-subtitle { color: var(--text-secondary); margin-bottom: var(--space-6); font-size: 15px; }

.section-title {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-secondary);
    margin: var(--space-8) 0 var(--space-4);
}

/* ============================================================
   STATS
   ============================================================ */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--space-4);
}
.stat-card {
    padding: var(--space-5);
    padding-left: calc(var(--space-5) + 8px);
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    position: relative;
    overflow: hidden;
    transition: box-shadow var(--t-normal);
}
.stat-card::before {
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 3px;
    background: var(--accent);
}
.stat-card:hover { box-shadow: var(--shadow-md); }

.stat-card .label {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-secondary);
}
.stat-card .value {
    font-size: 28px;
    font-weight: 700;
    color: var(--text-primary);
    margin-top: 6px;
    letter-spacing: -0.02em;
}
.stat-card .value.is-small {
    font-size: 18px;
    font-weight: 600;
    font-family: var(--font-mono);
}
.stat-card .value.text-mono { font-family: var(--font-mono); }
.stat-card .delta { font-size: 12px; color: var(--success); margin-top: 4px; }

/* ============================================================
   MODULE CARD
   ============================================================ */
.module-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-4);
}

.module-card {
    --m-color: var(--accent);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-5);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    text-decoration: none;
    color: var(--text-primary);
    transition: all var(--t-normal);
    min-height: 180px;
}
.module-card:hover {
    transform: translateY(-2px);
    border-color: var(--m-color);
    box-shadow: var(--shadow-lg);
    color: var(--text-primary);
}

.module-card .module-icon {
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--m-color) 12%, transparent);
    border-radius: 50%;
    color: var(--m-color);
    transition: background var(--t-fast);
}
.module-card:hover .module-icon {
    background: color-mix(in srgb, var(--m-color) 18%, transparent);
}
.module-card .module-icon svg { width: 24px; height: 24px; stroke-width: 2; }

.module-card .module-name {
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
.module-card .module-name .module-code {
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 600;
    color: var(--m-color);
    background: color-mix(in srgb, var(--m-color) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--m-color) 25%, transparent);
    padding: 2px 6px;
    border-radius: 4px;
    letter-spacing: 0.5px;
}
.module-card .module-desc {
    font-size: 14px;
    color: var(--text-secondary);
    line-height: 1.55;
}
.module-card .module-perms {
    display: flex;
    gap: 4px;
    margin-top: auto;
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 600;
}
.module-card .perm-flag {
    padding: 3px 8px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-tertiary);
    letter-spacing: 0.5px;
}
.module-card .perm-flag.is-on {
    color: var(--m-color);
    border-color: color-mix(in srgb, var(--m-color) 35%, transparent);
    background: color-mix(in srgb, var(--m-color) 10%, transparent);
}

/* ============================================================
   LOGIN PAGE
   ============================================================ */
.login-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    background: var(--bg-secondary);
    position: relative;
    overflow: hidden;
}
/* Blobs orgánicos sutiles de fondo (no neón) */
.login-page::before,
.login-page::after {
    content: '';
    position: absolute;
    border-radius: 50%;
    background: var(--accent-light);
    filter: blur(60px);
    z-index: 0;
    pointer-events: none;
}
.login-page::before {
    width: 380px; height: 380px;
    top: -120px; left: -80px;
    opacity: 0.6;
}
.login-page::after {
    width: 320px; height: 320px;
    bottom: -100px; right: -60px;
    background: rgba(255, 179, 71, 0.30);
    opacity: 0.7;
}
[data-theme="dark"] .login-page::before { opacity: 0.18; }
[data-theme="dark"] .login-page::after  { opacity: 0.18; }

.login-card {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 420px;
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-2xl);
    padding: 40px 36px;
    box-shadow: var(--shadow-xl);
}
/* Patrón de puntos decorativo en esquina */
.login-card::before {
    content: '';
    position: absolute;
    top: 16px;
    right: 16px;
    width: 54px;
    height: 54px;
    background-image: radial-gradient(circle, var(--accent) 1.5px, transparent 1.5px);
    background-size: 18px 18px;
    background-position: 0 0;
    opacity: 0.22;
    pointer-events: none;
}

.login-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: var(--space-8);
}
.login-brand img { height: 56px; margin-bottom: var(--space-4); }
.login-brand h1 {
    font-size: 24px;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0;
}
.login-brand p {
    font-size: 14px;
    color: var(--text-secondary);
    margin-top: 4px;
    text-align: center;
}
.brand-coop-name {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin-top: -8px;
    margin-bottom: var(--space-5);
    text-align: center;
}

.login-form .field-group { margin-bottom: var(--space-5); }

.login-footer {
    text-align: center;
    margin-top: var(--space-6);
    font-size: 11px;
    color: var(--text-tertiary);
}

/* Logo Cooserviunidos */
.logo-cooserviunidos {
    display: block;
    max-width: 100%;
    height: auto;
    object-fit: contain;
}
.cooserviunidos-img-dark { display: none; }
[data-theme="dark"] .cooserviunidos-img-dark  { display: block; }
[data-theme="dark"] .cooserviunidos-img-light { display: none; }

.sidebar-footer-logo {
    padding: var(--space-3) var(--space-5) var(--space-2);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    opacity: 0.85;
    transition: opacity var(--t-fast);
    border-top: 1px solid var(--border);
}
.sidebar-footer-logo:hover { opacity: 1; }
.sidebar-footer-logo .logo-cooserviunidos { max-height: 32px; }
.sidebar-footer-name {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.8px;
    color: var(--text-tertiary);
    text-transform: uppercase;
    text-align: center;
    white-space: nowrap;
}

.login-cooserviunidos {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--border);
    opacity: 0.80;
}
.login-cooserviunidos .logo-cooserviunidos { max-height: 36px; max-width: 200px; }

/* ============================================================
   PAGE HEADER + TOOLBAR + PAGINATION + TABS
   ============================================================ */
.page-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-bottom: var(--space-5);
}
.page-header .page-title { margin-bottom: 4px; }
.page-header-actions { display: flex; gap: var(--space-3); align-items: center; }

.toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    margin-bottom: var(--space-4);
}
/* max-width: techo del buscador de las toolbars. Con el contenedor en 1760px
   este campo se iba a 1220px, y ya hoy llega a 961 (gh_contratos), 812
   (usuarios), 722 (alm_catalogo), 720 (alm_saldos) y 653 (sed_candidatos).
   Las cinco son un <input> de búsqueda suelto y el placeholder más largo
   ("Buscar por código, cédula, nombre…") cabe de sobra en 520px. Las otras 7
   rutas con `.grow` miden 300–439px: para ellas el techo es inerte. */
.toolbar > .grow { flex: 1 1 240px; min-width: 180px; max-width: 520px; }
.toolbar .glass-input,
.toolbar .glass-select { width: 100%; }
.toolbar .toolbar-field { display: flex; flex-direction: column; gap: 4px; min-width: 160px; }
.toolbar .toolbar-field .field-label { margin-bottom: 0; }
/* Casilla con etiqueta dentro de una `.toolbar`. Sin esto el `<label>` se comporta como
   bloque y empuja al resto de la barra a la fila siguiente. La usan alm_stock y
   alm_custodia; vivía en un <style> de la primera. */
.alm-sw { display: flex; align-items: center; gap: 7px; font-size: 13px;
          color: var(--text-muted); white-space: nowrap; }

.row-actions {
    display: inline-flex;
    gap: 4px;
    align-items: center;
}
.row-actions .glass-btn { padding: 6px 10px; font-size: 12px; }
.row-actions .glass-btn-icon { width: 32px; height: 32px; padding: 0; }
.row-actions .glass-btn-icon svg { width: 14px; height: 14px; }

.state-toggle {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--bg-primary);
}
.state-toggle button {
    background: transparent;
    border: 0;
    padding: 5px 10px;
    color: var(--text-tertiary);
    cursor: pointer;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    transition: all var(--t-fast);
}
.state-toggle button:hover { background: var(--bg-secondary); color: var(--text-primary); }
.state-toggle button.is-active.state-Activo    { background: #E8F8EF; color: #15803d; }
.state-toggle button.is-active.state-Inactivo  { background: #FEF3C7; color: #92400e; }
.state-toggle button.is-active.state-Bloqueado { background: #FEE2E2; color: #991b1b; }

.pagination {
    display: flex;
    gap: 4px;
    justify-content: center;
    align-items: center;
    margin-top: var(--space-5);
    flex-wrap: wrap;
}
.pagination a,
.pagination span.page-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    padding: 6px 10px;
    border: 1px solid var(--border);
    background: var(--bg-primary);
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 13px;
    transition: all var(--t-fast);
}
.pagination a:hover { background: var(--accent-light); color: var(--accent); border-color: var(--accent); }
.pagination .page-num.is-current {
    background: var(--accent);
    color: #ffffff;
    border-color: var(--accent);
}
.pagination .is-disabled { opacity: 0.4; pointer-events: none; }
.pagination .pagination-info {
    font-size: 12px;
    color: var(--text-tertiary);
    margin: 0 var(--space-2);
}

/* Las pestañas de COM miden 1701px de ancho natural: a 1920 entran raspando y
   en cualquier laptop de 1440/1536 desbordan. La barra de scroll no es sólo
   fea — deja una línea horizontal justo debajo de la fila, compitiendo con el
   subrayado de la pestaña activa: dos líneas pegadas que significan cosas
   distintas. Se oculta la barra y se indica el desborde con un fade (abajo).
   ⚠️ Ocultar la barra SIN indicador sería peor que dejarla: el usuario no
   descubriría las pestañas escondidas. */
.page-tabs {
    display: flex;
    gap: 4px;
    margin-bottom: var(--space-5);
    border-bottom: 1px solid var(--border);
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scroll-behavior: smooth;
    scroll-padding-inline: 3rem;   /* que el foco de teclado no quede bajo el fade */
    scrollbar-width: none;
    -ms-overflow-style: none;
}
.page-tabs::-webkit-scrollbar { display: none; }
.page-tabs > * { flex: 0 0 auto; }

/* Fade guiado por scroll: aparece sólo del lado donde HAY contenido oculto,
   sin una línea de JS. Degrada limpio — sin soporte no hay fade y nada se
   rompe. */
@property --fade-ini { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --fade-fin { syntax: "<length>"; inherits: false; initial-value: 0px; }
@keyframes tabs-fade {
    0%        { --fade-ini: 0px; }
    10%, 100% { --fade-ini: 2.5rem; }
    0%,  90%  { --fade-fin: 2.5rem; }
    100%      { --fade-fin: 0px; }
}
@supports (animation-timeline: scroll(self inline)) {
    .page-tabs {
        animation: tabs-fade linear;
        animation-timeline: scroll(self inline);
        mask: linear-gradient(to right, #0000, #000 var(--fade-ini),
                              #000 calc(100% - var(--fade-fin)), #0000);
    }
}

/* Flechas ‹ › — las inyecta templates/layout.php y sólo aparecen cuando hay
   desborde real. Los usuarios de SIGA están en escritorio con mouse, y el
   scroll horizontal con mouse es incómodo. */
.page-tabs-wrap { position: relative; }
.page-tabs-arrow {
    position: absolute; top: 0; z-index: 2;
    display: none; align-items: center; justify-content: center;
    width: 32px; height: calc(100% - 1px);
    border: 0; padding: 0; cursor: pointer;
    background: var(--bg-page);
    color: var(--text-secondary);
    transition: color var(--t-fast), opacity var(--t-fast);
}
.page-tabs-arrow[hidden] { display: none !important; }
.page-tabs-wrap.has-overflow .page-tabs-arrow { display: inline-flex; }
.page-tabs-arrow-ini { inset-inline-start: 0; }
.page-tabs-arrow-fin { inset-inline-end: 0; }
.page-tabs-arrow:hover { color: var(--text-primary); }
.page-tabs-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.page-tabs-arrow svg { width: 18px; height: 18px; }

.page-tab {
    padding: 10px 16px;
    color: var(--text-secondary);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    font-size: 14px;
    font-weight: 500;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    /* 44px de alto mínimo: objetivo táctil accesible. */
    min-height: 44px;
    white-space: nowrap;
    transition: color var(--t-fast), border-color var(--t-fast);
}
.page-tab:hover { color: var(--text-primary); }
.page-tab.is-active {
    /* Medido antes: 2,54:1 (Aurora claro) / 2,62:1 (clásico claro). */
    color: var(--accent-texto);
    border-color: var(--accent);
    font-weight: 600;
}
.page-tab svg { width: 14px; height: 14px; }

/* ============================================================
   PERMISSION GRID
   ============================================================ */
.perm-grid-wrap {
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-4);
    overflow-x: auto;
}
.perm-grid {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    min-width: 520px;
}
.perm-grid thead th {
    text-align: center;
    padding: 10px 12px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-secondary);
    border-bottom: 1px solid var(--border);
}
.perm-grid thead th:first-child { text-align: left; }
.perm-grid tbody td {
    padding: 12px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    text-align: center;
    color: var(--text-primary);
}
.perm-grid tbody td:first-child {
    text-align: left;
    font-weight: 500;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    gap: var(--space-3);
}
.perm-grid tbody tr:last-child td { border-bottom: 0; }
.perm-grid tbody tr:hover td { background: var(--bg-secondary); }

.perm-grid .module-tag {
    width: 32px; height: 32px;
    display: inline-flex; align-items: center; justify-content: center;
    background: color-mix(in srgb, var(--m-color, var(--accent)) 12%, transparent);
    color: var(--m-color, var(--accent));
    border-radius: 8px;
    flex-shrink: 0;
}
.perm-grid .module-tag svg { width: 16px; height: 16px; }

.glass-check {
    appearance: none;
    -webkit-appearance: none;
    width: 18px;
    height: 18px;
    border: 1px solid var(--border-hover);
    background: var(--bg-primary);
    border-radius: 4px;
    cursor: pointer;
    position: relative;
    transition: all var(--t-fast);
    vertical-align: middle;
}
.glass-check:hover { border-color: var(--accent); }
.glass-check:checked {
    background: var(--accent);
    border-color: var(--accent);
}
.glass-check:checked::after {
    content: '';
    position: absolute;
    left: 5px; top: 1px;
    width: 5px; height: 10px;
    border-right: 2px solid #fff;
    border-bottom: 2px solid #fff;
    transform: rotate(45deg);
}
.glass-check:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(255, 107, 74, 0.20);
}

/* ============================================================
   EMPTY STATE
   ============================================================ */
.empty-state {
    padding: var(--space-10) var(--space-6);
    text-align: center;
    background: var(--bg-primary);
    border: 1px dashed var(--border-hover);
    border-radius: var(--radius-lg);
    color: var(--text-tertiary);
}
/* Techo del párrafo del estado vacío: en gh_reporte_seleccion la frase (109
   caracteres) ocupaba 1254px y con el contenedor en 1760 se iba a 1662px en
   UNA sola línea. Es cosmético, no de legibilidad: es una frase, no un cuerpo
   de texto. `margin-inline: auto` porque el contenedor centra el texto pero el
   <p> es bloque: sin él, al topar el ancho quedaría pegado a la izquierda. */
.empty-state p { max-width: 68ch; margin-inline: auto; }
.empty-state .icon-wrap {
    width: 64px; height: 64px;
    border-radius: 50%;
    background: var(--accent-light);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-bottom: var(--space-3);
    color: var(--accent);
}
.empty-state .icon-wrap svg { width: 24px; height: 24px; }
.empty-state h3 { color: var(--text-primary); margin-bottom: 4px; }

/* ============================================================
   OTP INPUT (codigo 2FA)
   ============================================================ */
.otp-input {
    display: block;
    width: 220px;
    margin: 0 auto;
    padding: 14px 8px;
    padding-left: 20px;
    font-family: var(--font-mono);
    font-size: 32px;
    font-weight: 600;
    letter-spacing: 12px;
    line-height: 1.2;
    text-align: center;
    color: var(--text-primary);
    caret-color: var(--accent);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-bottom: 2px solid var(--accent);
    border-radius: var(--radius-md);
    outline: none;
    transition: border-color var(--t-normal),
                box-shadow   var(--t-normal),
                background   var(--t-normal);
}
.otp-input::placeholder {
    color: var(--text-tertiary);
    opacity: 0.40;
    letter-spacing: 12px;
    font-weight: 600;
}
.otp-input:hover {
    border-color: var(--border-hover);
}
.otp-input:focus {
    border-color: var(--accent);
    border-bottom-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(255, 107, 74, 0.20);
}
[data-theme="dark"] .otp-input {
    background: var(--bg-secondary);
}

/* ============================================================
   DASHBOARD SLIDER
   ============================================================ */
.dash-slider {
    position: relative;
    /* ⚠️ **ESTE `height` NO es el que se ve.** Más abajo, el bloque «DASHBOARD
       SLIDER v2» lo pisa con `body.layout-no-sidebar .dash-slider { height:auto;
       min-height:300px }` — más específica y posterior —, y **todas** las páginas
       de SIGA llevan esa clase en el `<body>`. El alto efectivo se ajusta allá;
       tocar acá no cambia nada. (Lo aprendí midiendo: la primera versión de la
       v2.43.0 puso un `clamp` en esta línea y era completamente inerte.) */
    height: 200px;
    overflow: hidden;
    border-radius: var(--radius-xl);
    border: 1px solid var(--border);
    margin-bottom: var(--space-6);
    box-shadow: var(--shadow-md);
}
.dash-slider .slider-track {
    display: flex;
    height: 100%;
    transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
    will-change: transform;
}
.dash-slider .slide {
    flex: 0 0 100%;
    height: 100%;
    position: relative;
    display: flex;
    align-items: center;
    padding: var(--space-6) var(--space-8);
    color: #ffffff;
    text-decoration: none;
    overflow: hidden;
}
.dash-slider .slide::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(135deg, rgba(0,0,0,0.10), rgba(0,0,0,0.02) 60%);
    pointer-events: none;
}
.dash-slider .slide-icon {
    width: 64px;
    height: 64px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255,255,255,0.20);
    border: 1px solid rgba(255,255,255,0.30);
    border-radius: var(--radius-md);
    flex-shrink: 0;
    color: #ffffff;
    margin-right: var(--space-5);
    z-index: 1;
}
.dash-slider .slide-icon svg { width: 28px; height: 28px; }
.dash-slider .slide-content { z-index: 1; max-width: 640px; }
.dash-slider .slide-title {
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.01em;
    margin-bottom: 6px;
    color: #ffffff;
}
.dash-slider .slide-desc {
    font-size: 14px;
    line-height: 1.5;
    color: rgba(255,255,255,0.92);
}
.dash-slider .slide-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-top: var(--space-3);
    padding: 8px 16px;
    background: rgba(255, 255, 255, 0.22);
    border: 1px solid rgba(255, 255, 255, 0.32);
    border-radius: var(--radius-pill);
    color: #ffffff;
    font-size: 13px;
    font-weight: 500;
    text-decoration: none;
    transition: background var(--t-fast), transform var(--t-fast);
}
.dash-slider .slide-btn:hover {
    background: rgba(255, 255, 255, 0.32);
    transform: translateY(-1px);
    color: #ffffff;
}
.dash-slider .slide-btn svg { width: 14px; height: 14px; }

.dash-slider .slider-dots {
    position: absolute;
    bottom: 14px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 8px;
    z-index: 2;
}
.dash-slider .slider-dots button {
    width: 8px;
    height: 8px;
    border: 0;
    background: rgba(255,255,255,0.50);
    border-radius: 999px;
    padding: 0;
    cursor: pointer;
    transition: all 0.3s ease;
}
.dash-slider .slider-dots button.is-active {
    background: #ffffff;
    width: 24px;
}
.dash-slider .slider-dots button:hover { background: #ffffff; }

@media (max-width: 600px) {
    .dash-slider { height: auto; min-height: 180px; }
    .dash-slider .slide { flex-direction: column; align-items: flex-start; gap: var(--space-3); padding: var(--space-5); }
    .dash-slider .slide-icon { margin-right: 0; }
    .dash-slider .slide-title { font-size: 18px; }
}

/* ============================================================
   DASHBOARD GRID (Activity + Shortcuts)
   ============================================================ */
.dash-grid {
    display: grid;
    grid-template-columns: 1.5fr 1fr;
    gap: var(--space-4);
    margin-top: var(--space-6);
}
@media (max-width: 900px) {
    .dash-grid { grid-template-columns: 1fr; }
}

.dash-panel {
    padding: var(--space-5);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
}
.dash-panel-title {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-secondary);
    margin-bottom: var(--space-4);
}

.activity-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.activity-item {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3);
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    transition: background var(--t-fast), border-color var(--t-fast);
}
.activity-item:hover {
    background: var(--bg-tertiary);
    border-color: var(--border-hover);
}
.activity-item-icon {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--accent-light);
    color: var(--accent);
    border-radius: 8px;
}
.activity-item-icon svg { width: 16px; height: 16px; }
.activity-item-icon.is-fail {
    background: #FEE2E2;
    color: #991b1b;
}
.activity-item-body { flex: 1; min-width: 0; }
.activity-item-title {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-primary);
    margin-bottom: 2px;
    word-break: break-word;
}
.activity-item-meta {
    font-size: 11px;
    color: var(--text-tertiary);
    display: flex;
    gap: 8px;
    align-items: center;
}
.activity-item-meta .module-tag-mini {
    font-family: var(--font-mono);
    font-size: 10px;
    padding: 1px 6px;
    border: 1px solid var(--border);
    border-radius: 4px;
}

.shortcut-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.shortcut-btn {
    --m-color: var(--accent);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    text-decoration: none;
    transition: all var(--t-fast);
}
.shortcut-btn:hover {
    transform: translateX(2px);
    border-color: var(--m-color);
    background: color-mix(in srgb, var(--m-color) 6%, var(--bg-primary));
    color: var(--text-primary);
}
.shortcut-btn-icon {
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--m-color) 12%, transparent);
    border-radius: 50%;
    color: var(--m-color);
    flex-shrink: 0;
}
.shortcut-btn-icon svg { width: 16px; height: 16px; }
.shortcut-btn-text {
    flex: 1;
    font-size: 14px;
    font-weight: 500;
}
.shortcut-btn-arrow {
    color: var(--text-tertiary);
    transition: transform var(--t-fast), color var(--t-fast);
}
.shortcut-btn:hover .shortcut-btn-arrow {
    color: var(--m-color);
    transform: translateX(2px);
}

/* ============================================================
   FAB MESA DE AYUDA IT
   ============================================================ */
.tic-fab {
    position: fixed;
    bottom: 24px;
    right: 24px;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--accent);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    text-decoration: none;
    box-shadow: 0 6px 18px rgba(255, 107, 74, 0.35);
    z-index: 60;
    transition: transform var(--t-normal), box-shadow var(--t-normal);
}
.tic-fab:hover {
    transform: scale(1.08);
    background: var(--accent-hover);
    box-shadow: 0 8px 24px rgba(255, 107, 74, 0.50);
    color: #ffffff;
}
.tic-fab svg { width: 24px; height: 24px; }
.tic-fab-tooltip {
    position: absolute;
    right: calc(100% + 12px);
    top: 50%;
    transform: translateY(-50%) translateX(8px);
    white-space: nowrap;
    background: var(--text-primary);
    color: var(--bg-primary);
    padding: 8px 14px;
    border-radius: var(--radius-md);
    font-size: 13px;
    font-weight: 500;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease, transform 0.2s ease;
}
.tic-fab:hover .tic-fab-tooltip {
    opacity: 1;
    transform: translateY(-50%) translateX(0);
}

.tic-bubble {
    position: fixed;
    bottom: 96px;
    right: 24px;
    background: var(--bg-primary);
    border: 1px solid var(--accent);
    border-radius: var(--radius-lg);
    padding: 14px 36px 14px 16px;
    box-shadow: var(--shadow-xl);
    z-index: 70;
    max-width: 240px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.4s ease, transform 0.4s ease;
}
.tic-bubble.is-visible {
    opacity: 1;
    transform: translateY(0);
}
.tic-bubble::after {
    content: '';
    position: absolute;
    bottom: -7px;
    right: 28px;
    width: 12px;
    height: 12px;
    background: inherit;
    border-right: 1px solid var(--accent);
    border-bottom: 1px solid var(--accent);
    transform: rotate(45deg);
}
.tic-bubble-title {
    color: var(--accent);
    font-size: 13px;
    font-weight: 700;
}
.tic-bubble-text {
    color: var(--text-secondary);
    font-size: 12px;
}
.tic-bubble-close {
    position: absolute;
    top: 4px;
    right: 8px;
    background: transparent;
    border: 0;
    color: var(--text-tertiary);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: var(--radius-sm);
    transition: background var(--t-fast), color var(--t-fast);
}
.tic-bubble-close:hover {
    background: var(--bg-secondary);
    color: var(--text-primary);
}

@media (max-width: 600px) {
    .tic-fab { width: 50px; height: 50px; bottom: 16px; right: 16px; }
    .tic-fab svg { width: 22px; height: 22px; }
    .tic-bubble { right: 16px; bottom: 80px; max-width: 200px; }
    .tic-fab-tooltip { display: none; }
}

/* ============================================================
   MODULO SLIDES (gestion)
   ============================================================ */
.slide-icon-cell {
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    color: #ffffff;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
}
.slide-icon-cell svg { width: 20px; height: 20px; }

.color-preview {
    display: inline-block;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 2px solid var(--border);
    vertical-align: middle;
}

.slide-modal { max-width: 640px; }

.icon-suggestions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}
.icon-chip {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    cursor: pointer;
    transition: all var(--t-fast);
    padding: 0;
}
.icon-chip:hover {
    border-color: var(--accent);
    color: var(--accent);
    background: var(--accent-light);
    transform: translateY(-1px);
}
.icon-chip svg { width: 16px; height: 16px; }

.color-picker-row {
    display: flex;
    gap: 8px;
    align-items: stretch;
}
.color-swatch {
    width: 44px;
    height: 44px;
    padding: 2px;
    border: 1px solid var(--border-hover);
    border-radius: var(--radius-md);
    background: var(--bg-primary);
    cursor: pointer;
    flex-shrink: 0;
}
.color-swatch::-webkit-color-swatch { border: 0; border-radius: calc(var(--radius-md) - 4px); }
.color-swatch::-moz-color-swatch     { border: 0; border-radius: calc(var(--radius-md) - 4px); }
.color-picker-row .glass-input { flex: 1; min-width: 0; }

.slide-preview-wrap { margin-bottom: var(--space-5); }
.slide-preview-label {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin-bottom: 8px;
}
.slide-preview {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    background: linear-gradient(135deg, var(--accent), var(--accent-secondary));
    border-radius: var(--radius-lg);
    color: #ffffff;
    min-height: 110px;
    position: relative;
    overflow: hidden;
    transition: background 0.3s ease;
}
.slide-preview::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(135deg, rgba(0,0,0,0.10), rgba(0,0,0,0.02) 60%);
    pointer-events: none;
}
.slide-preview-icon {
    width: 52px;
    height: 52px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.20);
    border: 1px solid rgba(255, 255, 255, 0.30);
    border-radius: var(--radius-md);
    color: #ffffff;
    flex-shrink: 0;
    z-index: 1;
}
.slide-preview-icon svg { width: 24px; height: 24px; }
.slide-preview-body { z-index: 1; min-width: 0; flex: 1; }
.slide-preview-title {
    font-size: 18px;
    font-weight: 700;
    letter-spacing: -0.01em;
    margin-bottom: 4px;
    color: #ffffff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.slide-preview-desc {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.92);
    line-height: 1.4;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.slide-preview-btn {
    display: inline-flex;
    align-items: center;
    margin-top: 8px;
    padding: 5px 12px;
    background: rgba(255, 255, 255, 0.20);
    border: 1px solid rgba(255, 255, 255, 0.30);
    border-radius: var(--radius-pill);
    color: #ffffff;
    font-size: 12px;
    font-weight: 500;
    text-decoration: none;
}

/* ============================================================
   UTILITIES
   ============================================================ */
.flex          { display: flex; }
.flex-col      { display: flex; flex-direction: column; }
.items-center  { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-2 { gap: var(--space-2); }
.gap-3 { gap: var(--space-3); }
.gap-4 { gap: var(--space-4); }
.mt-4 { margin-top: var(--space-4); }
.mt-6 { margin-top: var(--space-6); }
.mb-4 { margin-bottom: var(--space-4); }
.mb-6 { margin-bottom: var(--space-6); }
.text-muted     { color: var(--text-tertiary); }
.text-secondary { color: var(--text-secondary); }
.text-accent    { color: var(--accent); }
.text-success   { color: var(--success); }
.text-danger    { color: var(--danger); }
.text-center    { text-align: center; }
.w-full         { width: 100%; }

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 900px) {
    .glass-sidebar {
        transform: translateX(-100%);
        width: var(--sidebar-w);
    }
    .glass-sidebar.is-open { transform: translateX(0); }
    .glass-sidebar.is-collapsed { width: var(--sidebar-w); }
    .glass-header { left: 0 !important; }
    .app-main { margin-left: 0 !important; padding-left: var(--space-4); padding-right: var(--space-4); }
    .sidebar-mobile-toggle {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 36px;
        height: 36px;
        background: var(--bg-secondary);
        border: 1px solid var(--border);
        border-radius: var(--radius-md);
        color: var(--text-primary);
        cursor: pointer;
        font-size: 18px;
        line-height: 1;
    }
    .sidebar-toggle { display: none; }
}

@media (max-width: 600px) {
    h1 { font-size: 24px; }
    .login-card { padding: 28px 24px; }
    .header-user .meta { display: none; }
    .header-user { padding: 4px; }
    .stat-card .value { font-size: 22px; }
}

/* ============================================================
   BOTON HOME (header)
   ============================================================ */
.home-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--accent);
    background: transparent;
    /* Texto → --accent-texto (el vivo da 2,82:1 sobre el header blanco). */
    color: var(--accent-texto);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    transition: all var(--t-fast);
    white-space: nowrap;
}
.home-btn:hover {
    background: var(--accent);
    color: #ffffff;
}
.home-btn svg { width: 14px; height: 14px; }
@media (max-width: 600px) {
    .home-btn { padding: 7px 10px; }
    .home-btn-text { display: none; }
}

/* ============================================================
   SEPARADOR DECORATIVO (••• coral)
   ============================================================ */
.dot-separator {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin: var(--space-8) 0 var(--space-5);
    user-select: none;
}
.dot-separator::before,
.dot-separator::after {
    content: '';
    height: 1px;
    flex: 0 0 56px;
    background: linear-gradient(to right, transparent, var(--border));
}
.dot-separator::after {
    background: linear-gradient(to left, transparent, var(--border));
}
.dot-separator .dots {
    display: inline-flex;
    gap: 6px;
}
.dot-separator .dots span {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--accent);
    opacity: 0.85;
}
.dot-separator .dots span:nth-child(2) { background: var(--accent-secondary); }

/* ============================================================
   MIS MÓDULOS (animated grid)
   ============================================================ */
.work-section { margin-top: var(--space-4); }
.work-section-header {
    text-align: center;
    margin-bottom: var(--space-6);
}
.work-section-header h2 {
    font-size: 24px;
    font-weight: 700;
    color: var(--text-primary);
    margin-bottom: 4px;
}
.work-section-header p {
    color: var(--text-secondary);
    font-size: 15px;
}

.module-work-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-4);
}
@media (max-width: 900px) {
    .module-work-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
    .module-work-grid { grid-template-columns: 1fr; }
}

.module-work-card {
    --m-color: var(--accent);
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-5);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    text-decoration: none;
    color: var(--text-primary);
    /* Estado inicial (oculto, ready para fadeInUp).
     * NO hay transition aqui sobre transform/opacity: el cambio inicial->visible
     * se anima via @keyframes fadeInUp, y el hover-lift via la propiedad
     * declarada en .is-visible:hover (sin animation: none). */
    opacity: 0;
    transform: translateY(30px);
    transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
/* Estado VISIBLE: declara explicitamente el estado final
 * para que sea "sticky" aunque algo desactive la animacion. */
.module-work-card.is-visible {
    opacity: 1;
    transform: translateY(0);
    animation: fadeInUp 0.5s ease-out;
}
.module-work-card.is-visible:hover {
    transform: translateY(-4px);
    border-color: var(--accent);
    box-shadow: 0 8px 24px rgba(255, 107, 74, 0.15);
}
/* Accesibilidad: si el usuario prefiere movimiento reducido,
 * sin animacion ni transform inicial, las cards aparecen directas. */
@media (prefers-reduced-motion: reduce) {
    .module-work-card {
        opacity: 1;
        transform: none;
        animation: none;
    }
}

/* Keyframes inmediatamente despues de la regla que los usa, para que
 * sea trivial encontrarlos al editar. */
@keyframes fadeInUp {
    from {
        opacity: 0;
        transform: translateY(30px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}
.module-work-icon {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--m-color) 14%, transparent);
    color: var(--m-color);
    flex-shrink: 0;
    transition: background var(--t-fast);
}
.module-work-card:hover .module-work-icon {
    background: color-mix(in srgb, var(--m-color) 20%, transparent);
}
.module-work-icon svg { width: 24px; height: 24px; stroke-width: 2; }

.module-work-body { flex: 1; min-width: 0; }
.module-work-name {
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: 2px;
    display: flex;
    align-items: center;
    gap: 8px;
}
.module-work-desc {
    font-size: 13px;
    color: var(--text-secondary);
    line-height: 1.45;
}
.module-work-arrow {
    color: var(--text-tertiary);
    transition: transform 0.2s ease, color 0.2s ease;
    flex-shrink: 0;
    display: inline-flex;
}
.module-work-arrow svg { width: 18px; height: 18px; }
.module-work-card:hover .module-work-arrow {
    transform: translateX(4px);
    color: var(--accent);
}

/* Stagger preset classes (por si se prefiere CSS-only) */
.stagger-1 { animation-delay: 0.05s !important; }
.stagger-2 { animation-delay: 0.15s !important; }
.stagger-3 { animation-delay: 0.25s !important; }
.stagger-4 { animation-delay: 0.35s !important; }
.stagger-5 { animation-delay: 0.45s !important; }
.stagger-6 { animation-delay: 0.55s !important; }
.stagger-7 { animation-delay: 0.65s !important; }
.stagger-8 { animation-delay: 0.75s !important; }

/* ============================================================
   LAYOUT SIN SIDEBAR (v2)
   Body class: .layout-no-sidebar
   - Sidebar eliminado: header full-width, main centrado.
   - Dropdowns en header: Módulos + Usuario.
   ============================================================ */
body.layout-no-sidebar .glass-header {
    left: 0;
}
body.layout-no-sidebar .main-content {
    margin: 0 auto;
    /* ------------------------------------------------------------------
       ANCHO ÚTIL: 1400 → 1760px (2026-08-05).
       En 1920 quedaban 411px sin usar mientras 11 rutas de 5 módulos pedían
       MÁS de los 1352px útiles que dejaba el 1400 (ancho NATURAL de cada
       tabla, medido con `table{width:auto}` sobre las 53 rutas):
       com_sedes 2160 · com_contactos 2046 · com_puestos 1947 ·
       gh_contratos 1868 · con_historico 1831 · com_contratos 1762 ·
       com_clientes 1606 · gh_asociados 1526 · com 1504 · usuarios 1467 ·
       gh 1421. Las que no lo piden NO crecen: una tabla que pide 613px se
       queda en 613px aunque el contenedor tenga 1760.
       `min()` → a 1366px manda el 100% y no cambia nada; se nota de ~1800
       de viewport en adelante.
       Va acá y no en siga-redesign.css a propósito: el bundle Aurora sólo
       lo carga el Super Admin (layout.php: `$auroraOn = isSuperAdmin()`),
       así que allí lo veía UNA persona. Aurora lo hereda por cascada.
       Los tres techos que acompañan a este ensanche están en las reglas de
       `.toolbar > .grow`, `.field-row` y `.empty-state`; el cuarto vive en
       el <style> de modules/com/novedades.php (.com-tl-desc).
       ------------------------------------------------------------------ */
    max-width: min(1760px, 100%);
    padding: calc(var(--header-h) + var(--space-6)) var(--space-6) var(--space-8);
    min-height: 100vh;
}
@media (max-width: 720px) {
    body.layout-no-sidebar .main-content {
        padding-left: var(--space-4);
        padding-right: var(--space-4);
    }
}

/* Header brand (logo SIGA en header) */
.header-brand {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    text-decoration: none;
    line-height: 0;
}
.header-brand-logo {
    height: 30px;
    width: auto;
    transition: opacity var(--t-fast);
}
.header-brand:hover .header-brand-logo { opacity: 0.85; }
@media (max-width: 600px) {
    .header-brand-logo { height: 24px; }
}

/* User chevron */
.user-chevron {
    width: 14px;
    height: 14px;
    color: var(--text-tertiary);
    margin-left: 2px;
    margin-right: 6px;
    transition: transform var(--t-fast);
}
.header-user[aria-expanded="true"] .user-chevron {
    transform: rotate(180deg);
}
.header-user {
    cursor: pointer;
    transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.header-user:hover {
    border-color: var(--accent);
}
.header-user[aria-expanded="true"] {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-light);
}

/* ============================================================
   DROPDOWN WRAPPER (relative anchor)
   ============================================================ */
.header-dropdown-wrap {
    position: relative;
}

/* ============================================================
   MODULES DROPDOWN
   ============================================================ */
.header-modules-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    color: var(--text-secondary);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: all var(--t-fast);
}
.header-modules-btn:hover,
.header-modules-btn[aria-expanded="true"] {
    background: var(--accent-light);
    border-color: var(--accent);
    color: var(--accent);
}
.header-modules-btn svg {
    width: 16px;
    height: 16px;
    stroke-width: 2;
}
@media (max-width: 600px) {
    .header-modules-text { display: none; }
    .header-modules-btn { padding: 8px; }
}

.modules-dropdown {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    width: 380px;
    max-width: calc(100vw - 32px);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-4);
    z-index: 60;
    animation: dropdownFade 0.18s ease-out both;
}
@keyframes dropdownFade {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}
.modules-dropdown-title {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1.2px;
    color: var(--text-tertiary);
    margin-bottom: var(--space-3);
    padding: 0 4px;
}
.modules-dropdown-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-2);
}
@media (max-width: 480px) {
    .modules-dropdown { width: calc(100vw - 24px); right: -8px; }
    .modules-dropdown-grid { grid-template-columns: repeat(2, 1fr); }
}

.module-tile {
    --m-color: var(--accent);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 14px 8px;
    border-radius: var(--radius-md);
    text-decoration: none;
    color: var(--text-secondary);
    background: transparent;
    border: 1px solid transparent;
    transition: all var(--t-fast);
    text-align: center;
}
.module-tile:hover {
    background: var(--bg-secondary);
    border-color: var(--border);
    transform: translateY(-2px);
    color: var(--text-primary);
}
.module-tile-icon {
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--m-color) 14%, transparent);
    color: var(--m-color);
    transition: background var(--t-fast);
}
.module-tile:hover .module-tile-icon {
    background: color-mix(in srgb, var(--m-color) 22%, transparent);
}
.module-tile-icon svg {
    width: 22px;
    height: 22px;
    stroke-width: 2;
}
.module-tile-name {
    font-size: 12px;
    font-weight: 600;
    line-height: 1.25;
}

/* ============================================================
   USER DROPDOWN
   ============================================================ */
.user-dropdown {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    width: 320px;
    max-width: calc(100vw - 32px);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-3) 0;
    z-index: 60;
    animation: dropdownFade 0.18s ease-out both;
}
@media (max-width: 480px) {
    .user-dropdown { width: calc(100vw - 24px); right: -8px; }
}

.user-dropdown-header {
    padding: var(--space-2) var(--space-4) var(--space-3);
}
.user-dropdown-name {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.2;
    word-break: break-word;
}
.user-dropdown-role {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--text-tertiary);
    margin-top: 4px;
    font-weight: 600;
}
.user-dropdown-divider {
    height: 1px;
    background: var(--border);
    margin: var(--space-2) 0;
}

.user-dropdown-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.user-dropdown-item {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 10px var(--space-4);
}
.user-dropdown-icon {
    width: 16px;
    height: 16px;
    color: var(--accent);
    flex-shrink: 0;
    margin-top: 2px;
}
.user-dropdown-item-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-tertiary);
    font-weight: 600;
    margin-bottom: 2px;
}
.user-dropdown-item-value {
    font-size: 13px;
    color: var(--text-primary);
    word-break: break-all;
}
.user-dropdown-item-value small {
    display: block;
    font-size: 11px;
    margin-top: 2px;
}

.user-dropdown-link {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 10px var(--space-4);
    background: transparent;
    border: 0;
    text-align: left;
    text-decoration: none;
    color: var(--text-primary);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background var(--t-fast);
    font-family: inherit;
}
.user-dropdown-link svg {
    width: 16px;
    height: 16px;
    color: var(--text-secondary);
    flex-shrink: 0;
}
.user-dropdown-link:hover:not(.is-disabled) {
    background: var(--bg-secondary);
}
.user-dropdown-link.is-disabled {
    cursor: not-allowed;
    opacity: 0.55;
}
.user-dropdown-link.is-disabled small {
    margin-left: auto;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.user-dropdown-link-danger {
    color: var(--danger, #dc2626);
}
.user-dropdown-link-danger svg { color: var(--danger, #dc2626); }
.user-dropdown-link-danger:hover {
    background: color-mix(in srgb, var(--danger, #dc2626) 8%, transparent);
}

/* ============================================================
   DASHBOARD SLIDER v2 — más grande + soporte imagen
   ============================================================ */
/* =========================================================================
   v2.43.0 §5 · EL CARRUSEL SE COMÍA LA MITAD DE LA PRIMERA PANTALLA
   =========================================================================
   Medido en el banco visual: el alto real era **300 px**, no los 200 de la
   regla base — esta regla la pisa. Con un visor de 695 px útiles, entre el
   header (80), el saludo y el carrusel con su margen no quedaba sitio para
   «Mis módulos» ni para las tareas sin bajar, que son las dos cosas por las
   que alguien entra a Inicio.

   ⚠️ **Hay que bajar los DOS `min-height`**, y es la parte no obvia: el del
   contenedor y el del `.slide` de adentro. Bajando sólo el primero, el slide
   sigue pidiendo sus 300 px y los empuja de vuelta desde dentro — el
   contenedor no puede ser más bajo que su contenido.

   Por eso el valor vive en **una variable**: dos números escritos a mano se
   separan, y cuando se separan el síntoma es que el carrusel «no obedece».

   Se hace proporcional al alto de la ventana con `clamp`: en una pantalla
   baja se achica más, en una alta crece un poco. Así el ajuste no depende de
   la resolución en la que se midió.
   ========================================================================= */
body.layout-no-sidebar {
    --slider-h: clamp(170px, 24vh, 240px);
}
body.layout-no-sidebar .dash-slider {
    height: auto;
    min-height: var(--slider-h);
    border-radius: 24px;
    margin-bottom: var(--space-5);
}
body.layout-no-sidebar .dash-slider .slide {
    min-height: var(--slider-h);
}
body.layout-no-sidebar .dash-slider .slide-title {
    font-size: 26px;
}
body.layout-no-sidebar .dash-slider .slide-desc {
    font-size: 15px;
}

/* Slide image-only variant */
.dash-slider .slide.slide-image {
    padding: 0;
}
.dash-slider .slide.slide-image::before {
    /* overlay sutil para mejor contraste de dots, pero NO tinte fuerte */
    background: linear-gradient(180deg, rgba(0,0,0,0) 70%, rgba(0,0,0,0.25));
}
.slide-image-link {
    position: absolute;
    inset: 0;
    z-index: 2;
    background: transparent;
    text-indent: -9999px;
}
.slide-image-link:focus-visible {
    outline: 3px solid #ffffff;
    outline-offset: -6px;
    border-radius: inherit;
}

@media (max-width: 600px) {
    body.layout-no-sidebar .dash-slider,
    body.layout-no-sidebar .dash-slider .slide {
        min-height: 240px;
    }
    body.layout-no-sidebar .dash-slider .slide-title { font-size: 20px; }
}

/* ============================================================
   DASHBOARD FOOTER
   ============================================================ */
.dash-footer {
    margin-top: var(--space-8);
    padding-top: var(--space-5);
    border-top: 1px solid var(--border);
    text-align: center;
    color: var(--text-tertiary);
    font-size: 12px;
    letter-spacing: 0.3px;
}

/* ============================================================
   FIELD HINT (forms helper text)
   ============================================================ */
.field-hint {
    font-size: 12px;
    color: var(--text-tertiary);
    margin-top: 6px;
    line-height: 1.4;
}

/* ============================================================
   SLIDE PREVIEW v2 (modal admin) — soporta modo imagen
   ============================================================ */
.slide-preview.is-image {
    min-height: 160px;
    padding: 0;
}
.slide-preview.is-image::before {
    display: none;
}

/* ============================================================
   TIC — Mesa de Ayuda IT
   ============================================================ */

/* ---- KPIs ---- */
/* auto-fill y NO auto-fit: con auto-fit las columnas vacías colapsan y la
   tarjeta que queda sola en la última fila se ESTIRA a todo el ancho —
   es lo que pasaba en GH con 8 tarjetas en 7 columnas. Con auto-fill la
   huérfana conserva su ancho normal.

   El piso es 280px, NO 200px. Con 200 las 8 de GH entraban en una sola fila
   pero a 206px cada una, y ahí dos etiquetas ("Requisitos por vencer (30
   días)", "Contratos por vencer (30 días)") se partían en TRES líneas y
   desalineaban la franja; además las 4 tarjetas de TIC/CON quedaban
   agrupadas a la izquierda dejando 870px muertos contra un panel de ancho
   completo. Medido con los 6 conteos reales (TIC/CON 4 · SED 5 · PRG 7 ·
   GH 8 · ALM 10) en los 3 anchos útiles (1712/1480/1310): con 280 ninguna
   etiqueta se parte, ninguna tarjeta se estira y sobran como mucho 3
   columnas. Preferir dos filas parejas antes que una fila apretada. */
.kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-6);
}
.kpi-card {
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-5);
    display: flex;
    align-items: center;
    gap: var(--space-4);
    box-shadow: var(--shadow-sm);
    min-width: 0;   /* los grid items traen min-width:auto y desbordan la columna */
    /* Contenedor de consulta: habilita el escalón de .kpi-value en tarjeta
       angosta (ver abajo). El ancho lo fija la grilla, no el contenido, así
       que la contención en el eje inline no cambia nada del layout actual. */
    container-type: inline-size;
    /* Sin `transform`: el hover confirma interactividad, no la celebra. */
    transition: box-shadow var(--t-fast), border-color var(--t-fast);
}
/* Hover HONESTO: sólo donde la tarjeta lleva a algún lado. */
@media (hover: hover) {
    .kpi-card.is-clickable:hover {
        box-shadow: var(--shadow-md);
        border-color: var(--border-hover);
    }
}
.kpi-card:focus-within { outline: 2px solid var(--accent-texto); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .kpi-card { transition: none; } }
/* ---- Ícono: disco TENUE, glifo del color de la familia ----
   El disco es decorativo (el dato lo dicen el número y la etiqueta), así que
   la única medición que la norma exige —WCAG G207— es la del GLIFO contra su
   propio tinte. El tinte se compone contra lo que haya detrás
   (`color-mix(… , transparent)` = el color al N % de alfa), no contra un hex
   calculado sobre blanco puro: por eso una sola regla sirve para los cuatro
   modos, y por eso no se puede volver a escapar un blanco sobre blanco.
   `--kpi-c` lo inyecta siga_kpi_icono() en el style inline de cada tarjeta. */
.kpi-icon {
    width: 48px; height: 48px;
    border-radius: 12px;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    background: color-mix(in oklab, var(--kpi-c, transparent) var(--kpi-tinte), var(--kpi-velo));
    color: var(--kpi-c, var(--kpi-apagado-ink));
    /* Aro de 1px del propio color: es lo que hace que el disco se perciba, ya
       que el relleno al 8 % da 1,20:1 en claro y 1,02:1 en oscuro. En el
       estado apagado --kpi-c no existe, el color-mix resuelve a transparente y
       el aro no se dibuja: ahí el relleno solo ya da 1,29:1. */
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--kpi-c, transparent) var(--kpi-aro), transparent);
}
.kpi-icon svg { width: 24px; height: 24px; }
/* Clases variante legacy: ningún módulo las usa desde el barrido de la regla
   del cero (una clase no puede apagarse sola cuando el contador está en 0),
   pero si alguna vista nueva las tomara, que salgan con la piel de hoy. */
.kpi-icon-info    { --kpi-c: var(--kpi-dinero); }
.kpi-icon-warning { --kpi-c: var(--kpi-compromisos); }
.kpi-icon-success { --kpi-c: var(--kpi-puestos); }
.kpi-icon-danger  { --kpi-c: var(--kpi-compromisos); }
.kpi-value {
    font-size: 28px;
    /* 600, no 700: en las sans modernas el 700 se ve tosco a este tamaño. */
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.05;
    letter-spacing: -.025em;
    /* Proporcionales, NO tabular-nums: tabular es para columnas que se alinean
       verticalmente (tablas), no para una fila de valores independientes. */
    font-variant-numeric: proportional-nums lining-nums;
}
/* ⚠️ El único valor largo de la app es el importe de COM: "$ 1.217.426.680"
   mide 191px a 28px de cuerpo, y la columna de texto de la tarjeta (ancho −
   40 de padding − 48 del ícono − 16 del gap) baja a 176px cuando la grilla
   toca su piso de 280px. Medido: el número se salía 16px sobre el padding
   derecho en clásico y 24px POR FUERA del borde en Aurora (donde el cuerpo es
   32px). No se puede abreviar el importe ("$1,2 B" pierde $17.426.680) ni
   partirlo — no tiene puntos de corte y romperlo entre dígitos es peor.
   El escalón baja el cuerpo SÓLO en tarjeta angosta, y como la regla vive en
   `.kpi-value` la aplican COM y GH por igual: los dos siguen computando lo
   mismo a cualquier ancho, que es la condición de esta tanda.
   ⚠️ La consulta mide el CONTENT BOX del contenedor, no el borde: hay que
   restarle el borde (2) y el padding (40). Umbral = 191 del número + 64 del
   ícono y su gap ≈ 256 de contenido, o sea tarjeta de ~298px para abajo. */
@container (max-width: 256px) {
    .kpi-value { font-size: 24px; }
}
/* Mosaico de NAVEGACIÓN, no franja de métricas: `alm/dashboard.php` reusa la
   tarjeta para los accesos rápidos y ahí la línea principal es un TÍTULO
   ("Stock actual"), no un número — el cuerpo de 28px sería absurdo. Es la
   ÚNICA excepción viva a "la tarjeta de KPI tiene una sola escala": vive acá
   y no en un `style` inline, que le ganaría al escalón de arriba. El tracking
   negativo se anula porque está calibrado para cifras, no para palabras. */
.kpi-card--acceso .kpi-value { font-size: 15px; letter-spacing: 0; }
.kpi-label {
    font-size: 13px;
    color: var(--text-secondary);
    margin-top: 2px;
}
/* Tercera línea OPCIONAL: contexto del número (denominador en palabras, enlace
   al detalle). Nació como parte de la variante --detalle de COM; al colapsar
   las dos caras en una sola quedó disponible para cualquier módulo. */
.kpi-sub {
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.35;
    margin-top: 3px;
}
.kpi-sub a {
    color: var(--accent-texto); text-decoration: none;
    border-bottom: 1px solid color-mix(in oklab, var(--accent-texto) 30%, transparent);
}
.kpi-sub a:hover { border-bottom-color: currentColor; }

/* Símbolo de moneda atenuado y a baseline (nunca superíndice). */
.kpi-cur {
    font-size: .58em; font-weight: 500; color: var(--text-muted);
    margin-right: .12em; letter-spacing: 0;
}
/* Denominador de una fracción: es contexto, no dato. */
.kpi-den {
    font-size: .48em; font-weight: 500; color: var(--text-muted);
    letter-spacing: 0; margin-left: .06em;
}
.kpi-card.is-alerta { border-color: color-mix(in oklab, var(--accent) 26%, var(--border)); }

/* ⚠️ Acá vivían `.kpi-bar`, `.kpi-dot`, `.kpi-card--detalle`,
   `.kpi-grid--detalle`, `.kpi-grid--sec` y `.kpi-card--sec` — la segunda cara
   de la tarjeta, que sólo usaba COM. Se eliminaron: no basta con compartir la
   superficie, un número de 21px al lado de uno de 28px se lee como otro
   producto. Del bloque sobrevive `.kpi-sub` (arriba). La barra de proporción,
   además, en producción quedaba como una línea de 3px cruzando los 416px de la
   tarjeta: se leía como subrayado de error, no como proporción. Y el punto de
   estado, junto a un ícono de color, era la misma señal dos veces. */

/* ---- KPIs analíticos (mini row) ---- */
.kpi-mini-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--space-3);
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px dashed var(--border);
}
.kpi-mini {
    padding: var(--space-3) var(--space-4);
    background: var(--bg-secondary);
    border-radius: var(--radius-md);
}
.kpi-mini-label {
    font-size: 11px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 4px;
}
.kpi-mini-value {
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
}

/* ---- Chart section (dona + leyenda) ---- */
.chart-section {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-6);
    align-items: start;
    margin-bottom: var(--space-4);
}
@media (max-width: 720px) {
    .chart-section {
        grid-template-columns: 1fr;
        gap: var(--space-4);
    }
}
.chart-donut-wrap {
    display: flex;
    align-items: center;
    justify-content: center;
}
.chart-donut { display: block; }
.chart-donut-total {
    font-size: 26px;
    font-weight: 700;
    fill: var(--text-primary);
}
.chart-donut-label {
    font-size: 11px;
    fill: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.chart-legend {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.chart-legend-row {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 13px;
    color: var(--text-primary);
}
.legend-dot {
    width: 12px; height: 12px;
    border-radius: 3px;
    flex-shrink: 0;
}
.legend-name { flex: 1; }
.legend-count {
    font-weight: 600;
    color: var(--text-primary);
}
.legend-count small {
    font-weight: 400;
    color: var(--text-secondary);
    margin-left: 4px;
}

/* ---- Subtítulo dentro del panel ---- */
.chart-subtitle {
    margin: var(--space-5) 0 var(--space-3);
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* ---- Bar chart (subcategorías) ---- */
.bar-chart {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.bar-row {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 13px;
}
.bar-name {
    width: 200px;
    flex-shrink: 0;
    text-align: right;
    color: var(--text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
@media (max-width: 720px) {
    .bar-name { width: 120px; }
}
.bar-track {
    flex: 1;
    height: 22px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
}
.bar-fill {
    height: 100%;
    border-radius: 5px;
    display: flex;
    align-items: center;
    padding-left: 8px;
    font-size: 12px;
    font-weight: 600;
    color: #fff;
    min-width: 28px;
    transition: width var(--t-normal);
}

/* ---- Badges de prioridad ---- */
.glass-badge-critica {
    background: rgba(239,68,68,0.12);
    color: #dc2626;
    border: 1px solid rgba(239,68,68,0.25);
}
.glass-badge-alta {
    background: rgba(245,158,11,0.12);
    color: #d97706;
    border: 1px solid rgba(245,158,11,0.25);
}
.glass-badge-media {
    background: rgba(59,130,246,0.12);
    color: #2563eb;
    border: 1px solid rgba(59,130,246,0.25);
}
.glass-badge-baja {
    background: rgba(107,114,128,0.12);
    color: #6b7280;
    border: 1px solid rgba(107,114,128,0.25);
}

/* ---- Botón pequeño (para acciones rápidas) ---- */
.glass-btn-sm {
    padding: 6px 12px;
    font-size: 12px;
}

/* ---- Tema oscuro: ajustes ---- */
[data-theme="dark"] .kpi-card {
    background: var(--bg-primary);
}
[data-theme="dark"] .kpi-mini {
    background: var(--bg-tertiary);
}
[data-theme="dark"] .bar-track {
    background: var(--bg-tertiary);
}

/* ============================================================
   TIC — Vista detalle de ticket
   ============================================================ */

.breadcrumb-mini {
    margin-bottom: var(--space-2);
    font-size: 13px;
}
.breadcrumb-mini a {
    color: var(--text-secondary);
    text-decoration: none;
    transition: color var(--t-fast);
}
.breadcrumb-mini a:hover { color: var(--accent); }

.ticket-detail {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: var(--space-6);
    align-items: start;
    margin-bottom: var(--space-6);
}
@media (max-width: 960px) {
    .ticket-detail {
        grid-template-columns: 1fr;
    }
}

.ticket-sidebar {
    position: sticky;
    top: 20px;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-5);
    box-shadow: var(--shadow-sm);
}
@media (max-width: 960px) {
    .ticket-sidebar { position: static; }
}

.ticket-card-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 0 var(--space-3);
    display: flex;
    align-items: center;
    gap: 8px;
}

.ticket-card .ticket-description {
    color: var(--text-primary);
    line-height: 1.6;
    font-size: 14.5px;
    white-space: pre-wrap;
    word-wrap: break-word;
}

.ticket-meta-pill {
    margin-top: var(--space-3);
    padding: 8px 12px;
    background: var(--bg-secondary);
    border-radius: var(--radius-pill);
    display: inline-flex;
    gap: 6px;
    align-items: center;
    font-size: 13px;
}

.ticket-solution {
    margin-top: var(--space-4);
    padding: var(--space-4);
    background: rgba(34,197,94,0.08);
    border-left: 3px solid #22c55e;
    border-radius: var(--radius-md);
    font-size: 14px;
    line-height: 1.5;
}
.ticket-solution-title {
    font-weight: 600;
    margin-bottom: 6px;
    color: #15803d;
    display: flex; align-items: center; gap: 6px;
}
.ticket-solution-title svg { width: 16px; height: 16px; }

.ticket-pause {
    margin-top: var(--space-4);
    padding: var(--space-4);
    background: rgba(107,114,128,0.08);
    border-left: 3px solid #6b7280;
    border-radius: var(--radius-md);
    font-size: 14px;
}
.ticket-pause-title {
    font-weight: 600;
    margin-bottom: 6px;
    color: var(--text-primary);
    display: flex; align-items: center; gap: 6px;
}

.ticket-cancel {
    margin-top: var(--space-4);
    padding: var(--space-4);
    background: rgba(239,68,68,0.08);
    border-left: 3px solid #ef4444;
    border-radius: var(--radius-md);
    font-size: 14px;
}
.ticket-cancel-title {
    font-weight: 600;
    margin-bottom: 6px;
    color: #b91c1c;
    display: flex; align-items: center; gap: 6px;
}

/* ---- Timeline ---- */
.ticket-timeline {
    list-style: none;
    padding: 0;
    margin: 0 0 var(--space-4);
}
.timeline-item {
    display: grid;
    grid-template-columns: 36px 1fr;
    gap: var(--space-3);
    padding-bottom: var(--space-4);
    position: relative;
}
.timeline-item:not(:last-child)::before {
    content: '';
    position: absolute;
    left: 17px;
    top: 36px;
    bottom: -4px;
    width: 2px;
    background: var(--border);
}
.timeline-icon {
    width: 36px; height: 36px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    color: #fff;
    flex-shrink: 0;
    box-shadow: 0 0 0 3px var(--bg-primary);
    z-index: 1;
}
.timeline-icon svg { width: 16px; height: 16px; }

.timeline-body {
    min-width: 0;
}
.timeline-header {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 10px;
    align-items: center;
    margin-bottom: 4px;
    font-size: 13px;
    color: var(--text-primary);
}
.timeline-type {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-tertiary);
    background: var(--bg-secondary);
    padding: 2px 8px;
    border-radius: var(--radius-pill);
}
.timeline-time {
    margin-left: auto;
    font-size: 12px;
    color: var(--text-secondary);
}
.timeline-content {
    font-size: 14px;
    color: var(--text-secondary);
    line-height: 1.5;
    white-space: pre-wrap;
    word-wrap: break-word;
}

.timeline-item.is-solution .timeline-content { color: var(--text-primary); }

/* ---- Comment form ---- */
.comment-form {
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px dashed var(--border);
}
.comment-form .field-label {
    display: block;
    margin-bottom: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}

/* ---- Meta blocks (sidebar derecho) ---- */
.meta-block {
    padding-bottom: var(--space-3);
    border-bottom: 1px dashed var(--border);
}
.meta-block:last-child {
    padding-bottom: 0;
    border-bottom: none;
}
.meta-block.meta-actions {
    padding-top: var(--space-2);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.meta-label {
    font-size: 11px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.meta-edit-btn {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-secondary);
    border-radius: 6px;
    width: 24px; height: 24px;
    display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer;
    transition: all var(--t-fast);
}
.meta-edit-btn:hover {
    border-color: var(--accent);
    color: var(--accent);
}
.meta-edit-btn svg { width: 12px; height: 12px; }
.meta-badge-lg {
    font-size: 13px;
    padding: 6px 14px;
}
.meta-value {
    font-size: 14px;
    color: var(--text-primary);
}
.meta-value .text-muted { font-size: 13px; }
.meta-chip {
    display: inline-block;
    padding: 4px 10px;
    background: var(--accent-light);
    color: var(--accent);
    border-radius: var(--radius-pill);
    font-size: 12px;
    font-weight: 600;
    margin-right: 4px;
}
.meta-chip-soft {
    background: var(--bg-secondary);
    color: var(--text-secondary);
}
.meta-fechas {
    list-style: none;
    padding: 0;
    margin: 0;
    font-size: 13px;
}
.meta-fechas li {
    display: flex;
    justify-content: space-between;
    padding: 4px 0;
}
.meta-fechas li span {
    color: var(--text-secondary);
}

/* ---- SLA bar ---- */
.sla-bar {
    height: 8px;
    background: var(--bg-secondary);
    border-radius: 4px;
    overflow: hidden;
    margin-bottom: 8px;
}
.sla-fill {
    height: 100%;
    border-radius: 4px;
    transition: width var(--t-normal);
}
.sla-bar.sla-ok       .sla-fill { background: #22c55e; }
.sla-bar.sla-warn     .sla-fill { background: #f59e0b; }
.sla-bar.sla-overdue  .sla-fill { background: #ef4444; }
.sla-text { font-size: 13px; }

/* ---- Inline forms (en sidebar) ---- */
.inline-form {
    margin-top: var(--space-3);
    padding: var(--space-3);
    background: var(--bg-secondary);
    border-radius: var(--radius-md);
}
.inline-form-actions {
    display: flex;
    gap: 6px;
    justify-content: flex-end;
    margin-top: var(--space-2);
}
.field-label-sm {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    margin-bottom: 4px;
}

/* ---- Botones de bloque (full width) ---- */
.glass-btn-block {
    display: flex;
    width: 100%;
    justify-content: center;
    gap: 8px;
}
.glass-btn-danger {
    background: rgba(239,68,68,0.08);
    color: #dc2626;
    border-color: rgba(239,68,68,0.25);
}
.glass-btn-danger:hover {
    background: rgba(239,68,68,0.16);
    border-color: rgba(239,68,68,0.45);
}

/* ---- Star rating ---- */
.star-rating {
    display: inline-flex;
    gap: 4px;
}
.star-rating .star {
    background: transparent;
    border: none;
    cursor: pointer;
    color: var(--border-hover);
    padding: 4px;
    transition: color var(--t-fast), transform var(--t-fast);
}
.star-rating .star svg { width: 28px; height: 28px; }
.star-rating .star:hover { transform: scale(1.1); }
.star-rating .star.is-filled,
.star-rating .star.is-filled svg { color: #f59e0b; fill: #f59e0b; }
.star-rating.is-readonly .star {
    cursor: default;
    padding: 0;
}
.star-rating.is-readonly .star:hover { transform: none; }

/* ============================================================
   TIC — Configuración (subtabs + categorías jerárquicas + chips)
   ============================================================ */

.subtabs {
    display: flex;
    gap: 4px;
    margin: 0 0 var(--space-5);
    padding: 4px;
    background: var(--bg-secondary);
    border-radius: var(--radius-pill);
    width: fit-content;
}
.subtab {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 16px;
    border-radius: var(--radius-pill);
    text-decoration: none;
    color: var(--text-secondary);
    font-size: 13px;
    font-weight: 500;
    transition: background var(--t-fast), color var(--t-fast);
}
.subtab svg { width: 14px; height: 14px; }
.subtab:hover { color: var(--text-primary); }
.subtab.is-active {
    background: var(--bg-primary);
    color: var(--accent);
    font-weight: 600;
    box-shadow: var(--shadow-sm);
}

/* ---- Categorías: filas indentadas ---- */
.cat-row .cat-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px; height: 24px;
    background: var(--accent-light);
    color: var(--accent);
    border-radius: 6px;
    margin-right: 8px;
    vertical-align: middle;
}
.cat-row .cat-icon svg { width: 14px; height: 14px; }
.cat-row.is-sub td {
    background: var(--bg-secondary);
}
.cat-row.is-sub .sub-arrow {
    color: var(--text-tertiary);
    margin-right: 6px;
}
[data-theme="dark"] .cat-row.is-sub td {
    background: var(--bg-tertiary);
}

/* ---- Checkbox pills (especialidad) ---- */
.checkbox-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 4px;
}
.checkbox-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    cursor: pointer;
    user-select: none;
    transition: all var(--t-fast);
    font-size: 13px;
}
.checkbox-pill:hover {
    border-color: var(--accent);
}
.checkbox-pill input[type="checkbox"] {
    margin: 0;
    accent-color: var(--accent);
}
.checkbox-pill:has(input:checked) {
    background: var(--accent-light);
    border-color: var(--accent);
    color: var(--accent);
    font-weight: 600;
}

/* ============================================================
   SIS — Slides upload + delete
   ============================================================ */

/* Boton icono peligro (eliminar) */
.glass-btn-icon-danger {
    color: var(--danger);
}
.glass-btn-icon-danger:hover {
    background: rgba(239,68,68,0.10);
    border-color: rgba(239,68,68,0.30);
    color: var(--danger);
}

/* Zona de drop / upload */
.upload-dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 18px 16px;
    border: 2px dashed var(--border-hover);
    border-radius: var(--radius-md);
    background: var(--bg-secondary);
    cursor: pointer;
    transition: all var(--t-fast);
    text-align: center;
}
.upload-dropzone:hover {
    border-color: var(--accent);
    background: var(--accent-light);
}
.upload-dropzone svg {
    width: 28px; height: 28px;
    color: var(--text-tertiary);
    margin-bottom: 2px;
}
.upload-dropzone:hover svg {
    color: var(--accent);
}
.upload-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}
.upload-hint {
    font-size: 11px;
    color: var(--text-tertiary);
}

/* Preview de la imagen subida */
.slide-img-preview {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 8px;
    padding: 8px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.slide-img-preview img {
    max-width: 100%;
    max-height: 160px;
    border-radius: var(--radius-sm);
    object-fit: cover;
}
.slide-img-preview .glass-btn {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 28px; height: 28px;
    padding: 0;
    background: rgba(255,255,255,0.92);
    backdrop-filter: blur(6px);
    border: 1px solid var(--border);
}
.slide-img-preview .glass-btn svg { width: 14px; height: 14px; }

/* ============================================================
   LOGIN — Fondo CSS animado (orbes flotantes)
   ============================================================ */

/* Body con clase has-orbs: base oscura + ocultar blobs coral del bg base */
.login-page.has-orbs {
    background: #1a1a2e;
}
.login-page.has-orbs::before,
.login-page.has-orbs::after {
    display: none;
}

/* Contenedor fijo que cubre la pantalla; sus hijos son los 3 orbes */
.login-orbs {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
}
.login-orb {
    position: absolute;
    border-radius: 50%;
    filter: blur(60px);
    opacity: 0.6;
    will-change: transform;
    animation: login-orb-float 15s ease-in-out infinite;
}
.login-orb-1 {
    width: 300px; height: 300px;
    background: #D85A30;       /* coral */
    top: -60px; left: -60px;
    animation-delay: 0s;
}
.login-orb-2 {
    width: 250px; height: 250px;
    background: #534AB7;       /* purpura */
    bottom: -50px; right: -50px;
    animation-delay: -5s;
}
.login-orb-3 {
    width: 200px; height: 200px;
    background: #1D9E75;       /* teal */
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);  /* sustituido por keyframes durante la animacion */
    animation-delay: -10s;
}

@keyframes login-orb-float {
    0%, 100% { transform: translate(0, 0) scale(1); }
    25%      { transform: translate(30px, -40px) scale(1.1); }
    50%      { transform: translate(-20px, 30px) scale(0.9); }
    75%      { transform: translate(40px, 20px) scale(1.05); }
}

@media (prefers-reduced-motion: reduce) {
    .login-orb { animation: none; }
}

/* Card sobre el fondo oscuro: efecto glass con white translucido + blur. */
/* Forzamos tokens light dentro del card para legibilidad consistente
   en modo claro y oscuro (el fondo de la pagina es siempre oscuro aqui). */
.login-page.has-orbs .login-card {
    --bg-primary:    #ffffff;
    --bg-secondary:  #FDF5F0;
    --bg-tertiary:   #F8F0EB;
    --text-primary:    #1a1a1a;
    --text-secondary:  #716867;
    --text-tertiary:   #76706E;   /* era #a39e9d → 2.65:1; ahora 4.87:1 (ver :root) */
    --text-muted:      var(--text-tertiary);
    --border:        #F0E8E4;
    --border-hover:  #E0D5D0;
    --glass-bg:             var(--bg-primary);
    --glass-border:         var(--border);

    z-index: 2;
    background: rgba(255, 255, 255, 0.92);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.10);
    border-color: rgba(255, 255, 255, 0.6);
}

/* ============================================================
   LOGIN — OTP en 6 celdas (verify_code.php)
   ============================================================ */
.otp-grid {
    display: flex;
    justify-content: center;
    gap: 10px;
    margin: 0 auto var(--space-2);
}
.otp-cell {
    width: 48px;
    height: 56px;
    padding: 0;
    text-align: center;
    font-family: var(--font-mono);
    font-size: 28px;
    font-weight: 600;
    line-height: 1;
    color: var(--text-primary);
    caret-color: var(--accent);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-bottom: 2px solid var(--accent);
    border-radius: var(--radius-md);
    outline: none;
    transition: border-color var(--t-fast),
                box-shadow var(--t-fast),
                background var(--t-fast);
}
.otp-cell:hover { border-color: var(--border-hover); }
.otp-cell:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(255, 107, 74, 0.20);
}
.otp-cell.is-filled {
    background: var(--accent-light);
}
[data-theme="dark"] .otp-cell {
    background: var(--bg-secondary);
}
[data-theme="dark"] .otp-cell.is-filled {
    background: rgba(255, 107, 74, 0.15);
}
@media (max-width: 400px) {
    .otp-grid { gap: 6px; }
    .otp-cell { width: 42px; height: 52px; font-size: 24px; }
}


/* =========================================================================
   REVISIÓN DE DISEÑO · v2.43.0
   =========================================================================
   Todo lo de esta sección es COMPARTIDO a propósito: el encargo pide corregir
   en los componentes antes que por pantalla. Va al final del archivo para
   ganar por orden de carga a igual especificidad, sin tocar las 647 reglas
   anteriores y sin un solo `!important` nuevo.

   ⚠️ **Lo que toque a `a`, `.kpi-grid`, `.glass-select` o la marca de agua hay
   que repetirlo en `siga-redesign.css`**, que se carga DESPUÉS y los redefine.
   Arreglar sólo acá deja el fallo vivo en modo Aurora — es la trampa que ya
   mordió con `--accent-texto` y con `.page-tabs`.
   ========================================================================= */

/* -------------------------------------------------------------------------
   §3 · EL COLOR DE LOS ENLACES — decisión de Camilo (5-nov-2026)
   -------------------------------------------------------------------------
   El rojo queda para alertas y errores. Hasta acá los enlaces usaban
   `--accent-texto` (#C53616 en claro), que es un rojo-naranja: el mismo
   registro visual que una alerta, en los ~634 enlaces de la app.

   Se reusa **`--estado-azul`**, que ya está medido en AA sobre el crema y
   sobre vidrio en los cuatro modos. No se inventa un color nuevo: un token
   nuevo habría que volver a medirlo, y el que ya existe dice lo mismo.

   ⚠️ `--enlace` es un token PROPIO y no un alias escrito a mano en cada
   regla: el día que se decida otro color se cambia en un lugar. Y apunta a
   `--estado-azul` en vez de duplicar el hex, para que no haya dos fuentes.
   ------------------------------------------------------------------------- */
:root { --enlace: var(--estado-azul); --enlace-hover: var(--estado-cian); }

a { color: var(--enlace); }
a:hover { color: var(--enlace-hover); }

/* ⚠️ `.accent-text` se sigue usando para DESTACAR (el nombre en el saludo, un
   total), no para navegar: ahí el coral es correcto y no se toca. Lo que se
   corrige es el enlace. */

/* -------------------------------------------------------------------------
   §2 · LOS FILTROS EN UNA FILA
   -------------------------------------------------------------------------
   La causa medida no era `.toolbar` —que ya es `flex` con `wrap`— sino que la
   regla compartida de campos trae **`width: 100%`**. En un contenedor flex,
   un hijo al 100% se queda con la línea entera: por eso `gh_critico` apilaba
   sus cuatro filtros en cuatro filas de 1686 px.

   Con `width:auto` y una base flexible, los campos van uno al lado del otro y
   **bajan solos cuando no caben**, que es lo que el encargo pide. Esto arregla
   TODAS las barras de filtros de la app de una vez, no sólo la de `gh_critico`.

   ⚠️ `.grow` conserva su regla previa (`flex: 1 1 240px; max-width: 520px`):
   el buscador sigue siendo el que se estira.
   ------------------------------------------------------------------------- */
.toolbar > .glass-input,
.toolbar > .glass-select,
.toolbar > label > .glass-input,
.toolbar > label > .glass-select {
  width: auto;
  flex: 0 1 190px;
  min-width: 150px;
}
.toolbar > .glass-input.grow { flex: 1 1 240px; }

/* Las etiquetas de filtro, cuando la pantalla las usa, son un bloque propio
   para que el campo no se estire a costa del texto. */
.toolbar > label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
  color: var(--text-secondary);
}


/* =========================================================================
   v2.43.4 · 🔴 UN ICONO DENTRO DE UN TEXTO SE IBA A SU PROPIA LÍNEA
   =========================================================================
   Medido en el navegador: en el aviso de última acta y en los títulos de
   sección del modal de contrato, el `<svg>` del icono salía con
   **`display: block`** y se llevaba una línea entera.

   **La causa es compartida y está arriba en esta misma hoja:**
   `img, svg { max-width: 100%; display: block; }`. Esa regla existe para que
   las imágenes de bloque no dejen el hueco de la línea base, y está bien para
   una imagen; pero **lucide reemplaza cada `<i data-lucide>` por un `<svg>`**,
   así que cualquier icono escrito dentro de un párrafo o un encabezado hereda
   `display:block` y rompe el renglón.

   Por eso el arreglo va en el COMPONENTE y no en las dos pantallas donde se
   reportó: el patrón «icono + texto en la misma línea» está en todo SIGA.

   ⚠️ **La lista de contenedores es cerrada a propósito.** Sólo elementos que
   llevan TEXTO, y sólo como **hijo directo** (`>`). Quedan fuera `button`, `a`,
   `td` y `th`: ahí los iconos suelen ser el contenido único de un control y
   varios dependen de `display:block` para centrarse — el barrido amplio
   (`p svg, td svg`…) habría descentrado los botones de icono de todas las
   tablas. Es el mismo criterio que la regla del `dialog`: medir el SUJETO.

   ⚠️ `vertical-align: -0.15em` y no `middle`: `middle` alinea al centro de la
   x-height y deja el icono flotando alto sobre texto de 12-13 px.
   ========================================================================= */
/* ⚠️ v2.43.5 · entra `summary`, que es un elemento de TEXTO como `legend` y
   tenía el mismo defecto (medido: 4 casos — «Más filtros» de la bitácora de
   nómina, «Crear un tipo nuevo» y «Agregar excepción de cubrimiento»).
   `div`, `td`, `th`, `button` y `a` siguen FUERA: ver la nota de la regla. */
:is(h1, h2, h3, h4, h5, h6, p, label, small, span, strong, em,
    dt, dd, legend, caption, figcaption, summary) > svg {
  display: inline-block;
  vertical-align: -0.15em;
}
/* =========================================================================
   v2.43.5 · 🔴 LAS COLUMNAS DE LA LISTA DE CONTRATOS, EN LA HOJA COMPARTIDA
   =========================================================================
   El nombre del asociado se partía en varias líneas mientras «Sede / Puesto de
   servicio» se quedaba con el ancho de sobra. La tabla es `table-layout: auto`,
   así que el navegador reparte por el contenido de cada columna — y el
   encabezado de Sede es largo, así que pide más ancho que los nombres de las
   sedes, que son cortos.

   🔴 **Y esto estuvo INERTE una versión entera.** En la v2.43.4 la regla se
   puso en un `<style>` de `modules/gh/contratos.php` que resultó estar dentro
   de `if ($canManage && $asociado !== null && $confirmarResumen)`: sólo se
   imprime en la **pantalla de confirmación** de un contrato nuevo. En la lista
   general —la única donde existe la columna Asociado— no salía nunca. Medido en
   producción: `th` de 134 px con `min-width: 0px`, con el CSS nuevo cargado y la
   clase puesta en el `<th>`.

   ⚠️ **La lección: una regla en un `<style>` de vista hereda las condiciones
   del bloque donde cae**, y en un archivo de 4.800 líneas con cinco `<style>`
   eso no se ve leyendo alrededor. Acá la hoja compartida se carga siempre —el
   `<link>` está en `layout.php` y hay una aserción que lo fija— así que la
   pregunta «¿se imprime?» desaparece.

   ⚠️ **El ancho se midió, no se eligió.** Barriendo anchos en el navegador con
   el nombre más largo de la muestra («VILLANUEVA ECHEVERRI JUAN SEBASTIAN»),
   **200 px es el umbral** donde pasa de 3 líneas a 2; 210 deja margen.

   ⚠️ Ni `width` duro ni `table-layout: fixed`: a 1920 px la tabla tiene espacio
   de sobra y un ancho fijo lo desperdicia, además de volver a partir el nombre
   con nombres más largos. El mínimo deja el reparto automático.
   ========================================================================= */
/* =========================================================================
   v2.43.6 · 🔴 LA TABLA DE CONTRATOS CABE POR CONSTRUCCIÓN, NO POR ARITMÉTICA
   =========================================================================
   Medido en producción con la v2.43.5: a 1536 px la tabla medía **1549 px**
   dentro de un `.glass-table-wrap` de **1434 px**, así que «Estado» quedaba
   cortado y aparecía scroll horizontal. El `min-width: 210px` de Asociado
   funcionaba —dos líneas por nombre, como se pedía— pero empujaba el total.

   **Por qué `table-layout: fixed` y no más aritmética.** Con `auto`, el ancho
   de la tabla es la suma de los anchos *mínimos de contenido* de sus 12
   columnas, y ese número no se puede acotar desde CSS: depende de los datos. Lo
   calculé sobre la **primera página real** (50 filas) y daba **1249 px** con el
   padding reducido — cabe en los 1286 px del contenedor a 1366, pero con sólo
   **37 px** de margen, y mis métricas de px/carácter tienen ±3 % (≈±35 px). O
   sea: habría cabido por casualidad. Con `fixed` la tabla **nunca** excede su
   contenedor y la pregunta deja de depender de una estimación.

   **Los porcentajes salen de los pisos medidos**, no de un reparto a ojo. Para
   cada columna se tomó el mayor entre el ancho mínimo de su contenido real y el
   de su encabezado, y el porcentaje es ese piso sobre 1286 px. Verificado: a
   1286 **las 12 columnas alcanzan su piso**, y a 1434 todas tienen margen.

     columna     piso    %      a 1286   a 1434
     #            35    2.8      36       40
     Código      180   14.0     180      201      ← nowrap, 19 chars monoespacio
     Proceso      73    5.7      73       82      ← su contenido real es «#2»
     Asociado    178   13.9     179      199      ← 2 líneas en los 50 nombres
     Tipo         80    6.3      81       90
     Cargo       110    8.6     111      123
     Sede        160   14.7     189      211      ← absorbe el sobrante
     Inicio       94    7.4      95      106
     Fin          94    7.4      95      106
     Sueldo      101    7.9     102      113
     Estado       65    5.1      66       73
     Acciones     79    6.2      80       89

   ⚠️ **Asociado va a 13,9 % (≈179 px a 1366), NO a 180 px fijos.** Medido sobre
   los 50 nombres de la primera página: a **180 px tres nombres pasan de dos
   líneas** («LANCHEROS BUITRAGO MIGUEL ANTONIO» entre ellos) y a 170 px pasan
   **siete**. El mínimo que deja los 50 en dos líneas es **190 px con el padding
   de 32**, que con el padding de 20 de esta tabla equivale a **178 px** — el
   área de texto es la misma. Por eso el porcentaje se calibró a ese piso.

   ⚠️ **El padding baja a 10 px por lado SÓLO en esta tabla.** Doce columnas ×
   32 px son **384 px de puro padding**, casi un tercio del ancho útil. Bajarlo
   a 20 por celda libera 144 px. No se toca `.glass-table` en general: una tabla
   de cinco columnas no necesita apretarse, y cambiarlo ahí movería la densidad
   de las 53 rutas.

   ⚠️ **NO se tocó el `nowrap` de `.text-mono`**, aunque dejar que el código
   envuelva por sus guiones liberaba 76 px más. Ese `nowrap` se agregó a
   propósito —los códigos se partían en el guion y se leían mal— y con el
   reparto fijo no hace falta: el 14 % le da sus 180 px a 1366.

   ⚠️ **Y reemplaza a `.ctr-col-asoc` / `.ctr-col-sede` de la v2.43.4/5**, que se
   eliminan: con el reparto fijo serían una segunda fuente de verdad para el
   ancho de esas dos columnas.
   ========================================================================= */
.ctr-tabla { table-layout: fixed; }
/* Doce columnas piden celdas más apretadas que una tabla de cinco. */
/* ⚠️ v2.44.1 · 10 → 8 px. Con los pisos del universo el presupuesto de 1366 no cerraba con
   10; cada 2 px por lado liberan 48 px en las doce columnas. La misma regla se repite en
   `siga-redesign.css`, o Aurora la pisa — ver el bloque de allá. */
.ctr-tabla thead th,
.ctr-tabla tbody td { padding-left: 8px; padding-right: 8px; }

/**
 * 🔴 **v2.44.1 · reparto recalculado, y el motivo es que la v2.43.6 midió con el padding
 * equivocado.** Esa versión bajó el padding de esta tabla a 10px por lado y calculó los doce
 * porcentajes sobre esa base… pero la regla vive sólo en esta hoja y **Aurora la pisaba**:
 * `siga-redesign.css .glass-table tbody td { padding: 13px 16px }` tiene la misma
 * especificidad (0,1,2) y carga después, así que en el modo en el que se mira el sistema el
 * padding real seguía siendo **16px**. Medido en producción el 6-nov: `padding-left: 16px`.
 *
 * Con 12px menos de caja por columna, dos celdas desbordaban y se montaban sobre la vecina
 * —el `<td>` no recorta, así que con `table-layout: fixed` el contenido que no envuelve se
 * sale—:
 *
 *   · `proc`   badge «PROCESO #4» = 114,5px sobre una caja de 49,8  →  desbordaba 64,8px
 *   · `estado` badge «ACTIVO»     =  83,9px sobre una caja de 41,2  →  desbordaba 42,7px
 *
 * El de `proc` es el que reportó Camilo (se monta sobre el nombre). El de `estado` **no estaba
 * reportado y también estaba mal**: se montaba sobre la columna de acciones.
 *
 * Los porcentajes de abajo salen de los pisos medidos sobre las 50 filas de la primera página,
 * con el padding ya corregido a 10px por lado (20 en total):
 *
 *   col     piso de contenido         +pad   %       px a 1286 (1366)   px a 1434 (1536)
 *   num     11   (encabezado «#»)      31    2.41      31                 35
 *   cod     159,6 «CONT-1020819215-002» nowrap        180   14.00  180    201
 *   proc    60,7 badge «#44»            81    6.30      81                 90
 *   asoc    164,8 (2 líneas)           188   14.62     188                210
 *   tipo    68,8 «Empleado»             89    6.91      89                 99
 *   cargo   89,9 (envuelve)            ~95    7.39      95                106
 *   sede    178,8 (envuelve)          ~137   10.65     137                153
 *   ini     84,6 fecha                 105    8.13     105                117
 *   fin     84,8 fecha                 105    8.15     105                117
 *   sueldo  94 (encabezado)            114    8.86     114                127
 *   estado  83,9 badge «ACTIVO»        104    8.07     104                116
 *   acc     38 (el botón)               58    4.51      58                 65
 *                                            100.00
 *
 * ⚠️ **El caso peor es 1366, no 1536**: a 1536 todo escala ×1,115. Si alguna vez hay que
 * recortar, se recorta de `cargo` y `sede`, que son las dos que **envuelven** y por lo tanto
 * las únicas cuyo piso es blando.
 */
/**
 * 🔴 **v2.44.1 · tercera pasada, y ahora los pisos son del UNIVERSO, no de la primera página.**
 *
 * Las dos pasadas anteriores midieron los anchos mínimos sobre **las 50 filas de la primera
 * página** de 1.491 contratos, y ésa es la razón por la que el problema volvió: las cadenas más
 * largas están en otras páginas. Medido el 6-nov-2026 sobre las 1.491 filas, con la tipografía
 * real y Aurora encendido:
 *
 *   col     peor del universo                              página 1   universo
 *   cod     «CONT-1000036196-001» (nowrap)                   159,6 →   190,3
 *   asoc    «OLIVEROS CASTELLANOS KELMER CEFERINO» (2 líneas) 165   →   175
 *   cargo   «ADMINISTRATIVO» (palabra más larga)               89,9 →   114,2
 *   sueldo  «$ 20.577.000»                                     92,4 →   105,3
 *   estado  badge «INACTIVO»                                   83,9 →    97
 *   sede    «TEUSAQUILLO/TURNO»                               128,9 →   128,9
 *   tipo    «Empleado»                                         68,8 →    68,8
 *
 * ⚠️ Ese último salió de un error que vale anotar: elegí la cadena más larga **por
 * caracteres** y «Asociado» y «Empleado» tienen los mismos ocho, pero «Empleado» mide 68,8
 * y «Asociado» 63,5. Con el piso en 63,5 la columna desbordaba 5,4 px a 1366. **El ancho de
 * un texto no se estima contando letras**: se mide.
 *
 * Y el presupuesto también estaba mal: el `.glass-table-wrap` mide **viewport − 100** (padding
 * fijo de `.main-content` 48 + `.dash-panel` 40 + barra de scroll 10), así que a 1366 hay
 * **1.266 px**, no los 1.286 con los que se calibró la v2.43.6. Veinte píxeles de más en el
 * presupuesto y cinco columnas con el piso subestimado: por eso los badges de «Proceso» y
 * «Estado» se montaban sobre la columna vecina.
 *
 * ⚠️ **Σ de pisos del universo = 1.345 px con padding 8, y a 1366 hay 1.266.** El déficit de
 * **79 px** no se cierra moviendo porcentajes: hay que o dejar envolver el código del contrato
 * (libera 84 px, pero la v2.43.6 decidió lo contrario a propósito — los códigos se partían en
 * el guion) o dejar que las dos columnas de **texto libre** —cargo y sede— partan palabra. Se
 * eligió lo segundo: `overflow-wrap: anywhere` (abajo) hace que esas dos usen **más líneas** en
 * vez de **invadir la vecina**, y una línea de más se lee; un texto encima de otro, no.
 *
 * El reparto da a las diez columnas de contenido fijo su piso del universo y a las dos de texto
 * libre el resto, repartido en proporción a los suyos:
 *
 *   col      %        px a 1266 (1366)   px a 1436 (1536)   piso universo
 *   num      2.13       27,0               30,6               27
 *   cod     16.30      206,4              234,1              206,3
 *   proc     6.34       80,3               91,0               80,3  (manda el encabezado)
 *   asoc    15.09      191,0              216,7              191
 *   tipo     6.70       84,8               96,1               84,8
 *   cargo    6.71       85,0               96,3              130,2  ← texto libre
 *   sede     8.04      101,8              115,3              144,9  ← texto libre
 *   ini      7.95      100,6              114,2              100,6
 *   fin      7.96      100,8              114,3              100,8
 *   sueldo   9.58      121,3              137,6              121,3
 *   estado   8.93      113,0              128,2              113
 *   acc      4.27       54,0               61,3               54
 *          100.00
 */
.ctr-tabla .ctr-c-num    { width:  2.13%; }
.ctr-tabla .ctr-c-cod    { width: 16.30%; }
.ctr-tabla .ctr-c-proc   { width:  6.34%; }
.ctr-tabla .ctr-c-asoc   { width: 15.09%; }
.ctr-tabla .ctr-c-tipo   { width:  6.70%; }
.ctr-tabla .ctr-c-cargo  { width:  6.71%; }
.ctr-tabla .ctr-c-sede   { width:  8.04%; }
.ctr-tabla .ctr-c-ini    { width:  7.95%; }
.ctr-tabla .ctr-c-fin    { width:  7.96%; }
.ctr-tabla .ctr-c-sueldo { width:  9.58%; }
.ctr-tabla .ctr-c-estado { width:  8.93%; }
.ctr-tabla .ctr-c-acc    { width:  4.27%; }
/**
 * ⚠️ **Las dos columnas de TEXTO LIBRE parten palabra si hace falta.** Son las únicas dos cuyo
 * contenido es una descripción y no un dato con forma: un cargo de 46 caracteres
 * («ADMINISTRADOR DE TECNOLOGÍA Y MEDIOS DIGITALES») y una sede de 187. Con `break-word` a
 * secas no alcanza: esa propiedad sólo parte cuando la palabra **no cabe en una línea entera**,
 * y lo que pasa acá es que cabe pero desborda la celda. `anywhere` sí la parte, y además le
 * dice al algoritmo de tabla que el min-content de la columna es un carácter — que es lo que
 * saca a estas dos de la ecuación del presupuesto.
 *
 * ⚠️ **NO se aplica a `cod`.** Ahí el nowrap es deliberado (los códigos se partían en el guion)
 * y el reparto le da sus 206 px, así que nunca necesita partirse.
 */
.ctr-tabla .ctr-c-cargo,
.ctr-tabla .ctr-c-sede { overflow-wrap: anywhere; }

/* ⚠️ El nombre y la sede tienen que poder envolver: con `fixed`, un contenido
   que no envuelve se DESBORDA de su celda en vez de ensanchar la columna. */
.ctr-tabla .ctr-c-asoc,
.ctr-tabla .ctr-c-sede { white-space: normal; }

/* -------------------------------------------------------------------------
   §2 · UN SOLO ALTO PARA LOS CAMPOS DE LA BARRA DE FILTROS
   -------------------------------------------------------------------------
   Puestos en una fila (arriba), quedó visible lo otro: una misma barra mezcla
   alturas. Un `<input type="date">` no mide igual que un `<select>` ni que un
   `<input type="text">` — cada uno calcula su alto desde su propio contenido,
   y al date el navegador le suma el espacio de su selector. Los bordes quedan
   desalineados y se lee como descuido aunque el espaciado esté bien.

   El alto se fija en una variable y se aplica a los tres, con
   `box-sizing: border-box` para que el padding no lo empuje, y el botón de la
   barra lo iguala — si no, queda flotando junto a campos más altos.

   ⚠️ **Va sobre `.toolbar > …`, nunca sobre `.glass-input` a secas.** La misma
   clase la usan los formularios, los modales y **las celdas de la malla de
   PRG**, donde el `<select>` ES la celda: un alto fijo global le rompería la
   grilla al módulo que más depende de ella.

   ⚠️ Y no toca `.field-group` de los formularios: ahí el campo es el
   protagonista y puede ser más alto. Son dos contextos, no uno.
   ------------------------------------------------------------------------- */
.toolbar { --filtro-h: 36px; }
.toolbar > .glass-input,
.toolbar > .glass-select,
.toolbar > label > .glass-input,
.toolbar > label > .glass-select {
  height: var(--filtro-h);
  box-sizing: border-box;
  padding-block: 0;
}
.toolbar > .glass-btn,
.toolbar > a.glass-btn,
.toolbar > button.glass-btn {
  min-height: var(--filtro-h);
}

/* -------------------------------------------------------------------------
   §2 · LA FLECHA DEL SELECT
   -------------------------------------------------------------------------
   ⚠️ **La flecha YA ESTABA** (`appearance:none` + un SVG embebido +
   `padding-right:36px`). Lo que pasaba es que su trazo era **#716867** en
   claro y **#9892A2** en Aurora: grises de muy bajo contraste contra el fondo
   del campo, así que el select «parecía texto». El arreglo no es agregar una
   flecha, es que la que hay se vea.

   Medido sobre el fondo del campo (`--bg-primary` = #FFFFFF en claro):
     #716867 → 4,96:1   ... pero a 12×8 px de glifo fino se lee como una sombra
     #3A3330 → 10,9:1   ... el gris de texto, que es lo que un control pide
   WCAG 1.4.11 le pide 3:1 a un objeto gráfico; acá lo que fallaba era la
   percepción de «esto se despliega», no la norma.
   ------------------------------------------------------------------------- */


/* =========================================================================
   v2.43.1 · 🔴 LA FLECHA DEL SELECT · los atajos de tema la estaban pisando
   =========================================================================
   Hoja CLÁSICA. Glifo oscuro en tema claro, claro en tema oscuro.

   **El síntoma en producción: triángulos en mosaico tapando el control.**
   Medido en los cuatro modos, la v2.43.0 dejaba esto:

     AURORA claro    repeat · 0% 0% · con imagen  → el triángulo EN MOSAICO
     AURORA oscuro   repeat · 0% 0% · SIN imagen  → no hay flecha
     clásico claro   no-repeat · 0% 0%            → la flecha arriba a la
                                                     izquierda, encima del texto
     clásico oscuro  repeat · 0% 0% · SIN imagen  → no hay flecha

   **La causa.** El bloque base `.glass-select` trae `background-image`,
   `background-repeat` y `background-position` juntos, con especificidad
   `(0,1,0)`. Encima hay reglas de TEMA que usan el **atajo `background`**:

     [data-theme="dark"] .glass-select        { background: … }   (0,2,0)
     [data-theme="light"] .glass-select       { background: … }   (0,2,0)
     [data-theme="dark"] .glass-select:hover  { background: … }   (0,3,0)
     .glass-select:focus                      { background: … }

   ⚠️ **Un atajo `background` reinicia TODOS los longhands que no nombra** —
   `image`, `repeat`, `position`, `size`, `attachment`, `origin`, `clip`— a su
   valor inicial. Esas reglas sólo querían cambiar el COLOR del campo, y de paso
   le ponían `repeat` y `0% 0%` a la flecha con más especificidad que el bloque
   base. La v2.43.0 empeoró el cuadro: cambió el color del glifo declarando
   **sólo `background-image`**, así que `repeat` y `position` quedaron en manos
   del atajo del tema.

   **El arreglo: los CUATRO longhands juntos, a especificidad que gane, y en los
   cuatro estados.** Si falta uno, lo decide el atajo del tema:
     · sin `repeat: no-repeat` → mosaico (el bug que se vio);
     · sin `position` → la flecha arriba a la izquierda, sobre el texto;
     · sin `size` → a merced del tamaño intrínseco del SVG;
     · sin `image` → no hay flecha.

   ⚠️ **`:hover` y `:focus` tienen que estar.** Los dos se repintan con atajo
   (`.glass-select:focus { background: … }` y
   `[data-theme] .glass-select:hover { background: … }`), así que sin ellos la
   flecha desaparece al pasar el mouse o al enfocar — un parpadeo que se lee como
   que el control se rompe al tocarlo.

   ⚠️ **Sin `!important`.** La competencia más alta es
   `[data-theme="dark"] .glass-select:hover` = `(0,3,0)`; este bloque usa
   `[data-theme] .glass-select:hover`, que **empata** en `(0,3,0)` y va **después**
   en el archivo, así que gana por orden. Un `!important` acá taparía el
   diagnóstico la próxima vez que alguien agregue un atajo.

   ⚠️ **El COLOR del glifo va en una variable, NO en este bloque.** Un data-URI
   dentro de `url()` no puede interpolar `var()`, así que la única forma de tener
   un glifo por tema sin repetir los cuatro longhands por tema y por estado es que
   la variable guarde el `url()` **completo**. Así el bloque es uno solo y el tema
   sólo cambia `--sel-flecha`.

   ⚠️ **Y tiene que estar en LAS DOS HOJAS.** Aurora carga después, así que su
   `[data-theme="dark"] .glass-select:hover` empata con el de design-system y le
   gana por orden: arreglar una sola hoja deja la otra mitad rota. Mismo modo de
   falla que `a`, `.page-tabs` y `.kpi-grid`.
   ========================================================================= */
:root { --sel-flecha: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%233A3330' d='M6 8L0 0h12z'/%3E%3C/svg%3E"); }
/* ⚠️ En tema oscuro el campo es `--bg-secondary` (#241e19): un glifo oscuro ahí
   es invisible. #B8ADA6 es el `--text-secondary` de ese tema, ya medido en
   8,25:1 contra el fondo de la página. */
[data-theme="dark"] { --sel-flecha: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%23B8ADA6' d='M6 8L0 0h12z'/%3E%3C/svg%3E"); }

[data-theme] .glass-select,
[data-theme] .glass-select:hover,
[data-theme] .glass-select:focus,
[data-theme] .glass-select:disabled,
[data-theme] .toolbar > .glass-select,
[data-theme] .toolbar > label > .glass-select {
  background-image: var(--sel-flecha);
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px 8px;
}
/* ⚠️ Y la misma declaración SIN `[data-theme]`: el login y el 2FA no pasan por el
   layout que pone el atributo, y ahí el bloque de arriba no engancharía. Donde el
   atributo sí existe esta copia es inofensiva —pierde por especificidad contra la
   de arriba— y es la única que aplica donde no existe. */
.glass-select,
.glass-select:hover,
.glass-select:focus,
.glass-select:disabled {
  background-image: var(--sel-flecha);
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px 8px;
}

/* -------------------------------------------------------------------------
   §4 · LA FRANJA DE KPI SE ADAPTA AL NÚMERO DE TARJETAS
   -------------------------------------------------------------------------
   `repeat(auto-fill, minmax(280px, 1fr))` da **5 columnas** en los 1.760 px de
   ancho útil, así que una franja de 4 deja un hueco y una de 6 deja una
   tarjeta huérfana en la segunda fila.

   ⚠️ **No se toca el piso de 280 px**, que está medido: con 200 px las
   etiquetas de GH se partían en tres líneas. Lo que se hace es decirle a la
   grilla **cuántas columnas** usar cuando el número de tarjetas se conoce, con
   `:has()` sobre el último hijo. Así 4 van en 4, 6 en 3+3 y 8 en 4+4 — filas
   parejas en vez de huérfanas.

   ⚠️ Se aplica **sólo desde 1200 px**: por debajo manda el piso de 280 px, que
   es el que evita que las etiquetas se rompan. Y sólo cuando el número de
   tarjetas es exacto; una franja de 5 o 7 sigue con `auto-fill`.
   ------------------------------------------------------------------------- */
@media (min-width: 1200px) {
  .kpi-grid:has(> :nth-child(4):last-child) { grid-template-columns: repeat(4, 1fr); }
  .kpi-grid:has(> :nth-child(6):last-child) { grid-template-columns: repeat(3, 1fr); }
  .kpi-grid:has(> :nth-child(8):last-child) { grid-template-columns: repeat(4, 1fr); }
  .kpi-grid:has(> :nth-child(9):last-child) { grid-template-columns: repeat(3, 1fr); }
  .kpi-grid:has(> :nth-child(10):last-child) { grid-template-columns: repeat(5, 1fr); }
  .kpi-grid:has(> :nth-child(12):last-child) { grid-template-columns: repeat(4, 1fr); }
}
/* ⚠️ `:has()` degrada solo: un navegador sin soporte ignora la regla y queda el
   `auto-fill` de siempre. No hace falta `@supports`. */

/* -------------------------------------------------------------------------
   §4 · TEXTO MÍNIMO DE 12 px EN TABLAS
   -------------------------------------------------------------------------
   Se declara el piso en el componente. ⚠️ **No alcanza para los `style=` en
   línea** —un `font-size:11px` inline le gana a cualquier hoja—, y de esos hay
   **135 dentro de celdas de tabla** (medido). Los de las pantallas revisadas
   se corrigen uno por uno; el resto queda contado en el informe. Esta regla
   cubre lo que no lleva estilo propio y fija el piso para lo que se escriba
   de ahora en adelante.
   ------------------------------------------------------------------------- */
.glass-table { font-size: 13px; }
.glass-table th,
.glass-table td { font-size: inherit; }
.glass-table .nb-sub,
.glass-table small { font-size: 12px; }

/* -------------------------------------------------------------------------
   §4 · UNA SOLA BARRA DE DESPLAZAMIENTO EN LAS TABLAS
   -------------------------------------------------------------------------
   ⚠️ Con `overflow-x: auto` el navegador habilita **también** el eje vertical
   en cuanto el contenido no cabe, así que un contenedor con `max-height` y
   `overflow:auto` dentro de una página que ya scrollea da **dos barras**.
   Se deja el scroll horizontal donde hace falta y el vertical lo lleva la
   página; el encabezado se mantiene pegado con `position: sticky`, que no
   necesita contenedor con altura.
   ------------------------------------------------------------------------- */
.glass-table-wrap { overflow-x: auto; overflow-y: visible; }
.glass-table-wrap > .glass-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg-primary);
}

/* -------------------------------------------------------------------------
   §4 · LA MARCA DE AGUA, SÓLO DONDE NO ESTORBA
   -------------------------------------------------------------------------
   Decisión de Camilo: visible en Inicio y en las pantallas de sesión; fuera de
   las pantallas de trabajo, donde se cruzaba con el texto y con las tarjetas
   translúcidas. La marca la pinta `siga-redesign.css` (`body::after`); acá sólo
   queda documentado dónde vive el interruptor: la clase `ds-marca` del `<body>`,
   que `templates/layout.php` pone únicamente en el dashboard.
   ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   NOTA QUE VENÍA DE `app.css`, que esta versión elimina
   -------------------------------------------------------------------------
   `app.css` tenía **0 reglas**: era un archivo de comentarios que las tres
   plantillas enlazaban igual, o sea una petición HTTP por página para no
   aplicar nada. Se elimina y su lección se conserva acá, que es donde se va a
   leer:

   ⚠️ **Un `@import` NO hereda el `?v=` de `siga_asset()`**: la hoja importada
   conserva su propia entrada de caché, y con el `max-age=604800` (7 días) que
   pone el hosting eso dejaba esta hoja congelada una semana después de cada
   deploy. Además un `@import` encadena dos descargas en vez de paralelizarlas.
   **Al agregar una hoja nueva, enlazarla desde las plantillas con
   `siga_asset()`, nunca con `@import`.**
   ------------------------------------------------------------------------- */