/* ============================================================================
   HomeIDS — capa estética "IDS Tech"
   Se aplica DESPUÉS de assets/brand-tokens.css. No reemplaza tokens de marca:
   los extiende. Light + dark (html.dark-theme / body.dark-theme).
   Motion: solo CSS. Iconos: FontAwesome 6 (fa-solid).
   ========================================================================= */

/* ---------------------------------------------------------------- 1. TOKENS
   Nuevos (no existían equivalentes). Mismo naming: kebab-case, doble guion. */
:root {
  /* geometría */
  --card-radius: 14px;
  --card-radius-sm: 10px;
  --pill-radius: 999px;
  --cut: 14px;                    /* corte diagonal de esquina (motivo de marca) */
  --sidebar-w: 264px;
  --flyout-w: 268px;

  /* superficies derivadas */
  --surface-raised: #ffffff;
  --surface-sunken: #f4f7fb;
  --surface-veil: rgba(255, 255, 255, 0.72);
  --hairline: rgba(15, 23, 42, 0.07);
  --hairline-strong: rgba(15, 23, 42, 0.16);
  --grid-line: rgba(15, 23, 42, 0.04);

  /* tintes de marca (derivados del rojo/azul ya definidos) */
  --primary-tint: rgba(165, 19, 23, 0.08);
  --primary-tint-strong: rgba(165, 19, 23, 0.16);
  --secondary-tint: rgba(30, 66, 172, 0.08);
  --primary-bright: #c2181d;

  /* acciones destructivas: mismo rojo de marca que .badge--danger, nunca un
     color nuevo. Sin este token, todo `var(--danger)` suelto en el código
     (botones de eliminar, montos negativos) quedaba sin color resuelto. */
  --danger: var(--primary);

  /* gradientes de marca */
  --grad-primary: linear-gradient(135deg, #c2181d 0%, #a51317 46%, #7d0e11 100%);
  --grad-secondary: linear-gradient(135deg, #2a55c8 0%, #1e42ac 46%, #163182 100%);
  --grad-rail: linear-gradient(90deg, var(--primary) 0%, var(--secondary) 100%);
  --grad-header: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(241, 245, 249, 0.55) 100%);
  --grad-sheen: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.55) 48%, transparent 66%);

  /* profundidad en capas (nunca un solo box-shadow chato) */
  --depth-1: 0 1px 1px rgba(15, 23, 42, 0.04), 0 2px 6px -1px rgba(15, 23, 42, 0.06);
  --depth-2: 0 1px 1px rgba(15, 23, 42, 0.05), 0 4px 10px -2px rgba(15, 23, 42, 0.08),
             0 12px 28px -12px rgba(15, 23, 42, 0.14);
  --depth-3: 0 1px 1px rgba(15, 23, 42, 0.06), 0 8px 18px -4px rgba(15, 23, 42, 0.12),
             0 28px 56px -20px rgba(15, 23, 42, 0.22);
  --glow-primary: 0 6px 18px -6px rgba(165, 19, 23, 0.55), 0 0 0 1px rgba(165, 19, 23, 0.22);
  --glow-secondary: 0 6px 18px -6px rgba(30, 66, 172, 0.55), 0 0 0 1px rgba(30, 66, 172, 0.22);

  /* foco: distinto del hover, siempre visible */
  --focus-ring: 0 0 0 2px var(--card-bg), 0 0 0 4px rgba(30, 66, 172, 0.55);
  --focus-ring-danger: 0 0 0 2px var(--card-bg), 0 0 0 4px rgba(165, 19, 23, 0.5);

  /* motion — se suma a --motion-fast/--motion-base/--ease-tech ya existentes */
  --motion-slow: 0.42s;
  --ease-enter: cubic-bezier(0.16, 1, 0.3, 1);   /* salida amplia: flyouts, modales */
  --ease-curtain: cubic-bezier(0.75, 0, 0.15, 1); /* el de animacion.html */

  /* superficie de la app */
  --app-bg: #ffffff;
  --halo-primary: rgba(165, 19, 23, 0.055);
  --halo-secondary: rgba(30, 66, 172, 0.05);

  /* tipografía de datos: solo fuentes de sistema, no agrega descargas */
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  /* escala de z-index: index.html tiene ~30 valores "mágicos" sueltos entre
     2 y 100050 (varios overlays distintos comparten 9999/10000/10050 sin
     relación entre sí). Estos tokens quedan disponibles para ir remapeando
     ese código de forma incremental -- no se tocó el HTML existente todavía
     porque reordenar z-index sin ver cada overlay en pantalla puede invertir
     un apilamiento que hoy funciona por casualidad. Al tocar un overlay
     nuevo o al revisar uno viejo, usar estos valores en vez de un número
     suelto. */
  --z-dropdown: 60;       /* .nav-flyout, search-drop, popovers de UI */
  --z-sidebar: 80;        /* sidebar/app-side en overlay mobile */
  --z-sticky: 100;        /* headers sticky, topbar */
  --z-modal: 1000;        /* modal-overlay estándar */
  --z-modal-stack: 10000; /* modal sobre otro modal (confirmaciones anidadas) */
  --z-toast: 100010;      /* toasts/avisos: siempre por encima de cualquier modal */
  --z-overlay-top: 100050; /* el único caso que debe ganarle a todo lo anterior */
}

html.dark-theme, body.dark-theme {
  --background: #0a0f1c;
  --card-bg: #111a2e;
  --text-dark: #e9eef8;
  --text-muted: #93a3bd;
  --border: #1e2b47;

  --app-bg: #0a0f1c;
  --halo-primary: rgba(224, 55, 61, 0.12);
  --halo-secondary: rgba(96, 137, 255, 0.1);
  --surface-raised: #16203a;
  --surface-sunken: #0d1424;
  --surface-veil: rgba(17, 26, 46, 0.72);
  --hairline: rgba(255, 255, 255, 0.08);
  --hairline-strong: rgba(255, 255, 255, 0.16);
  --grid-line: rgba(255, 255, 255, 0.035);

  --primary-tint: rgba(224, 55, 61, 0.14);
  --primary-tint-strong: rgba(224, 55, 61, 0.24);
  --secondary-tint: rgba(96, 137, 255, 0.16);
  --primary-bright: #e8474d;
  /* mismo azul que ya usa --focus-ring en dark mode (rgba(120,160,255)):
     el --secondary de marca (#1e42ac) es un navy oscuro que, contra el
     fondo casi negro de dark mode, no alcanza 4.5:1 en texto chico
     (badges, links). --secondary-bright es la versión clara de ese mismo
     azul para texto/iconos sobre fondo oscuro, nunca para fondos grandes. */
  --secondary-bright: #78a0ff;

  --grad-primary: linear-gradient(135deg, #c2181d 0%, #a51317 55%, #6d0c0f 100%);
  --grad-secondary: linear-gradient(135deg, #3a68e0 0%, #1e42ac 55%, #12275f 100%);
  --grad-header: linear-gradient(180deg, rgba(22, 32, 58, 0.9) 0%, rgba(10, 15, 28, 0.5) 100%);
  --grad-sheen: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.14) 48%, transparent 66%);

  --depth-1: 0 1px 1px rgba(0, 0, 0, 0.4), 0 2px 6px -1px rgba(0, 0, 0, 0.5);
  --depth-2: 0 1px 1px rgba(0, 0, 0, 0.45), 0 4px 12px -2px rgba(0, 0, 0, 0.55),
             0 16px 32px -12px rgba(0, 0, 0, 0.7);
  --depth-3: 0 1px 1px rgba(0, 0, 0, 0.5), 0 10px 22px -4px rgba(0, 0, 0, 0.6),
             0 32px 64px -20px rgba(0, 0, 0, 0.8);
  --glow-primary: 0 8px 22px -6px rgba(224, 55, 61, 0.5), 0 0 0 1px rgba(224, 55, 61, 0.35);
  --glow-secondary: 0 8px 22px -6px rgba(96, 137, 255, 0.45), 0 0 0 1px rgba(96, 137, 255, 0.35);
  --focus-ring: 0 0 0 2px var(--card-bg), 0 0 0 4px rgba(120, 160, 255, 0.7);
  --focus-ring-danger: 0 0 0 2px var(--card-bg), 0 0 0 4px rgba(232, 71, 77, 0.7);
}

/* --------------------------------------------------------- 2. BASE / FONDO */
/* Sirve tanto si .ids-tech va en <body> (app real) como en un div contenedor. */
body.ids-tech, .ids-tech {
  /* superficie de la app: blanca, con dos halos de marca muy tenues y la
     retícula técnica. En dark usa el azul profundo de --app-bg. */
  background-color: var(--app-bg);
  background-image:
    radial-gradient(900px 420px at 12% -8%, var(--halo-primary), transparent 72%),
    radial-gradient(760px 380px at 92% 4%, var(--halo-secondary), transparent 72%),
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: auto, auto, 48px 48px, 48px 48px;
  background-position: 0 0, 0 0, -1px -1px, -1px -1px;
  color: var(--text-dark);
  font-family: var(--font-body);
  overflow-x: clip;
}

/* foco global: nunca igual al hover */
.ids-tech :is(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--card-radius-sm);
}

/* transición de entrada de módulo — aplicar la clase al contenedor de contenido
   cada vez que switchPage() cambia de vista (ver handoff, punto 5) */
.module-enter { animation: module-in var(--motion-base) var(--ease-tech) both; }
.module-enter > * { animation: module-in 0.3s var(--ease-tech) both; }
.module-enter > *:nth-child(2) { animation-delay: 0.04s; }
.module-enter > *:nth-child(3) { animation-delay: 0.08s; }
.module-enter > *:nth-child(4) { animation-delay: 0.12s; }
.module-enter > *:nth-child(n + 5) { animation-delay: 0.16s; }

@keyframes module-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* Variante idéntica: solo sirve para re-disparar la animación cuando el DOM
   NO se reemplaza (alternar .module-enter / .module-enter-b). Si switchPage()
   reemplaza el innerHTML, con .module-enter alcanza. */
.module-enter-b { animation: module-in-b var(--motion-base) var(--ease-tech) both; }
.module-enter-b > * { animation: module-in-b 0.3s var(--ease-tech) both; }
.module-enter-b > *:nth-child(2) { animation-delay: 0.04s; }
.module-enter-b > *:nth-child(3) { animation-delay: 0.08s; }
.module-enter-b > *:nth-child(4) { animation-delay: 0.12s; }
.module-enter-b > *:nth-child(n + 5) { animation-delay: 0.16s; }

@keyframes module-in-b {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------- 3. CARDS */
.card {
  position: relative;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--card-radius);
  box-shadow: var(--depth-1);
  padding: 20px;
  isolation: isolate;
  transition:
    transform var(--motion-base) var(--ease-tech),
    box-shadow var(--motion-base) var(--ease-tech),
    border-color var(--motion-fast) var(--ease-tech);
}

/* riel superior de marca: se dibuja de 0 → 100% al hover */
.card::before {
  content: "";
  position: absolute;
  inset: 0 auto auto 0;
  height: 2px;
  width: 100%;
  border-radius: var(--card-radius) var(--card-radius) 0 0;
  background: var(--grad-rail);
  transform: scaleX(0);
  transform-origin: left;
  opacity: 0.9;
  transition: transform var(--motion-slow) var(--ease-enter);
}

/* velo diagonal interno, apenas perceptible: da la textura "técnica" */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(160deg, var(--hairline) 0%, transparent 38%);
  opacity: 0.7;
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--depth-2);
  border-color: var(--hairline-strong);
}
.card:hover::before { transform: scaleX(1); }

.card--static:hover { transform: none; box-shadow: var(--depth-1); }
.card--static:hover::before { transform: scaleX(0); }

/* variante con corte diagonal en la esquina superior derecha (motivo del logo) */
.card--cut {
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
}
.card--cut::before { width: calc(100% - var(--cut)); }

.card-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: -20px -20px 16px;
  padding: 14px 20px;
  background: var(--grad-header);
  border-bottom: 1px solid var(--border);
  border-radius: var(--card-radius) var(--card-radius) 0 0;
}
.card-title {
  font-family: var(--font-heading-bold);
  font-weight: 700;
  font-size: 0.9375rem;
  letter-spacing: -0.01em;
  color: var(--text-dark);
  margin: 0;
}
.card-title .fa-solid {
  color: var(--primary);
  margin-right: 8px;
  transition: transform var(--motion-base) var(--ease-tech);
}
.card:hover .card-title .fa-solid { transform: rotate(-6deg) scale(1.12); }
.card-tools { margin-left: auto; display: flex; gap: 6px; }
.card-sub { color: var(--text-muted); font-size: 0.8125rem; margin: 4px 0 0; }

/* ------------------------------------------------------------ 4. BOTONES */
.btn-premium {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 11px 20px;
  border: 0;
  border-radius: var(--card-radius-sm);
  background: var(--grad-primary);
  color: #fff;
  font-family: var(--font-body);
  font-size: 0.875rem;
  letter-spacing: 0.01em;
  cursor: pointer;
  overflow: hidden;
  box-shadow: var(--depth-1);
  transition:
    transform var(--motion-fast) var(--ease-tech),
    box-shadow var(--motion-base) var(--ease-tech),
    filter var(--motion-fast) var(--ease-tech);
}
/* barrido de brillo al hover */
.btn-premium::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--grad-sheen);
  transform: translateX(-120%);
  transition: transform var(--motion-slow) var(--ease-tech);
}
.btn-premium > * { position: relative; z-index: 1; }
.btn-premium .fa-solid { transition: transform var(--motion-base) var(--ease-tech); }

.btn-premium:hover {
  transform: translateY(-2px);
  box-shadow: var(--glow-primary), var(--depth-2);
  filter: saturate(1.08);
}
.btn-premium:hover::before { transform: translateX(120%); }
.btn-premium:hover .fa-solid { transform: translateX(3px); }
.btn-premium:active { transform: translateY(0) scale(0.985); }
.btn-premium:focus-visible { box-shadow: var(--focus-ring-danger); }

.btn-premium--secondary { background: var(--grad-secondary); }
.btn-premium--secondary:hover { box-shadow: var(--glow-secondary), var(--depth-2); }

.btn-premium--ghost {
  background: transparent;
  color: var(--text-dark);
  border: 1px solid var(--border);
  box-shadow: none;
}
.btn-premium--ghost:hover {
  background: var(--primary-tint);
  border-color: var(--primary);
  color: var(--primary);
  box-shadow: none;
}
html.dark-theme .btn-premium--ghost:hover,
body.dark-theme .btn-premium--ghost:hover { color: var(--primary-bright); }

.btn-premium--sm { padding: 7px 13px; font-size: 0.8125rem; }
.btn-premium--block { width: 100%; }

.btn-premium[disabled], .btn-premium.is-loading {
  pointer-events: none;
  opacity: 0.6;
}
.btn-premium.is-loading .fa-solid { animation: spin-tech 0.9s linear infinite; }

@keyframes spin-tech { to { transform: rotate(360deg); } }

/* --------------------------------------------------------- 5. KPI TILES */
/* Reemplaza el border-top: 4px solid. El color de categoría se pasa por
   --kpi-accent (inline o clase de área), así no hace falta una clase por área. */
.kpi-tile {
  --kpi-accent: var(--primary);
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px 18px 16px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--card-radius);
  box-shadow: var(--depth-1);
  overflow: hidden;
  transition:
    transform var(--motion-base) var(--ease-tech),
    box-shadow var(--motion-base) var(--ease-tech);
}
/* riel vertical izquierdo + halo de categoría */
.kpi-tile::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--kpi-accent);
  transform: scaleY(0.35);
  transform-origin: top;
  transition: transform var(--motion-slow) var(--ease-enter);
}
.kpi-tile::after {
  content: "";
  position: absolute;
  top: -40%; right: -20%;
  width: 190px; height: 190px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--kpi-accent) 0%, transparent 68%);
  opacity: 0.09;
  transition: opacity var(--motion-base) var(--ease-tech), transform var(--motion-slow) var(--ease-tech);
}
.kpi-tile:hover { transform: translateY(-3px); box-shadow: var(--depth-2); }
.kpi-tile:hover::before { transform: scaleY(1); }
.kpi-tile:hover::after { opacity: 0.16; transform: scale(1.12); }

.kpi-label {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--text-muted);
  display: flex; align-items: center; gap: 7px;
}
.kpi-label .fa-solid { color: var(--kpi-accent); font-size: 0.75rem; }
.kpi-value {
  font-family: var(--font-mono);
  font-size: 2rem;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
  color: var(--text-dark);
  animation: kpi-count-in var(--motion-slow) var(--ease-enter) both;
}
.kpi-delta {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--text-muted);
}
.kpi-delta--up { color: var(--success); }
.kpi-delta--down { color: var(--primary); }
html.dark-theme .kpi-delta--down, body.dark-theme .kpi-delta--down { color: var(--primary-bright); }

/* sparkline: 7 barras, CSS puro, altura por --h */
.kpi-spark { display: flex; align-items: flex-end; gap: 3px; height: 26px; margin-top: 4px; }
.kpi-spark i {
  flex: 1;
  background: var(--kpi-accent);
  opacity: 0.35;
  border-radius: 2px 2px 0 0;
  height: var(--h, 40%);
  transform-origin: bottom;
  animation: spark-rise 0.5s var(--ease-enter) both;
}
.kpi-spark i:nth-child(2) { animation-delay: 0.05s; }
.kpi-spark i:nth-child(3) { animation-delay: 0.1s; }
.kpi-spark i:nth-child(4) { animation-delay: 0.15s; }
.kpi-spark i:nth-child(5) { animation-delay: 0.2s; }
.kpi-spark i:nth-child(6) { animation-delay: 0.25s; }
.kpi-spark i:nth-child(7) { animation-delay: 0.3s; opacity: 0.85; }

@keyframes kpi-count-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes spark-rise { from { transform: scaleY(0); } to { transform: scaleY(1); } }

/* "Vida al saludo" del Hub (alta 06/10/2026, a pedido explícito) -- ver
   index.html, sección del saludo ("Buen día, X"). Igual que las barras de
   .kpi-spark de arriba, esto es una animación de UNA sola corrida (nunca
   infinite): juega una vez cuando el Hub se vuelve visible. Como
   view_role_selector arranca activo desde el parseo del HTML (antes de que
   termine el login), el disparo real no pasa solo con CSS -- ver
   reiniciarAnimacionesHubInicial() en index.html, que la reinicia a mano
   justo cuando se oculta el overlay de login, para que de verdad se vea. */
.hub-greeting-wave {
  display: inline-block;
  margin-right: 0.5rem;
  color: var(--primary);
  transform-origin: 70% 70%;
  animation: hub-greeting-wave 2.6s var(--ease-tech) 1 both;
}
/* Más paradas que antes, a pedido explícito ("se pierde muy rápido"): antes
   el vaivén terminaba a los 0.7s y el resto de la animación (0.9s) quedaba
   casi quieta -- eso es lo que se sentía como "se pierde". Ahora oscila
   durante todo el recorrido, con la amplitud decayendo de a poco (como una
   mano real asentándose), nunca dos paradas seguidas con el mismo valor. */
@keyframes hub-greeting-wave {
  0%   { transform: rotate(0deg); }
  8%   { transform: rotate(16deg); }
  18%  { transform: rotate(-11deg); }
  28%  { transform: rotate(15deg); }
  38%  { transform: rotate(-10deg); }
  48%  { transform: rotate(12deg); }
  58%  { transform: rotate(-7deg); }
  68%  { transform: rotate(8deg); }
  78%  { transform: rotate(-4deg); }
  88%  { transform: rotate(3deg); }
  100% { transform: rotate(0deg); }
}
.hub-greeting-accent {
  display: block;
  width: 64px;
  height: 4px;
  border-radius: 999px;
  margin-top: 0.6rem;
  background: linear-gradient(90deg, var(--secondary), var(--primary));
  transform: scaleX(0);
  transform-origin: left center;
  animation: hub-greeting-accent-in 0.7s var(--ease-enter) 0.25s 1 both;
}
@keyframes hub-greeting-accent-in {
  from { transform: scaleX(0); opacity: 0.4; }
  to   { transform: scaleX(1); opacity: 1; }
}

/* ---------------------------------------------------------- 6. MODALES */
/* .modal-content es el nombre real usado hoy en index.html para este mismo
   componente (17 apariciones): se trata como alias de .modal, no como un
   componente aparte, para no forzar un rename masivo en el HTML. */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(10, 15, 28, 0.55);
  backdrop-filter: blur(10px) saturate(1.1);
  -webkit-backdrop-filter: blur(10px) saturate(1.1);
  animation: overlay-in var(--motion-base) var(--ease-tech) both;
}
.modal-overlay[hidden], .modal-overlay.is-closed { display: none; }

.modal, .modal-content {
  position: relative;
  width: min(520px, 100%);
  max-height: 88vh;
  overflow: auto;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: var(--depth-3);
  animation: modal-in var(--motion-slow) var(--ease-enter) both;
}
.modal::before, .modal-content::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--grad-rail);
  border-radius: 18px 18px 0 0;
  animation: rail-draw var(--motion-slow) var(--ease-enter) 0.1s both;
}
.modal-head {
  display: flex; align-items: center; gap: 12px;
  padding: 20px 22px 14px;
  border-bottom: 1px solid var(--border);
}
.modal-head h3 {
  font-family: var(--font-heading-bold);
  font-weight: 700; font-size: 1.0625rem; margin: 0;
}
.modal-body { padding: 20px 22px; }
.modal-foot {
  display: flex; justify-content: flex-end; gap: 10px;
  padding: 14px 22px 20px;
}
.modal-close {
  margin-left: auto;
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: transform var(--motion-fast) var(--ease-tech), color var(--motion-fast) var(--ease-tech),
              border-color var(--motion-fast) var(--ease-tech);
}
.modal-close:hover { color: var(--primary); border-color: var(--primary); transform: rotate(90deg); }

@keyframes overlay-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-in {
  from { opacity: 0; transform: translateY(18px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}
@keyframes rail-draw { from { transform: scaleX(0); transform-origin: left; } to { transform: scaleX(1); } }

/* ----------------------------------------------------------- 7. TABLAS */
.table-wrap {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--card-radius);
  box-shadow: var(--depth-1);
  overflow: hidden;
}
.table-tech { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 0.875rem; }
.table-tech thead th {
  position: sticky; top: 0; z-index: 2;
  text-align: left;
  padding: 12px 16px;
  background: var(--grad-header);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
  font-family: var(--font-heading-bold);
  font-weight: 700;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--text-muted);
  white-space: nowrap;
}
.table-tech tbody td {
  padding: 13px 16px;
  border-bottom: 1px solid var(--hairline);
  color: var(--text-dark);
  transition: background var(--motion-fast) var(--ease-tech);
}
.table-tech tbody tr { position: relative; }
.table-tech tbody tr:last-child td { border-bottom: 0; }
.table-tech tbody tr:hover td { background: var(--primary-tint); }
/* marcador de fila activa, entra desde la izquierda */
.table-tech tbody tr td:first-child { box-shadow: inset 0 0 0 0 var(--primary); transition: box-shadow var(--motion-base) var(--ease-tech); }
.table-tech tbody tr:hover td:first-child { box-shadow: inset 3px 0 0 0 var(--primary); }
.table-tech .num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; text-align: right; }
.table-tech .col-actions { text-align: right; white-space: nowrap; }
.table-tech tbody tr .row-act { opacity: 0; transform: translateX(-4px); transition: opacity var(--motion-fast) var(--ease-tech), transform var(--motion-fast) var(--ease-tech); }
.table-tech tbody tr:hover .row-act { opacity: 1; transform: none; }

/* ----------------------------------------------------------- 8. BADGES */
.badge {
  --badge-color: var(--text-muted);
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 11px 4px 9px;
  border-radius: var(--pill-radius);
  border: 1px solid;
  font-size: 0.75rem;
  line-height: 1.4;
  letter-spacing: 0.01em;
  /* el texto usa --badge-text si el modificador lo define (ver más abajo);
     si no, cae al mismo tono que el punto/borde. El punto (::before) y el
     borde siguen usando --badge-color siempre: solo el texto necesita el
     ajuste de contraste, para no perder la identidad de color del estado. */
  color: var(--badge-text, var(--badge-color));
  border-color: color-mix(in oklab, var(--badge-color) 45%, transparent);
  background: color-mix(in oklab, var(--badge-color) 10%, transparent);
  transition: background var(--motion-fast) var(--ease-tech), transform var(--motion-fast) var(--ease-tech);
}
.badge::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--badge-color);
  box-shadow: 0 0 0 0 color-mix(in oklab, var(--badge-color) 60%, transparent);
}
.badge:hover { transform: translateY(-1px); }
/* --success (#10b981) y --warning (#f59e0b) son tonos "claros": a saturación
   plena, el texto sobre el fondo de 10% de tinte (casi blanco en light mode)
   queda en ~2:1 de contraste, muy por debajo del 4.5:1 mínimo para texto
   chico. --badge-text los oscurece SOLO para el texto (el punto y el borde
   siguen con el color pleno). En dark mode el mismo texto oscurecido
   perdería contraste contra el fondo casi negro, así que el override de
   abajo lo vuelve a su color pleno ahí. */
.badge--ok { --badge-color: var(--success); --badge-text: color-mix(in oklab, var(--success) 55%, black 45%); }
.badge--warn { --badge-color: var(--warning); --badge-text: color-mix(in oklab, var(--warning) 50%, black 50%); }
/* --secondary (navy) y --primary (rojo) son tonos oscuros: a saturación
   plena pasan bien en light mode contra el fondo casi blanco, pero en dark
   mode el mismo texto oscuro se hunde contra el fondo casi negro del propio
   badge (~2:1). El override de abajo los reemplaza por su variante clara
   solo en dark mode. */
.badge--info { --badge-color: var(--secondary); }
.badge--danger { --badge-color: var(--primary); }

/* Modificador para contadores numéricos (ej. campanita de notificaciones):
   .badge trae de fábrica un punto de estado (::before) + gap de 6px +
   padding asimétrico pensado para texto tipo "activa"/"pendiente" -- en un
   círculo de ~17px esos tres elementos empujan al número y lo deforman. Un
   contador es un número solo, sin indicador de estado, así que se le saca
   todo eso. border-radius fijo en vez de 50%: con dos dígitos (ej. "54") un
   50% sobre una caja que ya no es cuadrada redondea tan agresivo que come
   los bordes del texto -- con radio fijo queda una píldora que crece a lo
   ancho sin cortar nada, y con un solo dígito (mismo ancho que alto) se ve
   igual de circular. */
.badge--counter {
  display: inline-flex; align-items: center; justify-content: center;
  box-sizing: border-box;
  padding: 0 4px; gap: 0;
  border-radius: 999px;
}
.badge--counter::before { content: none; }

/* Modificador "salir / volver al portal": antes administracion.html y
   talento.html repetían el mismo style="color: #f87171" (coral) inline en
   cada uno -- un color fuera de la paleta de marca (rojo/azul). Reemplaza
   ese inline por esta clase, que usa var(--primary) como cualquier otro
   estado "danger" del sistema (mismo criterio que .badge--danger). Va acá
   y no en brand-tokens.css: ese archivo es fuente única de tokens de marca
   y no se edita. */
.ids-nav-link--danger {
  color: var(--primary-bright, var(--primary));
}

.ids-nav-link--danger:hover,
.ids-nav-link--danger:focus-visible {
  color: white;
  background-color: var(--primary);
}
/* estado en curso: borde punteado + latido, como el badge del Hub de Áreas */
.badge--live { --badge-color: var(--secondary); border-style: dashed; }
.badge--live::before { animation: badge-pulse 1.8s var(--ease-tech) infinite; }
/* --text-muted contra el fondo casi blanco del propio badge (10% de tinte,
   más claro que un fondo blanco liso) queda en ~4.2:1 -- justo debajo del
   mínimo. Mismo criterio que --ok/--warn: oscurecer un poco el texto,
   dejando el punto/borde con el tono original. */
.badge--idle { --badge-color: var(--text-muted); border-style: dotted; --badge-text: color-mix(in oklab, var(--text-muted) 85%, black 15%); }

/* Dark mode: contraste de texto de badge recalculado contra el fondo real
   del componente (10% del color de estado sobre --card-bg oscuro), no
   contra un fondo blanco genérico -- por eso los ajustes van en direcciones
   opuestas a los de light mode para el mismo color. */
html.dark-theme .badge--ok, body.dark-theme .badge--ok,
html.dark-theme .badge--warn, body.dark-theme .badge--warn,
html.dark-theme .badge--idle, body.dark-theme .badge--idle {
  /* en dark mode el tono pleno (sin oscurecer) ya da ~5.8-7:1 contra el
     fondo casi negro del badge: oscurecerlo como en light mode lo hundiría. */
  --badge-text: var(--badge-color);
}
html.dark-theme .badge--info, body.dark-theme .badge--info,
html.dark-theme .badge--live, body.dark-theme .badge--live {
  --badge-text: var(--secondary-bright);
}
html.dark-theme .badge--danger, body.dark-theme .badge--danger {
  /* --primary-bright (el tono ya usado para texto/iconos rojos en dark
     mode) queda muy cerca del mínimo (~4.4:1) contra el fondo particular
     del badge (más oscuro que otros usos de --primary-bright); se aclara
     un poco más solo para este caso. */
  --badge-text: color-mix(in oklab, var(--primary-bright) 78%, white 22%);
}

@keyframes badge-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in oklab, var(--badge-color) 60%, transparent); }
  70%  { box-shadow: 0 0 0 6px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* ------------------------------------------- 9. LOADERS / EMPTY / SKELETON */
/* loader de marca: tres barras diagonales, como el corte del logotipo */
.loader-ids { display: inline-flex; align-items: flex-end; gap: 5px; height: 30px; }
.loader-ids i {
  width: 6px; height: 100%;
  border-radius: 3px;
  background: var(--grad-primary);
  transform: skewX(-12deg);
  animation: loader-bar 1s var(--ease-tech) infinite;
}
.loader-ids i:nth-child(2) { animation-delay: 0.12s; }
.loader-ids i:nth-child(3) { animation-delay: 0.24s; }

@keyframes loader-bar {
  0%, 100% { transform: skewX(-12deg) scaleY(0.35); opacity: 0.45; }
  50%      { transform: skewX(-12deg) scaleY(1); opacity: 1; }
}

/* barra de progreso indeterminada para carga de módulo */
.loader-line { height: 2px; width: 100%; overflow: hidden; background: var(--surface-sunken); border-radius: 2px; }
.loader-line::after {
  content: "";
  display: block; height: 100%; width: 40%;
  background: var(--grad-rail);
  animation: loader-line 1.1s var(--ease-tech) infinite;
}
@keyframes loader-line {
  from { transform: translateX(-100%); }
  to   { transform: translateX(280%); }
}

.skeleton {
  background: linear-gradient(90deg, var(--surface-sunken) 0%, var(--hairline) 40%, var(--surface-sunken) 80%);
  background-size: 300% 100%;
  border-radius: 6px;
  animation: skeleton-sweep 1.4s var(--ease-tech) infinite;
}
@keyframes skeleton-sweep { from { background-position: 150% 0; } to { background-position: -150% 0; } }

.empty-state {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 12px;
  padding: 44px 24px;
  color: var(--text-muted);
}
.empty-state .empty-art {
  position: relative;
  width: 84px; height: 84px;
  display: grid; place-items: center;
  border-radius: 22px;
  background: var(--primary-tint);
  color: var(--primary);
  font-size: 1.75rem;
  animation: empty-float 4.5s var(--ease-tech) infinite;
}
.empty-state .empty-art::before,
.empty-state .empty-art::after {
  content: "";
  position: absolute; inset: -8px;
  border-radius: 26px;
  border: 1px dashed color-mix(in oklab, var(--primary) 35%, transparent);
  animation: empty-ring 3s var(--ease-tech) infinite;
}
.empty-state .empty-art::after { inset: -18px; border-radius: 32px; animation-delay: 0.5s; }
.empty-state h4 {
  font-family: var(--font-heading-bold); font-weight: 700;
  color: var(--text-dark); font-size: 1rem; margin: 0;
}
.empty-state p { margin: 0; max-width: 34ch; font-size: 0.875rem; }
html.dark-theme .empty-state .empty-art, body.dark-theme .empty-state .empty-art { color: var(--primary-bright); }
/* Variante para espacios chicos (ej. una sección dentro de un modal, como
   "Bloqueos" del modal de tarea del CRM): mismo componente, menos aire y un
   arte más chico, para no empujar el resto del formulario. */
.empty-state--compact { padding: 18px 12px; gap: 8px; }
.empty-state--compact .empty-art { width: 48px; height: 48px; border-radius: 14px; font-size: 1.1rem; }
.empty-state--compact .empty-art::before { inset: -5px; border-radius: 17px; }
.empty-state--compact .empty-art::after { inset: -10px; border-radius: 20px; }
.empty-state--compact h4 { font-size: 0.875rem; }
.empty-state--compact p { font-size: 0.8125rem; }

@keyframes empty-float {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-6px) rotate(-3deg); }
}
@keyframes empty-ring {
  0%   { opacity: 0.7; transform: scale(0.94); }
  70%  { opacity: 0; transform: scale(1.08); }
  100% { opacity: 0; }
}

/* ------------------------------------------- 10. SIDEBAR + FLYOUT DERECHA */
.nav-item {
  position: relative;
  display: flex; align-items: center; gap: 11px;
  width: 100%;
  padding: 10px 12px;
  border: 0;
  border-radius: var(--card-radius-sm);
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 0.875rem;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--motion-fast) var(--ease-tech), color var(--motion-fast) var(--ease-tech),
              padding-left var(--motion-fast) var(--ease-tech);
}
.nav-item > .fa-solid:first-child {
  width: 18px; text-align: center;
  transition: transform var(--motion-base) var(--ease-tech), color var(--motion-fast) var(--ease-tech);
}
.nav-item:hover { background: var(--primary-tint); color: var(--text-dark); padding-left: 15px; }
.nav-item:hover > .fa-solid:first-child { transform: scale(1.14) rotate(-6deg); color: var(--primary); }
.nav-item.is-active { color: var(--text-dark); background: var(--primary-tint-strong); }
.nav-item.is-active::before {
  content: "";
  position: absolute; left: 0; top: 8px; bottom: 8px;
  width: 3px; border-radius: 0 3px 3px 0;
  background: var(--primary);
  animation: rail-grow var(--motion-base) var(--ease-enter) both;
}
.nav-item .nav-caret { margin-left: auto; font-size: 0.6875rem; opacity: 0.6; transition: transform var(--motion-base) var(--ease-tech); }
.nav-group:hover > .nav-item .nav-caret,
.nav-group.is-open > .nav-item .nav-caret { transform: translateX(3px); opacity: 1; }

@keyframes rail-grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }

/* el submenú NUNCA se despliega hacia abajo: sale a la derecha */
.nav-group { position: relative; }
.nav-flyout {
  position: absolute;
  top: -8px;
  left: 100%;
  z-index: 60;
  width: var(--flyout-w);
  margin-left: 10px;
  padding: 8px;
  background: var(--surface-veil);
  backdrop-filter: blur(14px) saturate(1.2);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  border: 1px solid var(--border);
  border-radius: var(--card-radius);
  box-shadow: var(--depth-3);
  opacity: 0;
  transform: translateX(-10px) scale(0.98);
  transform-origin: left center;
  pointer-events: none;
  transition:
    opacity var(--motion-base) var(--ease-enter),
    transform var(--motion-base) var(--ease-enter);
}
.nav-group:hover > .nav-flyout,
.nav-group:focus-within > .nav-flyout,
.nav-group.is-open > .nav-flyout {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
/* puente invisible para que el mouse no pierda el flyout al cruzar el gap */
.nav-flyout::before { content: ""; position: absolute; top: 0; bottom: 0; left: -12px; width: 12px; }
/* cada ítem entra escalonado */
.nav-group:hover > .nav-flyout .nav-item,
.nav-group.is-open > .nav-flyout .nav-item { animation: flyout-item 0.3s var(--ease-enter) both; }
.nav-flyout .nav-item:nth-child(2) { animation-delay: 0.03s; }
.nav-flyout .nav-item:nth-child(3) { animation-delay: 0.06s; }
.nav-flyout .nav-item:nth-child(4) { animation-delay: 0.09s; }
.nav-flyout .nav-item:nth-child(5) { animation-delay: 0.12s; }
.nav-flyout .nav-item:nth-child(n + 6) { animation-delay: 0.15s; }
.nav-flyout-title {
  padding: 6px 12px 8px;
  font-family: var(--font-heading-bold); font-weight: 700;
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--text-muted);
}

@keyframes flyout-item {
  from { opacity: 0; transform: translateX(-8px); }
  to   { opacity: 1; transform: none; }
}

/* subgrupo anidado: sigue saliendo a la derecha */
.nav-flyout .nav-group > .nav-flyout { top: -8px; left: 100%; margin-left: 8px; }

@media (max-width: 768px) {
  .nav-flyout {
    position: static;
    width: auto; margin: 4px 0 4px 14px;
    padding: 6px 0 6px 12px;
    border-width: 0 0 0 1px;
    border-radius: 0;
    box-shadow: none;
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    transform: none;
    display: none;
    opacity: 1;
  }
  /* entrada del acordeón: es una apertura de submenú, no un hover -- usa la
     misma pareja motion-slow/ease-enter que el flyout de escritorio (tabla
     de "Movimiento" del SKILL), en vez del motion-base/ease-tech genérico
     que traía antes. */
  .nav-group.is-open > .nav-flyout { display: block; animation: module-in var(--motion-slow) var(--ease-enter) both; }
}

/* ------------------------------------------------- 11. INPUTS DE FORMULARIO */
.field { display: flex; flex-direction: column; gap: 7px; }
.field > label {
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--text-muted);
}
.input-tech {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  padding: 0 14px;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--card-radius-sm);
  transition: border-color var(--motion-fast) var(--ease-tech), background var(--motion-fast) var(--ease-tech),
              box-shadow var(--motion-base) var(--ease-tech);
}
.input-tech .fa-solid { color: var(--text-muted); font-size: 0.875rem; transition: color var(--motion-fast) var(--ease-tech); }
.input-tech input, .input-tech select {
  flex: 1;
  padding: 12px 0;
  border: 0; outline: none; background: transparent;
  color: var(--text-dark);
  font-family: var(--font-body); font-size: 0.9375rem;
}
/* select no hereda cursor:text de un input de texto -- sin esto, un <select>
   dentro de .input-tech (ej. elegir proveedor en Planilla Negocio) queda con
   la flecha nativa del navegador pero el cursor de línea de texto encima. */
.input-tech select { cursor: pointer; }
.input-tech:hover { border-color: var(--hairline-strong); }
.input-tech:focus-within {
  background: var(--card-bg);
  border-color: var(--secondary);
  box-shadow: 0 0 0 3px var(--secondary-tint);
}
.input-tech:focus-within .fa-solid { color: var(--secondary); }

/* ------------------------------------------------- 12. REDUCED MOTION */
@media (prefers-reduced-motion: reduce) {
  .ids-tech *, .ids-tech *::before, .ids-tech *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}


/* ------------------------------------------- 13. HUB DE ÁREAS (.tech-area-card)
   Evolución del patrón que ya funcionaba: glassmorphism, gradiente por área,
   rotación del ícono al hover. Se agrega el barrido diagonal y el riel inferior. */
.area-grid {
  display: grid;
  gap: 18px;
  /* auto-fit (no auto-fill): con pocas tarjetas (hoy 6) y ventana muy ancha
     (monitores ultra-wide), auto-fill reserva columnas fantasma vacías al
     final de la fila y las tarjetas reales quedan angostas con un vacío a la
     derecha. auto-fit colapsa esas columnas vacías y deja que las tarjetas
     reales se estiren para ocupar el ancho disponible. */
  grid-template-columns: repeat(auto-fit, minmax(268px, 1fr));
}

.tech-area-card {
  --area-a: var(--primary);
  --area-b: var(--primary-hover);
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 22px;
  min-height: 178px;
  border: 1px solid var(--border);
  border-radius: 18px;
  background: var(--surface-veil);
  backdrop-filter: blur(12px) saturate(1.15);
  -webkit-backdrop-filter: blur(12px) saturate(1.15);
  box-shadow: var(--depth-1);
  color: inherit;
  text-decoration: none;
  overflow: hidden;
  cursor: pointer;
  transition:
    transform var(--motion-base) var(--ease-tech),
    box-shadow var(--motion-base) var(--ease-tech),
    border-color var(--motion-fast) var(--ease-tech);
}
/* halo del área */
.tech-area-card::before {
  content: "";
  position: absolute;
  top: -55%; right: -25%;
  width: 260px; height: 260px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--area-a) 0%, transparent 66%);
  opacity: 0.1;
  transition: opacity var(--motion-base) var(--ease-tech), transform var(--motion-slow) var(--ease-tech);
}
/* riel inferior que se dibuja al hover */
.tech-area-card::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--area-a), var(--area-b));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--motion-slow) var(--ease-enter);
}
.tech-area-card > * { position: relative; z-index: 1; }

.tech-area-card:hover {
  transform: translateY(-8px) scale(1.01);
  box-shadow: var(--depth-3);
  border-color: color-mix(in oklab, var(--area-a) 40%, transparent);
}
.tech-area-card:hover::before { opacity: 0.2; transform: scale(1.14); }
.tech-area-card:hover::after { transform: scaleX(1); }
.tech-area-card:focus-visible { box-shadow: var(--focus-ring); }

.area-icon {
  width: 50px; height: 50px;
  display: grid; place-items: center;
  border-radius: 15px;
  background: linear-gradient(135deg, var(--area-a), var(--area-b));
  color: #fff;
  font-size: 1.25rem;
  box-shadow: 0 6px 16px -6px color-mix(in oklab, var(--area-a) 70%, transparent);
  transition: transform var(--motion-base) var(--ease-tech);
}
.tech-area-card:hover .area-icon { transform: rotate(-3deg) scale(1.08); }

.area-name {
  font-family: var(--font-heading-bold);
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: -0.01em;
  color: var(--text-dark);
  margin: 0;
}
.area-desc { margin: 0; font-size: 0.8125rem; line-height: 1.55; color: var(--text-muted); }
.area-foot {
  margin-top: auto;
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--text-muted);
}
.area-arrow {
  margin-left: auto;
  color: var(--area-a);
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity var(--motion-base) var(--ease-tech), transform var(--motion-base) var(--ease-tech);
}
.tech-area-card:hover .area-arrow { opacity: 1; transform: none; }

/* El flyout se ancla al viewport, no al ítem: con top y bottom fijos más
   height fit-content y margin auto queda centrado y NUNCA se corta, sin
   importar si el grupo está arriba o abajo del sidebar ni cuántos ítems tenga. */
.nav-flyout {
  position: fixed;
  top: 14px; bottom: 14px;
  left: calc(var(--sidebar-w) + 10px);
  margin-left: 0;
  height: fit-content;
  max-height: calc(100vh - 28px);
  overflow-x: hidden;
  overflow-y: auto;
  scrollbar-width: thin;
  overscroll-behavior: contain;
  margin-block: auto;
}
/* los subgrupos anidados siguen colgando de su padre */
.nav-flyout .nav-group > .nav-flyout { left: auto; }

@media (max-width: 768px) {
  .nav-flyout {
    position: static;
    top: auto; bottom: auto; left: auto;
    height: auto; max-height: none;
    overflow: visible;
    margin-block: 4px;
  }
}

/* --------------------------------------------------- 14. HEADER CARD
   Banner superior de módulo/vista. Fuente única: antes existían 4 versiones
   distintas (index.html, administracion.html, talento.html, más una en
   modulos-bridge.css con !important que le ganaba a las otras tres y, de
   paso, dejaba sin efecto real ~40 estilos inline de color de acento en
   index.html). La variación de color por vista entra por
   --header-card-a/--header-card-b (mismo patrón que --area-a/--area-b de
   .tech-area-card): siempre un tinte de rojo o azul de marca, nunca un
   color nuevo.
   Rediseño: antes era un bloque de RELLENO sólido en gradiente (navy → rojo)
   con texto blanco encima -- el único componente de todo IDS Tech con un
   fondo de color pleno (el resto son --card-bg + acento: .card,
   .tech-area-card, .kpi-tile). Ahora es una tarjeta normal, sin relleno de
   color: mismo --card-bg que cualquier otra tarjeta, y el color de marca
   vive SOLO en el borde (gradiente de dos tonos, técnica de doble capa de
   background: padding-box con --card-bg + border-box con el gradiente,
   nada de máscaras) y en el halo. --header-card-a/--header-card-b siguen
   siendo la única perilla de color por módulo: antes pintaban el fondo
   entero, ahora pintan el borde y el halo -- ningún HTML que ya seteaba
   estas variables por style="" necesita cambiar. Sigue leyéndose como
   protagonista por tamaño/tipografía y por ser el único borde en gradiente
   de dos tonos del sistema (el resto usa --border sólido). */
.header-card {
  --header-card-a: var(--secondary);
  --header-card-b: var(--primary);
  position: relative;
  background:
    linear-gradient(var(--card-bg), var(--card-bg)) padding-box,
    linear-gradient(135deg, var(--header-card-a) 0%, var(--header-card-b) 100%) border-box;
  color: var(--text-dark);
  padding: 2.25rem 2.5rem;
  border-radius: var(--card-radius);
  border: 1.5px solid transparent;
  box-shadow: var(--depth-2);
  margin-bottom: 1.75rem;
  overflow: hidden;
  /* Rediseño 05/10/2026, a pedido explícito ("la animación es insulsa, quiero
     que se vea mejor"): la tarjeta ahora reacciona al pasar el mouse (se
     eleva un toque) -- ver .header-card:hover más abajo. */
  transition: transform var(--motion-base) var(--ease-tech), box-shadow var(--motion-base) var(--ease-tech);
}
.header-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--depth-3);
}
/* Halo decorativo -- ahora DOBLE (05/10/2026, a pedido explícito: "más
   vistoso"): dos manchas de luz en esquinas opuestas, una con cada tono de
   marca (--header-card-a/--header-card-b), en vez de un único círculo en una
   esquina. Van en el mismo pseudo-elemento (cubre toda la tarjeta con
   inset:0) para que una sola animación de transform las mueva como unidad,
   sin necesitar un pseudo-elemento extra que no existe en CSS. En reposo se
   ven más grandes y más saturadas que la versión anterior; al pasar el mouse
   el drift se pausa y el halo queda a tope de opacidad (ver :hover), como
   si la tarjeta "despertara". */
.header-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 96% 2%, color-mix(in oklab, var(--header-card-a) 55%, transparent) 0%, transparent 42%),
    radial-gradient(circle at 2% 100%, color-mix(in oklab, var(--header-card-b) 46%, transparent) 0%, transparent 40%);
  pointer-events: none;
  animation: header-halo-drift 6s var(--ease-tech) infinite alternate;
}
.header-card:hover::after {
  animation-play-state: paused;
  opacity: 1;
}
/* deriva del halo doble: más amplitud que la versión anterior (opacity
   0.7->1, traslado/escala más marcados) para que se note de verdad sin
   dejar de ser una deriva, no un parpadeo. Dos paradas (from/to) + alternate
   = curva continua, sin tramos planos. Solo transform/opacity. */
@keyframes header-halo-drift {
  from { opacity: 0.7; transform: translate3d(0, 0, 0) scale(1); }
  to   { opacity: 1; transform: translate3d(-22px, 16px, 0) scale(1.2); }
}
/* Entrada ÚNICA del anillo (rediseño 05/10/2026: reemplaza el pulso
   infinito anterior, que a fuerza de repetirse para siempre se sentía
   "insulso" en vez de vistoso). Un anillo grueso en gradiente invertido
   (b -> a) destella una sola vez y se asienta -- gracias a que .page-view
   usa display:none/block para cambiar de pantalla, el navegador trata cada
   reingreso a una sección como una entrada nueva del elemento, así que este
   destello se repite cada vez que ABRÍS esa pantalla (no una sola vez en
   toda la sesión), que es lo que realmente se ve como "vistoso" sin quedar
   parpadeando todo el tiempo como antes. animation-iteration-count:1 a
   propósito (nunca infinite). Misma técnica de doble capa de background que
   el borde real, sin ninguna API nueva; 3 paradas con valores siempre
   distintos entre sí = curva continua, nunca un tramo plano. */
.header-card::before {
  content: "";
  position: absolute;
  inset: 0;
  box-sizing: border-box;
  border-radius: inherit;
  border: 8px solid transparent;
  background:
    linear-gradient(var(--card-bg), var(--card-bg)) padding-box,
    linear-gradient(135deg, var(--header-card-b) 0%, var(--header-card-a) 100%) border-box;
  pointer-events: none;
  opacity: 0;
  animation: header-ring-entrance 1.1s var(--ease-enter) 1 both;
}
@keyframes header-ring-entrance {
  0%   { opacity: 0;    transform: scale(1.03); }
  55%  { opacity: 0.85; transform: scale(1.004); }
  100% { opacity: 0;    transform: scale(1); }
}
/* Ícono de fondo (alta 05/10/2026, a pedido explícito: "incluir imágenes, o
   algo"): no hay fotografía de stock en IDS Tech (solo FontAwesome), así que
   en vez de una imagen se usa el MISMO ícono del título de la tarjeta,
   clonado gigante y traslúcido como marca de agua -- ver
   decorarHeaderCardsConIcono() en cada página (index.html/administracion.html/
   talento.html), que clona el <i> de .header-title una sola vez por tarjeta
   al cargar. Clase sola, sin selector de elemento: así no depende de qué
   ícono puntual sea. */
.header-card-icon-bg {
  position: absolute;
  top: 50%;
  right: -0.5rem;
  transform: translateY(-50%);
  font-size: 7rem;
  line-height: 1;
  /* El glifo de FontAwesome se pinta en el ::before del <i>, no en el <i>
     mismo -- un truco de "background-clip:text" puesto acá no llegaría a
     ese ::before (background no se hereda) y el ícono quedaría invisible.
     `color` sí se hereda al ::before (es como ya se pintan todos los demás
     íconos de HomeIDS, ej. color: var(--primary) inline), así que el tinte
     usa directamente eso -- un solo tono mezclado entre las dos variables
     de marca de la tarjeta, no un degradé real, pero fiable. */
  color: color-mix(in oklab, var(--header-card-b) 65%, var(--header-card-a) 35%);
  opacity: 0.1;
  pointer-events: none;
  z-index: 0;
  animation: header-icon-entrance 1s var(--ease-enter) 1 both;
}
@keyframes header-icon-entrance {
  0%   { opacity: 0; transform: translateY(-50%) scale(0.82) rotate(-8deg); }
  100% { opacity: 0.1; transform: translateY(-50%) scale(1) rotate(0deg); }
}
.header-card .header-title,
.header-title {
  position: relative;
  z-index: 1;
  font-family: var(--font-heading-bold);
  font-weight: 800;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
  color: var(--text-dark);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.35rem;
}
.header-card .header-subtitle,
.header-subtitle {
  position: relative;
  z-index: 1;
  font-family: var(--font-body);
  font-size: 0.9375rem;
  /* Antes usaba --text-muted (gris tenue): a pedido explícito, mismo color
     firme que el título (--text-dark) para que se lea bien siempre, tanto
     en reposo como durante la animación del borde. */
  color: var(--text-dark);
  line-height: 1.5;
  max-width: 800px;
}
html.dark-theme .header-card, body.dark-theme .header-card { box-shadow: var(--depth-3); }
html.dark-theme .header-card:hover, body.dark-theme .header-card:hover { box-shadow: var(--depth-3); }

/* administracion.html y talento.html no tenían NINGÚN @media propio: este
   ajuste vive acá (fuente única de .header-card) para que las 3 páginas que
   lo usan se beneficien igual, sin duplicarlo en cada <style> embebido. */
@media (max-width: 768px) {
  .header-card { padding: 1.5rem 1.5rem; }
  .header-title, .header-card .header-title { font-size: 1.25rem; }
  /* El ícono de fondo compite por espacio con el texto en pantallas
     angostas (el subtítulo puede ocupar todo el ancho) -- se saca, no se
     reduce, para no arriesgar legibilidad. */
  .header-card-icon-bg { display: none; }
}

/* ------------------------------------------ 15. CRM: BLOQUEOS DE TAREA
   Alta 15/10/2026 (a pedido explícito). Sección "Bloqueos" del modal de
   tarea del CRM de Desarrollo, modal "¿Por qué se bloquea?" y avisos de la
   tarjeta del Kanban. Reemplaza al checkbox "Tuvo un bloqueante externo".
   Reusa .badge, .field, .input-tech, .btn-premium y .empty-state--compact:
   acá va solo el layout propio de la lista y del formulario. */
.bloqueos-tarea {
  display: flex; flex-direction: column; gap: 12px;
  border-top: 1px solid var(--border);
  padding-top: 1rem; margin-top: 0.5rem;
}
.bloqueos-tarea[hidden] { display: none; }
.bloqueos-tarea__head { display: flex; align-items: center; gap: 10px; }
.bloqueos-tarea__head .btn-premium { margin-left: auto; }
.bloqueos-tarea__head .btn-premium[hidden] { display: none; }
/* mismo aspecto que los demás títulos de sección del modal de tarea
   (Historial, Conversación), pero con la fuente de títulos del sistema */
.bloqueos-tarea__title {
  display: flex; align-items: center; gap: 6px; margin: 0;
  font-family: var(--font-heading-bold); font-weight: 700;
  font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--secondary);
}
.bloqueos-tarea__list { display: flex; flex-direction: column; gap: 8px; }
.bloqueos-tarea__form {
  display: flex; flex-direction: column; gap: 12px;
  padding: 14px;
  background: var(--card-bg);
  border: 1px dashed var(--hairline-strong);
  border-radius: var(--card-radius-sm);
}
.bloqueos-tarea__form[hidden] { display: none; }
/* dentro del modal "¿Por qué se bloquea?" el propio .modal ya es el marco */
.bloqueos-tarea__form--plano { padding: 0; border: 0; background: transparent; }
.bloqueos-tarea__form-title {
  font-family: var(--font-heading-bold); font-weight: 700;
  font-size: 0.875rem; color: var(--text-dark);
}
.bloqueos-tarea__fechas {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px;
}
.bloqueos-tarea__hint { margin: 0; font-size: 0.78rem; color: var(--text-muted); }
.bloqueos-tarea__hint:empty { display: none; }
.bloqueos-tarea__acciones { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }

.bloqueo-item {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 10px; align-items: start;
  padding: 10px 12px;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--card-radius-sm);
}
.bloqueo-item__tipo {
  font-family: var(--font-heading-bold); font-weight: 700;
  font-size: 0.85rem; color: var(--text-dark);
}
.bloqueo-item__meta { font-size: 0.78rem; color: var(--text-muted); overflow-wrap: anywhere; }
.bloqueo-item__meta .num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.bloqueo-item__side { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.bloqueo-item__acciones { display: flex; gap: 4px; }
.bloqueo-item__acciones .btn-premium { padding: 6px 9px; }

/* alta de un tipo nuevo desde el desplegable ("+ Nuevo tipo…") */
.tipo-bloqueo-nuevo {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 10px;
  padding: 12px;
  background: var(--surface-sunken);
  border-radius: var(--card-radius-sm);
}
.tipo-bloqueo-nuevo[hidden] { display: none; }
.tipo-bloqueo-nuevo .bloqueos-tarea__acciones { grid-column: 1 / -1; }

/* sprint de origen, arriba del historial de estados del modal de tarea */
.tarea-origen {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  border-top: 1px solid var(--border);
  padding-top: 1rem; margin-top: 0.5rem;
  font-size: 0.82rem; color: var(--text-muted);
}
.tarea-origen[hidden] { display: none; }
.tarea-origen .fa-solid { color: var(--secondary); }
.tarea-origen strong { font-family: var(--font-heading-bold); color: var(--text-dark); }

/* avisos de bloqueo en la tarjeta del Kanban (tipo del bloqueo abierto,
   "Bloqueante externo"): fila que no estira los badges a todo el ancho */
.kanban-card-avisos { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; }

html.dark-theme .bloqueos-tarea__title, body.dark-theme .bloqueos-tarea__title,
html.dark-theme .tarea-origen .fa-solid, body.dark-theme .tarea-origen .fa-solid {
  color: var(--secondary-bright);
}

@media (max-width: 768px) {
  .tipo-bloqueo-nuevo { grid-template-columns: minmax(0, 1fr); }
  .bloqueo-item { grid-template-columns: minmax(0, 1fr); }
  .bloqueo-item__side { flex-direction: row; align-items: center; justify-content: space-between; }
}
