/* ═══════════════════════════════════════════════════════════════════════════
   COMPONENTES — describen QUÉ ES algo, con variantes por sufijo.
   Contratos y nombres en docs/FRONTEND.md §4. Dirección visual en §1:

   "Tablero de tienda" — los bloques son ETIQUETAS planas (hairline, sin
   sombra). La sombra queda reservada a lo que de verdad flota (modal, toast).
   El fondo de la app es un lienzo tintado por la marca, que es lo que permite
   separar superficies sin sombras.

   2026-09-04: se retiró el acento de color al borde ("lomo") que existía en
   tarjetas, la nav activa y las herramientas — es un patrón reconocible de
   interfaz generada por IA (Notion/shadcn lo usan por todos lados) y el
   usuario pidió sacarlo de raíz. La jerarquía ahora se hace solo con
   tipografía, color de texto/fondo y badges — nunca con un borde de acento.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────── BLOQUE ─────────────────────────────────────
   La superficie base (reemplaza a la vieja .card con sombra). */
.bloque {
  background: var(--surface);
  border: 1px solid var(--line-100);
  border-radius: var(--r-md);
  padding: var(--sp-5);
}
.bloque-sm { padding: var(--sp-4); }
.bloque-plano { border-radius: 0; }
.bloque-cabecera {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
  margin-bottom: var(--sp-4); padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line-100);
}
.bloque-titulo {
  font-size: var(--fs-lg); font-weight: 800; color: var(--ink-900);
  letter-spacing: -.01em;
}

/* ─────────────────────────────── BADGE ──────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: 3px 10px; border-radius: var(--r-pill);
  font-size: var(--fs-xs); font-weight: 600; white-space: nowrap;
}
.badge-info    { background: var(--info-bg);    color: var(--brand-700); }
.badge-logro   { background: var(--logro-bg);   color: var(--logro); }
.badge-urgente { background: var(--urgente-bg); color: var(--urgente); }
.badge-evento  { background: var(--evento-bg);  color: var(--evento); }
.badge-neutro  { background: var(--neutro-bg);  color: var(--ink-500); }
.badge-solido  { background: var(--brand-600);  color: #fff; }
/* Punto de estado dentro de una badge (encuesta activa, usuario en línea). */
.badge-punto::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; flex-shrink: 0;
}

/* ─────────────────────────────── BOTONES ────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 38px; padding: 9px var(--sp-5);
  border: 1px solid transparent; border-radius: var(--r-md);
  font-family: var(--font); font-size: var(--fs-md); font-weight: 600;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background-color var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out),
              color var(--dur-1) var(--ease-out);
}
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn-primary { background: var(--brand-600); color: #fff; }
.btn-primary:hover:not(:disabled) { background: var(--brand-700); }
.btn-accent  { background: var(--evento); color: #fff; }
.btn-accent:hover:not(:disabled) { background: #A96A0F; }
.btn-outline { background: var(--surface); color: var(--brand-600); border-color: var(--line-200); }
.btn-outline:hover:not(:disabled) { background: var(--brand-50); border-color: var(--brand-300); }
.btn-ghost   { background: transparent; color: var(--ink-500); }
.btn-ghost:hover:not(:disabled) { background: var(--canvas); color: var(--ink-900); }
.btn-danger  { background: var(--urgente); color: #fff; }
.btn-danger:hover:not(:disabled) { background: #A82F2F; }
.btn-sm { min-height: 32px; padding: 5px var(--sp-3); font-size: var(--fs-sm); }
/* Target Size Minimum (WCAG 2.5.8): 32px en escritorio, 44 en táctil (ver el
   bloque responsive del final). */
.btn-icon {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 32px; min-height: 32px; padding: var(--sp-2);
  border: none; border-radius: var(--r-sm); background: transparent;
  color: var(--ink-500); cursor: pointer; font-size: var(--fs-md);
  transition: background-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
}
.btn-icon:hover { background: var(--canvas); color: var(--ink-900); }

/* Chip de filtro (barra de herramientas de un listado). Estado por aria-pressed,
   no por una clase — así el estado real y el visual no pueden divergir. */
.chip {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  min-height: 32px; padding: 4px var(--sp-3);
  background: var(--surface); color: var(--ink-500);
  border: 1px solid var(--line-200); border-radius: var(--r-pill);
  font-family: var(--font); font-size: var(--fs-sm); font-weight: 600;
  cursor: pointer;
  transition: background-color var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
}
.chip:hover { border-color: var(--brand-300); color: var(--ink-900); }
.chip[aria-pressed="true"] {
  background: var(--brand-600); border-color: var(--brand-600); color: #fff;
}

/* ────────────────────────────── FORMULARIOS ─────────────────────────────── */
.form-group { margin-bottom: var(--sp-4); }
.form-label {
  display: block; margin-bottom: var(--sp-2);
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-700);
}
.form-control {
  width: 100%; padding: 10px var(--sp-3);
  background: var(--surface); color: var(--ink-900);
  border: 1px solid var(--line-200); border-radius: var(--r-md);
  font-family: var(--font); font-size: var(--fs-md);
  transition: border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out);
}
.form-control::placeholder { color: var(--ink-300); }
.form-control:focus { outline: none; border-color: var(--brand-600); box-shadow: var(--focus-ring); }
.form-control.has-error { border-color: var(--urgente); }
.form-control.has-error:focus { box-shadow: 0 0 0 3px rgba(201, 58, 58, .22); }
.form-hint  { margin-top: var(--sp-1); font-size: var(--fs-xs); color: var(--ink-300); }
.form-error { margin-top: var(--sp-1); font-size: var(--fs-xs); font-weight: 600; color: var(--urgente); }
select.form-control { appearance: none; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-300) 50%),
                    linear-gradient(135deg, var(--ink-300) 50%, transparent 50%);
  background-position: calc(100% - 16px) 50%, calc(100% - 11px) 50%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
  padding-right: var(--sp-8);
}
textarea.form-control { resize: vertical; min-height: 92px; line-height: var(--lh-base); }
input[type="file"].form-control { padding: var(--sp-2); font-size: var(--fs-sm); }
input[type="color"].form-control { height: 42px; padding: 4px; cursor: pointer; }
input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--brand-600); cursor: pointer; }
.form-check { display: flex; align-items: center; gap: var(--sp-2); cursor: pointer; font-size: var(--fs-md); }
.form-acciones {
  display: flex; gap: var(--sp-2); justify-content: flex-end;
  margin-top: var(--sp-5); padding-top: var(--sp-4); border-top: 1px solid var(--line-100);
}
/* Lista de opciones con scroll dentro de un modal (asignar tiendas, áreas...). */
.lista-check {
  max-height: 320px; overflow-y: auto;
  border: 1px solid var(--line-100); border-radius: var(--r-md);
  padding: var(--sp-2) var(--sp-3);
}
.lista-check label { display: flex; align-items: center; gap: var(--sp-2); padding: 6px 0; cursor: pointer; }

/* Aviso de error global del formulario (arriba del propio form, dentro del
   modal — abrir un segundo modal perdería lo ya escrito). */
.form-error-banner {
  background: var(--urgente-bg); color: var(--urgente);
  border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm); margin-bottom: var(--sp-4); text-align: left;
  animation: entrar var(--dur-2) var(--ease-out);
}
.form-error-banner ul { margin: var(--sp-1) 0 0; padding-left: var(--sp-5); }

/* ─────────────────────────────── TOGGLE ─────────────────────────────────── */
.toggle {
  display: inline-flex; align-items: center; flex-shrink: 0;
  width: 42px; height: 24px; padding: 2px; border: none;
  border-radius: var(--r-pill); background: var(--line-200); cursor: pointer;
  transition: background-color var(--dur-2) var(--ease-inout);
}
.toggle[aria-pressed="true"] { background: var(--brand-600); }
.toggle-knob {
  width: 20px; height: 20px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 3px rgba(19,26,43,.28);
  transform: translateX(0);
  transition: transform var(--dur-2) var(--ease-spring);
}
.toggle[aria-pressed="true"] .toggle-knob { transform: translateX(18px); }

/* ──────────────────────────────── LOGIN ─────────────────────────────────── */
#loginScreen, #cambiarPasswordScreen {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  padding: var(--sp-5);
  background:
    radial-gradient(1200px 600px at 15% -10%, rgba(127,165,208,.35), transparent 60%),
    linear-gradient(160deg, var(--brand-900) 0%, var(--brand-600) 70%, #2A6DB5 100%);
}
.login-box {
  width: 100%; max-width: 420px;
  background: var(--surface); border-radius: var(--r-lg);
  padding: var(--sp-8) var(--sp-7); box-shadow: var(--elev-2);
  animation: entrar var(--dur-3) var(--ease-out);
}
.login-logo { display: flex; align-items: center; justify-content: center; gap: var(--sp-3); margin-bottom: var(--sp-7); }
.login-logo-icon {
  width: 44px; height: 44px; flex-shrink: 0;
  background: var(--brand-600); border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
}
.login-logo-icon svg { width: 26px; height: 26px; fill: #fff; }
.login-marca { font-size: var(--fs-2xl); font-weight: 800; color: var(--brand-600); letter-spacing: -.03em; line-height: 1; }
.login-title { font-size: var(--fs-xl); font-weight: 800; color: var(--ink-900); text-align: center; letter-spacing: var(--tracking-display); }
.login-sub   { font-size: var(--fs-sm); color: var(--ink-500); text-align: center; margin: var(--sp-2) 0 var(--sp-6); }
.login-error {
  background: var(--urgente-bg); color: var(--urgente); border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4); font-size: var(--fs-sm); margin-bottom: var(--sp-4);
  animation: entrar var(--dur-2) var(--ease-out);
}
.login-box .btn { width: 100%; min-height: 44px; }

/* ─────────────────────────────── LAYOUT ─────────────────────────────────── */
#app { display: flex; min-height: 100vh; }

.sidebar {
  position: fixed; top: 0; left: 0; z-index: 100;
  width: var(--sidebar-w); height: 100vh;
  display: flex; flex-direction: column;
  background: var(--surface); border-right: 1px solid var(--line-100);
  transition: transform var(--dur-2) var(--ease-inout), width var(--dur-2) var(--ease-inout);
}
.sidebar-brand {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5); border-bottom: 1px solid var(--line-100);
}
.sidebar-brand-icon {
  width: 34px; height: 34px; flex-shrink: 0;
  background: var(--brand-600); border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
}
.sidebar-brand-icon svg { width: 19px; height: 19px; }
.sidebar-brand-text .name { font-size: var(--fs-xl); font-weight: 800; color: var(--brand-600); letter-spacing: -.04em; line-height: 1.1; }
.sidebar-brand-text .tagline {
  font-size: var(--fs-eyebrow); font-weight: 700; color: var(--ink-300);
  text-transform: uppercase; letter-spacing: var(--tracking-eyebrow);
}
.sidebar-nav { flex: 1; padding: var(--sp-3) 0; overflow-y: auto; }
.nav-section { padding: var(--sp-1) var(--sp-3); margin-top: var(--sp-3); }
.nav-section:first-child { margin-top: 0; }
.nav-section-label { padding: 0 var(--sp-3); margin-bottom: var(--sp-1); }
.nav-item {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%;
  padding: 9px var(--sp-3); margin: 1px 0;
  background: none; border: none; border-radius: var(--r-sm);
  font-family: var(--font); font-size: var(--fs-md); font-weight: 500;
  color: var(--ink-700); text-align: left; cursor: pointer;
  transition: background-color var(--dur-1) var(--ease-out),
              color var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out);
}
.nav-item:hover { background: var(--canvas); color: var(--ink-900); }
.nav-item[aria-current="page"] {
  background: var(--brand-100); color: var(--brand-700); font-weight: 700;
}
.nav-icon { width: 20px; flex-shrink: 0; text-align: center; font-size: var(--fs-lg); line-height: 1; }
/* Chip de iniciales del área: con el sidebar colapsado, cinco 🧰 idénticos eran
   indistinguibles. Ver core/router.js (icono como { texto: 'CO' }). */
.nav-chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: var(--r-sm);
  background: var(--brand-100); color: var(--brand-700);
  font-size: 0.62rem; font-weight: 800; letter-spacing: .03em;
}
.nav-item[aria-current="page"] .nav-chip { background: var(--brand-600); color: #fff; }
.nav-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Desplegable de herramientas por área (2026-09-08): el botón principal de la
   fila sigue navegando a la grilla como cualquier .nav-item — el chevron es un
   control aparte (.disclosure-toggle genérico, ver core/ui.js) que solo
   muestra/oculta la sublista real. Separarlos en dos botones (en vez de que
   uno solo abra+navegue) es lo que permite que el sidebar colapsado a íconos
   siga funcionando sin cambios: ahí se oculta el chevron/panel más abajo y el
   botón principal queda igual que cualquier otro ícono de área. */
.nav-item-grupo { margin: 1px 0; }
.nav-item-fila { display: flex; align-items: stretch; gap: 2px; }
.nav-item-fila .nav-item-principal { flex: 1; min-width: 0; margin: 0; }
/* .disclosure-toggle (el patrón genérico que reutiliza este botón, ver más abajo)
   trae `width: 100%` — sin este selector más específico que lo pisa, ese 100%
   gana la cascada y empuja a .nav-item-principal a encogerse casi a cero. */
.nav-item-fila .nav-item-chevron-btn {
  display: flex; align-items: center; justify-content: center;
  width: 28px; flex: 0 0 28px; background: none; border: none; border-radius: var(--r-sm);
  color: var(--ink-300); cursor: pointer;
}
.nav-item-fila .nav-item-chevron-btn:hover { background: var(--canvas); color: var(--ink-900); }
.nav-subitem {
  display: block; width: 100%; padding: 6px var(--sp-3) 6px calc(20px + var(--sp-3) * 2);
  margin: 1px 0; background: none; border: none; border-radius: var(--r-sm);
  font-family: var(--font); font-size: var(--fs-sm); color: var(--ink-500);
  text-align: left; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nav-subitem:hover { background: var(--canvas); color: var(--ink-900); }
.nav-subitem-ver-todas { color: var(--brand-600); font-weight: 600; }
/* Sin espacio para leer una sublista en el riel de íconos — el botón principal
   sigue navegando igual, solo se oculta el control de despliegue. */
#app.sidebar-colapsado .nav-item-chevron-btn,
#app.sidebar-colapsado .nav-item-grupo .disclosure-panel { display: none; }
.nav-badge {
  margin-left: auto; padding: 1px 7px; border-radius: var(--r-pill);
  background: var(--urgente); color: #fff; font-size: var(--fs-eyebrow); font-weight: 700;
}
.sidebar-user {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--line-100);
}
.sidebar-user-info { min-width: 0; }
.sidebar-user-info .name { font-size: var(--fs-sm); font-weight: 600; color: var(--ink-900); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar-user-info .role { font-size: var(--fs-xs); color: var(--ink-300); }

/* Sidebar colapsado (escritorio): sigue visible, solo se angosta a íconos.
   OJO: .nav-label se oculta, por eso cada .nav-item lleva aria-label propio en
   router.js — display:none también borra el texto para un lector de pantalla. */
#app.sidebar-colapsado .sidebar { width: var(--sidebar-w-colapsado); }
#app.sidebar-colapsado .main-area { margin-left: var(--sidebar-w-colapsado); }
#app.sidebar-colapsado .sidebar-brand { padding: var(--sp-4) var(--sp-2); justify-content: center; }
#app.sidebar-colapsado .sidebar-brand-text,
#app.sidebar-colapsado .nav-label,
#app.sidebar-colapsado .nav-section-label,
#app.sidebar-colapsado .sidebar-user-info { display: none; }
#app.sidebar-colapsado .nav-section { border-top: 1px solid var(--line-100); padding-top: var(--sp-2); }
#app.sidebar-colapsado .nav-section:first-child { border-top: none; }
#app.sidebar-colapsado .nav-item { justify-content: center; padding-inline: var(--sp-2); }
#app.sidebar-colapsado .sidebar-user { justify-content: center; padding-inline: var(--sp-2); }
#app.sidebar-colapsado #sidebarColapsarBtn { margin: 0; }

.main-area {
  flex: 1; min-width: 0; display: flex; flex-direction: column;
  margin-left: var(--sidebar-w);
  transition: margin-left var(--dur-2) var(--ease-inout);
}
.topbar {
  position: sticky; top: 0; z-index: 90;
  height: var(--topbar-h); display: flex; align-items: center; gap: var(--sp-4);
  padding: 0 var(--sp-6);
  background: rgba(255,255,255,.88); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line-100);
}
.topbar-title { font-size: var(--fs-lg); font-weight: 700; color: var(--ink-900); }
.sidebar-toggle { display: none; }
.velo-sidebar {
  position: fixed; inset: 0; z-index: 99;
  background: rgba(19,26,43,.42); backdrop-filter: blur(2px);
  opacity: 0; pointer-events: none; transition: opacity var(--dur-2) var(--ease-out);
}
.velo-sidebar.visible { opacity: 1; pointer-events: auto; }

.page-content { flex: 1; width: 100%; max-width: var(--content-max); padding: var(--sp-6); }
/* El router le mueve el foco acá al cambiar de página (para que un lector de
   pantalla siga en el contenido nuevo). Es foco programático sobre un
   contenedor, no un control: dibujar el anillo alrededor de toda la página
   confunde en vez de ayudar — el cambio ya se anuncia en la región viva. */
.page-content:focus, .page-content:focus-visible { outline: none; }
.page-header { margin-bottom: var(--sp-6); }
.page-header h1 {
  font-size: var(--fs-2xl); font-weight: 800; color: var(--ink-900);
  letter-spacing: var(--tracking-display); line-height: var(--lh-tight);
}
.page-header h1:focus { outline: none; }
.page-sub { font-size: var(--fs-md); color: var(--ink-500); margin-top: var(--sp-1); max-width: 62ch; }
.page-header-fila { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }

/* ───────────────────────────────── KPI ──────────────────────────────────── */
.kpi {
  display: flex; align-items: center; gap: var(--sp-4);
  background: var(--surface); border: 1px solid var(--line-100);
  border-radius: var(--r-md); padding: var(--sp-4) var(--sp-5);
}
.kpi-icono {
  width: 42px; height: 42px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm); font-size: var(--fs-xl);
  background: var(--info-bg);
}
.kpi-icono.es-logro   { background: var(--logro-bg); }
.kpi-icono.es-evento  { background: var(--evento-bg); }
.kpi-icono.es-urgente { background: var(--urgente-bg); }
.kpi-val { font-size: var(--fs-3xl); font-weight: 800; line-height: 1; letter-spacing: var(--tracking-display); }
.kpi-label {
  margin-top: var(--sp-1);
  font-size: var(--fs-eyebrow); font-weight: 700; color: var(--ink-300);
  text-transform: uppercase; letter-spacing: var(--tracking-eyebrow);
}

/* ─────────────────────────────── AVATAR ─────────────────────────────────── */
.avatar {
  width: 36px; height: 36px; flex-shrink: 0; border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-600); color: #fff;
  font-size: var(--fs-sm); font-weight: 700; letter-spacing: .02em;
}
.avatar-sm { width: 28px; height: 28px; font-size: var(--fs-xs); }
.avatar-lg { width: 56px; height: 56px; font-size: var(--fs-xl); border-radius: var(--r-md); }

/* ─────────────────────────────── TABLA ──────────────────────────────────── */
.tabla-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; }
th {
  padding: var(--sp-3) var(--sp-4); text-align: left;
  background: var(--canvas-soft); color: var(--ink-500);
  font-size: var(--fs-eyebrow); font-weight: 700;
  text-transform: uppercase; letter-spacing: var(--tracking-eyebrow);
  border-bottom: 1px solid var(--line-100); white-space: nowrap;
}
td { padding: var(--sp-3) var(--sp-4); font-size: var(--fs-sm); border-bottom: 1px solid var(--line-100); }
tbody tr { transition: background-color var(--dur-1) var(--ease-out); }
tbody tr:hover td { background: var(--canvas-soft); }
.celda-acciones { display: flex; gap: var(--sp-1); }

/* Columna angosta del checkbox de selección (tabla) — ver .fila-check en
 * usuarios.js. Ancho fijo para que no empuje el resto de columnas. */
.celda-check { width: 40px; }

/* Vista de tarjetas: reemplaza a la tabla debajo de 860px (ver responsive). */
.lista-tarjetas { display: none; flex-direction: column; gap: var(--sp-2); }
.tarjeta-registro {
  display: flex; align-items: center; gap: var(--sp-3);
  background: var(--surface); border: 1px solid var(--line-100);
  border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
}
.tarjeta-registro-datos { min-width: 0; flex: 1; }

/* Barra flotante de acciones en masa (Usuarios, 2026-09-10) — aparece al pie
 * de la pantalla apenas hay 1+ seleccionados. Mismo z-index que el contenedor
 * de toasts para quedar por encima del contenido normal, pero por debajo del
 * overlay de un modal (500) si se abre uno desde acá. */
.barra-masiva {
  position: fixed; left: var(--sp-5); right: var(--sp-5); bottom: var(--sp-5); z-index: 400;
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap;
  background: var(--ink-900); color: #fff;
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md); box-shadow: var(--elev-2);
}
.barra-masiva .btn-outline { background: transparent; color: #fff; border-color: rgba(255,255,255,.3); }
.barra-masiva .btn-outline:hover:not(:disabled) { background: rgba(255,255,255,.12); border-color: rgba(255,255,255,.5); }
.barra-masiva .btn-ghost { color: rgba(255,255,255,.75); }
.barra-masiva .btn-ghost:hover:not(:disabled) { background: rgba(255,255,255,.12); color: #fff; }

/* ──────────────────── BARRA DE HERRAMIENTAS DE UN LISTADO ───────────────── */
.toolbar {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}
.campo-busqueda { position: relative; flex: 1; min-width: 220px; }
.campo-busqueda .form-control { padding-left: var(--sp-8); }
.campo-busqueda::before {
  content: '🔍'; position: absolute; left: var(--sp-3); top: 50%;
  transform: translateY(-50%); font-size: var(--fs-sm); opacity: .5; pointer-events: none;
}
.toolbar-resultado { font-size: var(--fs-sm); color: var(--ink-500); margin-left: auto; }
/* .form-control declara width:100%; en la toolbar los selects van al ancho de su
   contenido. La utilidad sola no gana porque este archivo se carga después. */
.toolbar .form-control.w-auto { width: auto; min-width: 150px; }

/* ────────────────────── DISCLOSURE (expander) ────────────────────────────
 * Patrón WAI-ARIA "disclosure" (botón + panel controlado por aria-expanded/
 * aria-controls) para contenido largo que no hace falta ver siempre — ej. el
 * detalle de venta por tienda de un superuser, que antes salía como una tabla
 * de 40 filas siempre desplegada en el Inicio.
 *
 * La animación de alto usa grid-template-rows 0fr→1fr en vez de max-height a
 * ciegas: anima a la altura REAL del contenido sin adivinar un número, y con
 * el contenido colapsado a 0fr no ocupa espacio ni reserva scroll. Ver
 * core/ui.js::alternarDisclosure.
 */
.disclosure-toggle {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  padding: var(--sp-2) 0; margin: calc(var(--sp-2) * -1) 0;
  background: none; border: none; cursor: pointer;
  font-family: var(--font); font-size: var(--fs-md); font-weight: 600; color: var(--ink-700);
  text-align: left;
}
.disclosure-toggle:hover { color: var(--ink-900); }
.disclosure-chevron {
  flex-shrink: 0; font-size: .7em; color: var(--ink-300);
  transition: transform var(--dur-2) var(--ease-out);
}
.disclosure[data-abierto="true"] .disclosure-chevron { transform: rotate(180deg); }
.disclosure-panel {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-3) var(--ease-inout);
}
.disclosure[data-abierto="true"] .disclosure-panel { grid-template-rows: 1fr; }
.disclosure-panel-inner { overflow: hidden; min-height: 0; }
.disclosure-panel-body { padding-top: var(--sp-4); }

.paginacion {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
  margin-top: var(--sp-4); padding-top: var(--sp-4); border-top: 1px solid var(--line-100);
}
.paginacion-info { font-size: var(--fs-sm); color: var(--ink-500); }

/* ────────────────────────────── COMUNICADO ──────────────────────────────── */
.comunicado {
  display: block; width: 100%; text-align: left;
  background: var(--surface); border: 1px solid var(--line-100);
  border-radius: var(--r-md); padding: var(--sp-4) var(--sp-5);
  margin-bottom: var(--sp-3);
  font-family: var(--font); color: inherit; cursor: pointer;
}
.comunicado:hover { background: var(--canvas-soft); }
/* El bloque es un <button>: sus hijos son <span> y necesitan volverse bloque
   para apilarse (un span dentro de un button sigue siendo inline). */
.comunicado > span { display: block; }
.comunicado-meta { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-2); }
.comunicado-titulo { font-size: var(--fs-lg); font-weight: 700; color: var(--ink-900); line-height: 1.3; }
.comunicado-cuerpo { margin-top: var(--sp-1); font-size: var(--fs-md); color: var(--ink-700); }
.comunicado-texto { white-space: pre-wrap; line-height: var(--lh-base); }
.comunicado-pie {
  display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3);
  font-size: var(--fs-xs); color: var(--ink-300);
}
/* La imagen es un AFICHE: se muestra completa y a su proporción real, nunca
   recortada. Antes era object-fit:cover con 160px de alto y cortaba el texto del
   afiche justo por la mitad, que es lo que la gente necesitaba leer. Se limita
   por ALTO (no por ancho) para que un afiche vertical no ocupe la pantalla
   entera ni deje una caja vacía al costado. */
.comunicado-imagen {
  display: block; width: auto; max-width: 100%; max-height: 240px;
  border-radius: var(--r-sm); margin-bottom: var(--sp-3);
}
.modal .comunicado-imagen { max-height: 420px; margin-inline: auto; }
.comunicado-imagen-mini {
  width: 56px; height: 56px; flex-shrink: 0; object-fit: cover;
  border-radius: var(--r-sm); background: var(--canvas);
}
/* Ítem compacto del inicio */
.comunicado-fila {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%;
  padding: var(--sp-3); border: none; border-radius: var(--r-sm);
  background: transparent; font-family: var(--font); color: inherit;
  text-align: left; cursor: pointer;
}
.comunicado-fila:hover { background: var(--canvas-soft); }
.comunicado-destacado {
  display: block; width: 100%; padding: 0 0 var(--sp-4);
  margin-bottom: var(--sp-3); border: none; border-bottom: 1px solid var(--line-100);
  background: transparent; font-family: var(--font); color: inherit;
  text-align: left; cursor: pointer;
}
.comunicado-destacado > span { display: block; }
.comunicado-destacado .comunicado-meta { display: flex; }
.comunicado-destacado img {
  display: block; width: 100%; max-width: 320px; margin: 0 auto var(--sp-3);
  border-radius: var(--r-sm);
  transition: transform var(--dur-2) var(--ease-out);
}
.comunicado-destacado:hover img { transform: scale(1.015); }

/* ─────────────────────────────── ENCUESTA ───────────────────────────────── */
.encuesta-barra { height: 6px; background: var(--line-100); border-radius: var(--r-pill); overflow: hidden; }
.encuesta-barra-fill {
  height: 100%; background: var(--brand-600); border-radius: var(--r-pill);
  transition: width var(--dur-3) var(--ease-out);
}
.encuesta-pct { font-size: var(--fs-xl); font-weight: 800; color: var(--brand-600); letter-spacing: var(--tracking-display); }
.encuesta-opcion {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%;
  padding: 11px var(--sp-4); margin-bottom: var(--sp-2);
  background: var(--surface); border: 1px solid var(--line-200); border-radius: var(--r-md);
  font-family: var(--font); font-size: var(--fs-md); color: var(--ink-700);
  text-align: left; cursor: pointer;
  transition: border-color var(--dur-1) var(--ease-out), background-color var(--dur-1) var(--ease-out);
}
.encuesta-opcion::before {
  content: ''; width: 16px; height: 16px; flex-shrink: 0; border-radius: 50%;
  border: 2px solid var(--line-200);
  transition: border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-spring);
}
.encuesta-opcion:hover { border-color: var(--brand-300); background: var(--brand-50); }
.encuesta-opcion[aria-checked="true"] {
  border-color: var(--brand-600); background: var(--brand-50);
  color: var(--brand-700); font-weight: 600;
}
.encuesta-opcion[aria-checked="true"]::before {
  border-color: var(--brand-600); box-shadow: inset 0 0 0 3px var(--brand-600);
}
.pregunta-builder {
  border: 1px solid var(--line-200); border-radius: var(--r-md);
  padding: var(--sp-4); margin-bottom: var(--sp-3);
}

/* ────────────────────────────── HERRAMIENTA ─────────────────────────────── */
.herramienta {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line-100);
  border-radius: var(--r-md); overflow: hidden;
  transition: border-color var(--dur-1) var(--ease-out);
}
.herramienta:hover { border-color: var(--brand-300); }
/* --marca es el ÚNICO valor que llega desde la base de datos, y pasa por
   colorSeguro() antes de tocar el CSS (ver docs/FRONTEND.md §8). */
.herramienta-marca {
  height: 72px; display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--marca, var(--brand-600)) 14%, white);
  border-bottom: 1px solid var(--line-100);
}
.herramienta-icono { font-size: 1.9rem; line-height: 1; }
.herramienta-cuerpo { padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); flex: 1; }
.herramienta-titulo { font-size: var(--fs-md); font-weight: 700; color: var(--ink-900); }
.herramienta-desc { font-size: var(--fs-sm); color: var(--ink-500); flex: 1; }
.herramienta-acciones { margin-top: var(--sp-1); }

/* Material (PDF/link) de una herramienta 'integrada', dentro del modal
   abierto por abrirMaterial() en herramientas.js — ver 2026-09-09. */
.lista-material { display: flex; flex-direction: column; gap: var(--sp-2); }
.material-item {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3); border: 1px solid var(--line-100); border-radius: var(--r-sm);
}
.material-icono { font-size: 1.3rem; line-height: 1; flex-shrink: 0; }
.material-titulo { flex: 1; min-width: 0; font-weight: 600; color: var(--ink-900); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Carpeta por mes (2026-09-09) — el mismo .disclosure genérico (ver
   core/ui.js), solo con look de carpeta: borde propio y el título ocupando el
   espacio libre para empujar el contador y la flecha a la derecha. */
.material-carpeta { border: 1px solid var(--line-100); border-radius: var(--r-sm); padding: 0 var(--sp-3); }
.material-carpeta .disclosure-toggle { padding: var(--sp-3) 0; margin: 0; }
.material-carpeta-icono { font-size: 1.1rem; line-height: 1; flex-shrink: 0; }
.material-carpeta-etiqueta { flex: 1; min-width: 0; text-align: left; }
.material-carpeta .disclosure-panel-body { padding: 0 0 var(--sp-3); }
.material-carpeta .lista-material { padding-left: calc(1.1rem + var(--sp-2)); }

/* ──────────────────────────────── PERFIL ────────────────────────────────── */
.perfil-hero {
  display: flex; align-items: center; gap: var(--sp-5); flex-wrap: wrap;
  padding: var(--sp-6);
  background: linear-gradient(120deg, var(--brand-900) 0%, var(--brand-600) 100%);
  border-radius: var(--r-md); color: #fff; margin-bottom: var(--sp-5);
}
.perfil-hero .avatar-lg { background: rgba(255,255,255,.22); }
.perfil-hero .nombre { font-size: var(--fs-2xl); font-weight: 800; letter-spacing: var(--tracking-display); }
.perfil-hero .cargo  { font-size: var(--fs-md); opacity: .85; }
.dato-fila {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--line-100);
}
.dato-fila:last-child { border-bottom: none; }
.dato-label { font-size: var(--fs-sm); color: var(--ink-500); }
.dato-valor { font-size: var(--fs-md); font-weight: 600; color: var(--ink-900); }

/* Punto de estado (activo / desactivado) */
/* Punto de estado — reemplaza al acento de color al borde para marcar "esto es
 * nuevo/distinto" sin usar un borde (ver docs/FRONTEND.md §1). */
.status-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.status-dot.online   { background: var(--logro); }
.status-dot.offline  { background: var(--line-200); }
.status-dot.info     { background: var(--info); }
.status-dot.urgente  { background: var(--urgente); }

/* ──────────────────────────────── MODAL ─────────────────────────────────── */
.modal-overlay {
  position: fixed; inset: 0; z-index: 500;
  display: flex; align-items: center; justify-content: center; padding: var(--sp-5);
  background: rgba(19, 26, 43, .48); backdrop-filter: blur(3px);
  animation: aparecer var(--dur-2) var(--ease-out);
}
.modal {
  width: 100%; max-width: 560px; max-height: 88vh; overflow-y: auto;
  background: var(--surface); border-radius: var(--r-lg);
  box-shadow: var(--elev-2); padding: var(--sp-6);
  animation: modalEntra var(--dur-2) var(--ease-out);
  overscroll-behavior: contain;   /* el scroll no se contagia a la página de atrás */
}
.modal-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); margin-bottom: var(--sp-5);
}
.modal-title { font-size: var(--fs-xl); font-weight: 800; color: var(--ink-900); letter-spacing: var(--tracking-display); }
.modal-close {
  width: 34px; height: 34px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--canvas); border: none; border-radius: var(--r-sm);
  color: var(--ink-500); cursor: pointer;
  transition: background-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
}
.modal-close:hover { background: var(--line-100); color: var(--ink-900); }
/* Con el modal abierto, el fondo no scrollea (si no, en una lista larga la
   página de atrás se mueve bajo el diálogo). Ver core/ui.js. */
body.modal-abierto { overflow: hidden; }

/* ──────────────────────────────── TOAST ─────────────────────────────────── */
.toast-container {
  position: fixed; bottom: var(--sp-5); right: var(--sp-5); z-index: 999;
  display: flex; flex-direction: column; gap: var(--sp-2);
  max-width: min(380px, calc(100vw - var(--sp-8)));
}
.toast {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md);
  background: var(--ink-900); color: #fff;
  font-size: var(--fs-md); box-shadow: var(--elev-2);
  animation: toastEntra var(--dur-2) var(--ease-out);
}
.toast.success { background: var(--logro); }
.toast.error   { background: var(--urgente); }
.toast.aviso   { background: var(--evento); }
.toast.saliendo { animation: toastSale var(--dur-2) var(--ease-inout) forwards; }
.toast-texto { flex: 1; }
.toast-cerrar {
  flex-shrink: 0; width: 24px; height: 24px; border: none; border-radius: var(--r-sm);
  background: rgba(255,255,255,.16); color: #fff; cursor: pointer; font-size: var(--fs-xs);
  transition: background-color var(--dur-1) var(--ease-out);
}
.toast-cerrar:hover { background: rgba(255,255,255,.3); }

/* ──────────────────────── ESTADOS: vacío / error / carga ────────────────── */
.estado-vacio, .estado-error {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; padding: var(--sp-8) var(--sp-5); gap: var(--sp-2);
}
.estado-vacio .icono, .estado-error .icono { font-size: 2.4rem; }
.estado-vacio h3, .estado-error h3 { font-size: var(--fs-lg); font-weight: 700; color: var(--ink-900); }
.estado-vacio p, .estado-error p { font-size: var(--fs-md); color: var(--ink-500); max-width: 46ch; }
.estado-vacio .btn, .estado-error .btn { margin-top: var(--sp-2); }

.skeleton {
  background: linear-gradient(90deg, var(--line-100) 25%, var(--canvas-soft) 37%, var(--line-100) 63%);
  background-size: 400% 100%;
  animation: skeletonOnda 1.4s var(--ease-inout) infinite;
  border-radius: var(--r-sm);
}
.skeleton-linea { height: 12px; margin-bottom: var(--sp-2); }
.skeleton-bloque { height: 96px; border-radius: var(--r-md); margin-bottom: var(--sp-3); }
.spinner {
  width: 16px; height: 16px; flex-shrink: 0; border-radius: 50%;
  border: 2px solid rgba(255,255,255,.35); border-top-color: #fff;
  animation: girar .7s linear infinite; display: inline-block;
}
.btn-outline .spinner, .btn-ghost .spinner { border-color: var(--line-200); border-top-color: var(--brand-600); }

/* ────────────────────────────── ANIMACIONES ─────────────────────────────── */
@keyframes entrar     { from { opacity: 0; transform: translateY(8px); }  to { opacity: 1; transform: none; } }
@keyframes aparecer   { from { opacity: 0; } to { opacity: 1; } }
@keyframes modalEntra { from { opacity: 0; transform: translateY(12px) scale(.985); } to { opacity: 1; transform: none; } }
@keyframes toastEntra { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: none; } }
@keyframes toastSale  { to { opacity: 0; transform: translateX(24px); } }
@keyframes skeletonOnda { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@keyframes girar { to { transform: rotate(360deg); } }

/* Entrada de página ESCALONADA, 100% CSS (sin una línea de JS): los bloques
   principales aparecen en cascada de 45ms. Tope de 6 pasos — más que eso se
   siente lento en vez de fluido. */
.page-enter :is(.page-header, .bloque, .kpi, .comunicado, .herramienta, .toolbar, .estado-vacio, .estado-error, .perfil-hero) {
  animation: entrar var(--dur-3) var(--ease-out) both;
}
.page-enter :is(.bloque, .kpi, .comunicado, .herramienta):nth-child(2) { animation-delay: 45ms; }
.page-enter :is(.bloque, .kpi, .comunicado, .herramienta):nth-child(3) { animation-delay: 90ms; }
.page-enter :is(.bloque, .kpi, .comunicado, .herramienta):nth-child(4) { animation-delay: 135ms; }
.page-enter :is(.bloque, .kpi, .comunicado, .herramienta):nth-child(5) { animation-delay: 180ms; }
.page-enter :is(.bloque, .kpi, .comunicado, .herramienta):nth-child(n+6) { animation-delay: 225ms; }

/* ═════════════════════════════ RESPONSIVE ═══════════════════════════════════
   Mobile-first: lo de arriba ya es la versión de celular en lo que importa.
   Acá se agrega lo de escritorio y se corrigen los casos táctiles. */

@media (max-width: 860px) {
  .sidebar { transform: translateX(-100%); box-shadow: var(--elev-2); }
  .sidebar.abierto { transform: translateX(0); }
  .main-area { margin-left: 0; }
  .sidebar-toggle { display: inline-flex; }
  #sidebarColapsarBtn { display: none; }
  .page-content { padding: var(--sp-4); }
  .topbar { padding: 0 var(--sp-4); }
  /* Objetivo táctil cómodo (WCAG 2.5.8) */
  .btn-icon { min-width: 44px; min-height: 44px; }
  .btn { min-height: 44px; }
  .btn-sm { min-height: 36px; }
  /* La tabla de 194 filas era ilegible en celular (scroll horizontal dentro de
     una página de 33.000px): debajo de este ancho se muestra la lista de
     tarjetas y se esconde la tabla. */
  .tabla-wrap { display: none; }
  .lista-tarjetas { display: flex; }
  /* Las acciones bajan a su propia fila: con tres botones táctiles de 44px al
     costado, al nombre le quedaban ~130px y se cortaba en "Administra…". */
  .tarjeta-registro { flex-wrap: wrap; }
  .tarjeta-registro .celda-acciones {
    width: 100%; justify-content: flex-end;
    padding-top: var(--sp-2); border-top: 1px solid var(--line-100);
  }
  .modal { padding: var(--sp-5); max-height: 92vh; }
  .toast-container { left: var(--sp-4); right: var(--sp-4); bottom: var(--sp-4); max-width: none; }
  .barra-masiva { left: var(--sp-4); right: var(--sp-4); bottom: var(--sp-4); justify-content: flex-start; }
  .perfil-hero { padding: var(--sp-5); }
}

@media (min-width: 1180px) {
  .page-content { padding: var(--sp-7); }
}
