/* ============================================================
   PLATAFORMA RED PESAJE — Sistema de diseño institucional
   Dirección de Vialidad — reinterpretación moderna, no oficial.
   ============================================================ */

:root {
  /* Paleta */
  --color-primary: #005AA9;
  --color-primary-dark: #00458a;
  --color-secondary: #0A74C4;
  --color-success: #2E7D32;
  --color-warning: #F9A825;
  /* #F9A825 solo es apto como fondo (con texto oscuro encima) o borde decorativo:
     contra blanco da 1.97:1, por debajo del mínimo WCAG 1.4.11 (3:1) para objetos
     gráficos (arcos, líneas de gráficos, íconos). Para esos casos usar esta variante. */
  --color-warning-graphic: #C77D00;
  --color-danger: #C62828;
  --color-bg: #FFFFFF;
  --color-bg-alt: #F5F7FA;
  --color-text: #333333;
  /* #666666 pasaba AA (4.5:1) pero no AAA (7:1) contra blanco; #595959 sí, y es
     visualmente casi idéntico. Ver "Auditoría WCAG AAA" más abajo. */
  --color-text-secondary: #595959;
  --color-border: #DDDDDD;
  --zebra-stripe: rgba(0, 0, 0, 0.02);

  --color-success-bg: #E8F5E9;
  --color-warning-bg: #FFF8E1;
  --color-danger-bg: #FDECEA;
  --color-info-bg: #E8F1FB;
  /* Acento "gris pizarra" para distinguir datos de conteo manual de datos de pesajes
     (selector de dominio de Estadísticas) sin sumar un cuarto color a la paleta
     institucional — ya se usaba este mismo tono en los gráficos de comparativa. */
  --color-manual: #5a6b78;
  --color-manual-bg: #eef1f3;
  --color-manual-text: #41505c;

  /* ------------------------------------------------------------
     Auditoría WCAG AAA (1.4.6, contraste de texto 7:1): las variables
     de arriba (--color-primary, --color-danger, etc.) siguen siendo la
     paleta institucional real y se usan tal cual para RELLENOS (fondos
     de botón, bordes, gráficos) — ahí AA (que ya cumplían) es el
     criterio correcto, porque forzar 7:1 en un fondo sólido implicaría
     cambiar la identidad visual de la marca. Estas variantes "-text"
     son las mismas familias de color, afinadas solo para cuando se
     usan como TEXTO/ícono sobre un fondo claro u oscuro, que es donde
     aplica el 7:1 de verdad. Se calculó cada una contra el fondo más
     exigente en que aparece como texto (su propio tono "-bg" claro),
     no solo contra blanco puro. */
  --color-primary-text: #005197;
  --color-secondary-text: #07538c;
  --color-success-text: #225d25;
  --color-warning-text: #784b00;
  --color-danger-text: #9b1f1f;

  --font-sans: 'Inter', 'Open Sans', 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  --fs-h1: 40px;
  --fs-h2: 32px;
  --fs-h3: 24px;
  --fs-h4: 20px;
  --fs-body: 16px;
  --fs-small: 14px;

  --radius-sm: 6px;
  --radius-md: 10px;
  /* Sombras con un tinte azulado-neutro (en vez de negro puro) y dos capas — una
     ajustada al borde, otra más difusa — para dar una sensación de profundidad real
     en vez del "borde gris + sombra casi invisible" que se ve chato en pantalla. */
  --shadow-card: 0 1px 2px rgba(16, 24, 40, 0.04), 0 4px 10px rgba(16, 24, 40, 0.055);
  --shadow-card-hover: 0 4px 10px rgba(16, 24, 40, 0.07), 0 14px 28px rgba(16, 24, 40, 0.09);
  --shadow-modal: 0 4px 12px rgba(16, 24, 40, 0.10), 0 20px 44px rgba(16, 24, 40, 0.22);

  --sidebar-width: 264px;
  --sidebar-width-collapsed: 72px;
  --header-height: 64px;
  --content-max-width: 1400px;

  /* Curva con una leve desaceleración al final (en vez de "ease" lineal-ish): las
     transiciones de hover/foco se sienten más suaves y menos abruptas. */
  --transition-fast: 150ms cubic-bezier(.4, 0, .2, 1);
  --transition-base: 220ms cubic-bezier(.4, 0, .2, 1);
}

:root[data-theme='dark'] {
  --color-bg: #10161d;
  --color-bg-alt: #161e27;
  --color-text: #e7ebf0;
  --color-text-secondary: #a7b1bc;
  --color-border: #2a3542;
  --color-success-bg: #16281a;
  --color-warning-bg: #2b2210;
  --color-danger-bg: #2b1414;
  --color-info-bg: #10202f;
  --color-manual: #9aa6b1;
  --color-manual-bg: #1c242c;
  --color-manual-text: #c2cad2;
  /* Las variantes "-text" del modo claro (pensadas para fondos claros) caen a apenas
     2-3:1 sobre el fondo oscuro — una falla real de accesibilidad, no solo un matiz de
     AAA. Se reemplazan por versiones más claras, recalculadas contra sus propios fondos
     oscuros ("-bg" oscuro), otra vez a 7:1. */
  --color-primary-text: #40a6ff;
  --color-secondary-text: #52b0f6;
  --color-success-text: #5dc463;
  --color-warning-text: #f49900;
  --color-danger-text: #e88b8b;
  /* Un aclarado (blanco translúcido) en vez del oscurecido del modo claro: sobre un
     fondo ya oscuro, seguir oscureciendo apenas se nota. */
  --zebra-stripe: rgba(255, 255, 255, 0.03);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --color-bg: #10161d;
    --color-bg-alt: #161e27;
    --color-text: #e7ebf0;
    --color-text-secondary: #a7b1bc;
    --color-border: #2a3542;
    --color-success-bg: #16281a;
    --color-warning-bg: #2b2210;
    --color-danger-bg: #2b1414;
    --color-info-bg: #10202f;
    --color-manual: #9aa6b1;
    --color-manual-bg: #1c242c;
    --color-manual-text: #c2cad2;
    --color-primary-text: #40a6ff;
    --color-secondary-text: #52b0f6;
    --color-success-text: #5dc463;
    --color-warning-text: #f49900;
    --color-danger-text: #e88b8b;
    --zebra-stripe: rgba(255, 255, 255, 0.03);
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--color-bg-alt);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { margin: 0 0 8px; font-weight: 700; line-height: 1.25; letter-spacing: -0.015em; }
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }
h4 { font-size: var(--fs-h4); }
p { margin: 0 0 8px; }
small, .text-small { font-size: var(--fs-small); color: var(--color-text-secondary); }
a { color: var(--color-secondary-text); }

button, input, select, textarea { font-family: inherit; font-size: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--color-secondary);
  outline-offset: 2px;
}

::selection { background: var(--color-secondary); color: #fff; }

/* Scrollbars propias (discretas, del color del sistema) en vez de las del navegador:
   se notan sobre todo en los paneles internos con scroll (ranking, sidebar del mapa,
   dropdowns, modales), donde una barra gris genérica del SO desentona con el resto. */
html { scrollbar-width: thin; scrollbar-color: var(--color-border) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 999px; border: 2px solid var(--color-bg); }
::-webkit-scrollbar-thumb:hover { background: var(--color-text-secondary); }

.hidden { display: none !important; }

.skip-link {
  position: absolute; left: 8px; top: -48px;
  background: var(--color-primary); color: #fff;
  padding: 10px 16px; border-radius: var(--radius-sm);
  z-index: 1000; transition: top var(--transition-fast);
  font-weight: 600; text-decoration: none;
}
.skip-link:focus { top: 8px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ============================================================
   LOGIN
   ============================================================ */
.login-screen {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    radial-gradient(680px circle at 15% 10%, rgba(255, 255, 255, 0.10), transparent 60%),
    radial-gradient(900px circle at 88% 92%, rgba(255, 255, 255, 0.07), transparent 55%),
    linear-gradient(160deg, var(--color-primary) 0%, var(--color-primary-dark) 100%);
  padding: 24px;
}

.login-card {
  background: var(--color-bg);
  border-radius: var(--radius-md);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: var(--shadow-modal);
  width: 100%;
  max-width: 400px;
  padding: 40px 36px;
}

.login-brand {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 24px;
}

.login-brand .brand-mark {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  display: block;
  object-fit: contain;
  border-radius: var(--radius-sm);
}

.login-brand .brand-text strong {
  display: block;
  font-size: 16px;
}
.login-brand .brand-text span {
  display: block;
  font-size: var(--fs-small);
  color: var(--color-text-secondary);
}

.login-error {
  background: var(--color-danger-bg);
  color: var(--color-danger-text);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font-size: var(--fs-small);
  margin-bottom: 16px;
}

/* ============================================================
   LAYOUT: HEADER + SIDEBAR
   ============================================================ */
.app-shell {
  display: flex;
  min-height: 100vh;
}

.app-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: var(--header-height);
  background: var(--color-bg);
  border-bottom: 1px solid var(--color-border);
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.03);
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 20px;
  z-index: 100;
}

.offline-banner {
  position: fixed;
  top: var(--header-height);
  left: 0; right: 0;
  z-index: 90;
  background: var(--color-warning-bg);
  color: #8a6100;
  border-bottom: 1px solid var(--color-warning-graphic);
  padding: 8px 20px;
  font-size: 13px;
  text-align: center;
}
.offline-banner .badge-count {
  position: static;
  display: inline-flex;
  margin-left: 6px;
  background: var(--color-warning-graphic);
}

.app-header .brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: var(--sidebar-width);
  font-weight: 700;
}
.app-header .brand .brand-mark { width: 30px; height: 30px; display: block; object-fit: contain; border-radius: var(--radius-sm); }

.header-search {
  flex: 1;
  max-width: 420px;
  position: relative;
}
.header-search input {
  width: 100%;
  padding: 8px 12px 8px 36px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg-alt);
}
.header-search svg {
  position: absolute;
  left: 10px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px;
  color: var(--color-text-secondary);
}
.header-search-kbd {
  position: absolute;
  right: 10px; top: 50%; transform: translateY(-50%);
  font-family: inherit; font-size: 11px; font-weight: 600;
  color: var(--color-text-secondary);
  background: var(--color-bg); border: 1px solid var(--color-border);
  border-radius: 4px; padding: 2px 6px;
  pointer-events: none;
}
.header-search input:focus ~ .header-search-kbd { display: none; }

.global-search-results {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0;
  max-height: 60vh; overflow-y: auto;
  background: var(--color-bg); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-modal);
  z-index: 200; padding: 6px;
}
.gs-group-title {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  color: var(--color-text-secondary); padding: 8px 10px 4px;
}
.gs-item {
  display: flex; flex-direction: column; gap: 1px;
  width: 100%; text-align: left; padding: 8px 10px; border-radius: var(--radius-sm);
  background: none; border: none; cursor: pointer; font: inherit; color: var(--color-text);
}
.gs-item:hover, .gs-item.active { background: var(--color-bg-alt); }
.gs-item-sub { font-size: 12px; color: var(--color-text-secondary); }
.gs-empty { padding: 16px 10px; text-align: center; color: var(--color-text-secondary); font-size: 13px; }
.gs-ia-item { border: 1px dashed var(--color-border); margin-bottom: 4px; }
.gs-ia-banner {
  padding: 10px; margin-bottom: 6px; border-radius: var(--radius-sm);
  background: var(--color-bg-alt); font-size: 13px; line-height: 1.5;
}
.gs-ia-banner-off { color: var(--color-text-secondary); font-style: italic; }

.header-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

.icon-btn {
  position: relative;
  width: 38px; height: 38px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--color-text);
  transition: background var(--transition-fast);
}
.icon-btn:hover { background: var(--color-bg-alt); }

.badge-count {
  position: absolute;
  top: 2px; right: 2px;
  background: var(--color-danger);
  color: #fff;
  font-size: 10px;
  min-width: 16px; height: 16px;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  padding: 0 3px;
}

.user-menu {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--transition-fast);
}
.user-menu:hover { background: var(--color-bg-alt); }
.user-avatar {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--color-primary);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 13px;
  flex-shrink: 0;
}
.user-menu .user-info { line-height: 1.2; text-align: left; }
.user-menu .user-info strong { display: block; font-size: 13px; }
.user-menu .user-info span { display: block; font-size: 12px; color: var(--color-text-secondary); }

.app-sidebar {
  position: fixed;
  top: var(--header-height); bottom: 0; left: 0;
  width: var(--sidebar-width);
  background: var(--color-bg);
  border-right: 1px solid var(--color-border);
  overflow-y: auto;
  transition: width var(--transition-base);
  z-index: 90;
}
.app-sidebar.collapsed { width: var(--sidebar-width-collapsed); }
.app-sidebar.collapsed .nav-label,
.app-sidebar.collapsed .nav-section-title { display: none; }

.nav-section-title {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--color-text-secondary);
  padding: 16px 26px 6px;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 2px 12px;
  padding: 10px 14px;
  color: var(--color-text);
  text-decoration: none;
  cursor: pointer;
  border-radius: var(--radius-sm);
  font-size: 14px;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.nav-item svg { width: 20px; height: 20px; flex-shrink: 0; }
.nav-item:hover { background: var(--color-bg-alt); }
.nav-item.active {
  background: var(--color-info-bg);
  color: var(--color-primary-text);
  font-weight: 600;
}
/* En modo colapsado los ítems se acercan al ancho angosto de la barra: el margen
   lateral fijo de arriba (12px) les dejaría muy poco aire, así que se reduce. */
.app-sidebar.collapsed .nav-item { margin: 2px 8px; padding: 10px; justify-content: center; }

.sidebar-toggle {
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  border-radius: 50%;
  cursor: pointer;
}

.app-main {
  margin-left: var(--sidebar-width);
  margin-top: var(--header-height);
  padding: 28px 32px 60px;
  width: calc(100% - var(--sidebar-width));
  min-width: 0;
  transition: margin-left var(--transition-base), width var(--transition-base);
}
.app-sidebar.collapsed ~ .app-main { margin-left: var(--sidebar-width-collapsed); width: calc(100% - var(--sidebar-width-collapsed)); }

.content-max {
  max-width: var(--content-max-width);
  margin: 0 auto;
}

.page-header {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.page-header h1 { font-size: 28px; margin-bottom: 4px; }
.page-header .page-subtitle { color: var(--color-text-secondary); font-size: var(--fs-small); }

@media (max-width: 640px) {
  /* Varios módulos arman los botones/filtros del encabezado como un
     "flex gap-8" con selects de ancho mínimo fijo (inline style, p.ej.
     min-width:220px) pensado para desktop; en una pantalla angosta esa
     fila no cabía y empujaba toda la página a hacer scroll horizontal
     en vez de acomodarse. Acá se le permite envolver y encogerse. */
  .page-header > .flex { flex-wrap: wrap; width: 100%; }
  .page-header .field { min-width: 0 !important; }
  .page-header > .flex > .btn,
  .page-header > .flex > .field { flex: 1 1 160px; }

  /* En todos los módulos, la acción principal (+ Nuevo ticket, + Nueva unidad...) es
     btn-primary y siempre el ÚLTIMO botón del grupo en el HTML (Exportar/Imprimir/etc.
     van antes, pensados para un mouse en desktop). Al apilarse en columna en celular,
     eso la dejaba al final, obligando a pasar de largo 3-4 botones secundarios y los
     filtros antes de llegar a lo que la persona vino a hacer. column-reverse invierte
     el orden visual (no el del DOM ni el foco de teclado) para que la acción principal
     quede arriba de todo, sin tener que tocar cada módulo uno por uno. */
  .page-header > .flex {
    flex-direction: column-reverse;
    /* flex-basis:160px de la regla anterior era para repartir ancho en fila; en
       columna ese mismo valor se vuelve una ALTURA mínima y cada botón queda
       gigante. En columna basta con que ocupen su alto natural. */
    align-items: stretch;
  }
  .page-header > .flex > .btn,
  .page-header > .flex > .field { flex: 0 0 auto; }
}

.breadcrumb {
  display: flex; align-items: center; gap: 6px;
  font-size: 13px;
  color: var(--color-text-secondary);
  margin-bottom: 6px;
}
.breadcrumb a { color: var(--color-text-secondary); text-decoration: none; }
.breadcrumb .current { color: var(--color-text); font-weight: 600; }

.app-footer {
  margin-left: var(--sidebar-width);
  padding: 20px 32px;
  border-top: 1px solid var(--color-border);
  color: var(--color-text-secondary);
  font-size: 12px;
  transition: margin-left var(--transition-base);
}
.app-sidebar.collapsed ~ .app-footer { margin-left: var(--sidebar-width-collapsed); }

.sidebar-backdrop {
  display: none;
  position: fixed;
  top: var(--header-height); right: 0; bottom: 0; left: 0;
  background: rgba(15, 23, 32, 0.5);
  z-index: 85; /* debajo del sidebar (90), encima del contenido */
}
.sidebar-backdrop.visible { display: block; }

/* Botón de búsqueda para mobile: en desktop el buscador ya está siempre visible
   en el header, así que este botón sobra ahí. */
.mobile-search-toggle { display: none; }

@media (max-width: 960px) {
  .app-sidebar { transform: translateX(-100%); width: 260px; }
  .app-sidebar.mobile-open { transform: translateX(0); width: 260px; }
  .app-main, .app-footer { margin-left: 0 !important; }
  .app-main { width: 100% !important; }
  .header-search { display: none; }
  /* En desktop este ancho alinea la marca con el sidebar fijo; en mobile el
     sidebar es un panel superpuesto (off-canvas), así que solo desperdicia
     espacio y puede empujar el resto del header fuera de pantalla. */
  .app-header .brand { min-width: 0; }
  .app-header .brand span { display: none; }
  .user-menu .user-info { display: none; }
  .dropdown-panel { max-width: calc(100vw - 24px); }

  .mobile-search-toggle { display: inline-flex; }
  /* Ctrl+K no sirve sin teclado físico y el buscador quedaba oculto sin ningún
     reemplazo táctil; este botón lo despliega como una barra propia debajo
     del header, con los mismos resultados y lógica que ya tiene el buscador
     de escritorio (solo cambia dónde se muestra). */
  .header-search.mobile-open {
    display: block;
    position: fixed;
    top: var(--header-height); left: 0; right: 0;
    max-width: none;
    background: var(--color-bg);
    border-bottom: 1px solid var(--color-border);
    padding: 10px 16px;
    z-index: 150;
    box-shadow: var(--shadow-modal);
  }
  .header-search.mobile-open .header-search-kbd { display: none; }
  .header-search.mobile-open .global-search-results { left: 16px; right: 16px; }
}

/* ============================================================
   BOTONES
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 18px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast),
    color var(--transition-fast), box-shadow var(--transition-fast), transform var(--transition-fast);
  white-space: nowrap;
}
.btn svg { width: 16px; height: 16px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn:active:not(:disabled) { transform: translateY(1px); }

.btn-primary { background: var(--color-primary); color: #fff; box-shadow: 0 1px 2px rgba(0, 90, 169, 0.18); }
.btn-primary:hover:not(:disabled) { background: var(--color-primary-dark); box-shadow: 0 4px 10px rgba(0, 90, 169, 0.28); transform: translateY(-1px); }
.btn-primary:active:not(:disabled) { box-shadow: 0 1px 2px rgba(0, 90, 169, 0.18); }

.btn-secondary { background: var(--color-bg); color: var(--color-primary-text); border-color: var(--color-primary); }
.btn-secondary:hover:not(:disabled) { background: var(--color-info-bg); }

.btn-danger { background: var(--color-danger); color: #fff; box-shadow: 0 1px 2px rgba(198, 40, 40, 0.18); }
.btn-danger:hover:not(:disabled) { background: #a92121; box-shadow: 0 4px 10px rgba(198, 40, 40, 0.24); transform: translateY(-1px); }
.btn-danger:active:not(:disabled) { box-shadow: 0 1px 2px rgba(198, 40, 40, 0.18); }

.btn-ghost { background: transparent; color: var(--color-text); }
.btn-ghost:hover:not(:disabled) { background: var(--color-bg-alt); }

.btn-sm { padding: 6px 12px; font-size: 13px; }
.btn-block { width: 100%; }

/* Grupo de botones tipo "segmented control" (p.ej. alternar Lista/Kanban en Tickets). */
.btn-group { display: inline-flex; border-radius: var(--radius-sm); overflow: hidden; }
.btn-group .btn { border-radius: 0; margin-left: -1px; }
.btn-group .btn:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); margin-left: 0; }
.btn-group .btn:last-child { border-radius: 0 var(--radius-sm) 0 var(--radius-sm); }
.btn-active.btn-secondary { background: var(--color-primary); color: #fff; }

/* ============================================================
   FORMULARIOS
   ============================================================ */
.field { margin-bottom: 16px; }
.field label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 6px;
}
.field .hint { font-size: 12px; color: var(--color-text-secondary); margin-top: 4px; }
.field .error-text { font-size: 12px; color: var(--color-danger-text); margin-top: 4px; display: none; }

.evidencia-thumb {
  display: block; max-width: 140px; max-height: 140px; border-radius: var(--radius-sm);
  border: 1px solid var(--color-border); object-fit: cover; cursor: zoom-in;
}
.geocoder-results { margin-top: 8px; border: 1px solid var(--color-border); border-radius: var(--radius-sm); overflow: hidden; }
.geocoder-results:empty { display: none; border: none; }
.geocoder-result-item {
  display: block; width: 100%; text-align: left; padding: 8px 12px;
  border: none; border-bottom: 1px solid var(--color-border); background: var(--color-bg);
  cursor: pointer; font-size: 13px; color: var(--color-text);
}
.geocoder-result-item:last-child { border-bottom: none; }
.geocoder-result-item:hover { background: var(--color-info-bg); }

.input, select.input, textarea.input {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: var(--color-text);
}
.input:focus, select.input:focus, textarea.input:focus {
  border-color: var(--color-secondary);
  outline: none;
  box-shadow: 0 0 0 3px rgba(10, 116, 196, 0.15);
}
.input.invalid { border-color: var(--color-danger); }
textarea.input { resize: vertical; min-height: 90px; }

.form-row { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }

.input-group { display: flex; align-items: stretch; }
.input-group .input { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.input-group .input-suffix {
  display: flex; align-items: center; padding: 0 10px; white-space: nowrap;
  border: 1px solid var(--color-border); border-left: none;
  border-top-right-radius: var(--radius-sm); border-bottom-right-radius: var(--radius-sm);
  background: var(--color-bg-alt); color: var(--color-text-secondary); font-size: 14px;
}

.credential-box {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--color-bg-alt); border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  padding: 10px 12px; font-family: monospace; font-size: 15px; margin: 10px 0;
}

.checkbox-row, .radio-row {
  display: flex; align-items: center; gap: 8px; font-size: 14px;
}

.switch { position: relative; display: inline-block; width: 40px; height: 22px; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch .slider {
  position: absolute; inset: 0; background: var(--color-border);
  border-radius: 22px; cursor: pointer; transition: var(--transition-fast);
}
.switch .slider::before {
  content: ''; position: absolute; width: 16px; height: 16px; left: 3px; top: 3px;
  background: #fff; border-radius: 50%; transition: var(--transition-fast);
}
.switch input:checked + .slider { background: var(--color-primary); }
.switch input:checked + .slider::before { transform: translateX(18px); }

/* ============================================================
   CARDS / KPI
   ============================================================ */
.card {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 20px;
  min-width: 0;
}
.card-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 14px;
}
.card-header h3 { font-size: 16px; margin: 0; }

.grid { display: grid; gap: 20px; min-width: 0; }

/* Barra de "% dentro del rango recomendado" — Web Vitals reales (RUM), ver
   assets/js/modules/usuarios.js → cargarRendimiento(). */
.progress-bar {
  height: 6px;
  border-radius: 999px;
  background: var(--color-border);
  overflow: hidden;
}
.progress-bar-fill {
  height: 100%;
  background: var(--color-success);
  border-radius: 999px;
}
.grid-kpi { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }

.dashboard-top { display: grid; grid-template-columns: 300px 1fr; gap: 20px; align-items: start; }
@media (max-width: 900px) { .dashboard-top { grid-template-columns: 1fr; } }

.kpi-card {
  display: flex; align-items: center; gap: 14px;
  border-left-width: 4px;
  border-left-style: solid;
}
.kpi-accent-neutral { border-left-color: var(--color-border); }
.kpi-accent-primary { border-left-color: var(--color-primary); }
.kpi-accent-success { border-left-color: var(--color-success); }
.kpi-accent-warning { border-left-color: var(--color-warning-graphic); }
.kpi-accent-danger { border-left-color: var(--color-danger); }

.kpi-icon {
  width: 46px; height: 46px; border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.kpi-icon svg { width: 24px; height: 24px; }
.kpi-icon-neutral { background: var(--color-bg-alt); color: var(--color-text-secondary); }
.kpi-icon-primary { background: var(--color-info-bg); color: var(--color-primary-text); }
.kpi-icon-success { background: var(--color-success-bg); color: var(--color-success-text); }
.kpi-icon-warning { background: var(--color-warning-bg); color: var(--color-warning-text); }
.kpi-icon-danger { background: var(--color-danger-bg); color: var(--color-danger-text); }

.kpi-value { font-size: 26px; font-weight: 700; line-height: 1.1; }
.kpi-label { font-size: 13px; color: var(--color-text-secondary); }
.kpi-delta { font-size: 12px; font-weight: 600; }
.kpi-delta.up { color: var(--color-success-text); }
.kpi-delta.down { color: var(--color-danger-text); }

/* Ranking de regiones por % de operatividad (lista, no gráfico de barras:
   con 16 regiones un chart horizontal de ancho completo era difícil de leer). */
.ranking-regiones {
  display: flex; flex-direction: column; gap: 10px;
  margin-top: 12px; max-height: 460px; overflow-y: auto; padding-right: 4px;
}
.ranking-row { display: flex; align-items: center; gap: 12px; }
.ranking-rank {
  flex-shrink: 0; width: 26px; height: 26px; border-radius: 50%;
  background: var(--color-bg-alt); color: var(--color-text-secondary);
  font-size: 12px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.ranking-main { flex: 1; min-width: 0; }
.ranking-row-header { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 4px; }
.ranking-name { font-size: 13px; font-weight: 600; color: var(--color-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ranking-pct { font-size: 13px; font-weight: 700; flex-shrink: 0; }
.ranking-metric-extra { font-size: 11.5px; font-weight: 600; color: var(--color-text-secondary); background: var(--color-bg-alt); padding: 2px 7px; border-radius: 10px; white-space: nowrap; }
.ranking-bar-track { height: 8px; border-radius: 4px; background: var(--color-bg-alt); overflow: hidden; }
.ranking-bar-fill { height: 100%; border-radius: 4px; transition: width 0.6s cubic-bezier(.22,1,.36,1); }
.ranking-detail { margin-top: 3px; }
.ranking-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.ranking-actions .btn { padding: 3px 9px; font-size: 11.5px; }
.ranking-pct.zone-success { color: var(--color-success-text); }
.ranking-pct.zone-warning { color: var(--color-warning-text); }
.ranking-pct.zone-danger { color: var(--color-danger-text); }
.ranking-bar-fill.zone-success { background: var(--color-success); }
.ranking-bar-fill.zone-warning { background: var(--color-warning-graphic); }
.ranking-bar-fill.zone-danger { background: var(--color-danger); }

.kpi-clickable { cursor: pointer; transition: border-color var(--transition-fast), box-shadow var(--transition-fast), transform var(--transition-fast); }
.kpi-clickable:hover { box-shadow: var(--shadow-card-hover); transform: translateY(-2px); }

/* ============================================================
   BADGES / ALERTAS / TOAST
   ============================================================ */
.badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}
.badge-success { background: var(--color-success-bg); color: var(--color-success-text); }
.badge-warning { background: var(--color-warning-bg); color: #8a6100; }
.badge-danger { background: var(--color-danger-bg); color: var(--color-danger-text); }
.badge-info { background: var(--color-info-bg); color: var(--color-primary-text); }
.badge-neutral { background: var(--color-bg-alt); color: var(--color-text-secondary); }

.alert {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  border: 1px solid transparent;
}
.alert-success { background: var(--color-success-bg); color: var(--color-success-text); border-color: #b6dab8; }
.alert-warning { background: var(--color-warning-bg); color: #8a6100; border-color: #f0d896; }
.alert-danger { background: var(--color-danger-bg); color: var(--color-danger-text); border-color: #edb7b3; }
.alert-info { background: var(--color-info-bg); color: var(--color-primary-text); border-color: #b7d4ec; }

.toast-container {
  position: fixed;
  bottom: 20px; right: 20px;
  display: flex; flex-direction: column; gap: 10px;
  z-index: 1000;
}
.toast {
  min-width: 260px; max-width: 360px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--color-primary);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-modal);
  padding: 12px 16px;
  font-size: 14px;
  animation: toast-in var(--transition-base);
}
.toast.success { border-left-color: var(--color-success); }
.toast.warning { border-left-color: var(--color-warning); }
.toast.danger { border-left-color: var(--color-danger); }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }

/* ============================================================
   BANNER DE INSTALACIÓN (PWA) — assets/js/install-prompt.js
   ============================================================ */
.install-banner {
  position: fixed;
  left: 12px; right: 12px;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  z-index: 1000;
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: 480px;
  margin: 0 auto;
  background: var(--color-primary);
  color: #fff;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-modal);
  padding: 14px 16px;
  animation: toast-in var(--transition-base);
}
.install-banner-icono { font-size: 22px; line-height: 1; flex-shrink: 0; }
.install-banner-texto { flex: 1; font-size: 13px; line-height: 1.4; }
.install-banner-acciones { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.install-banner-acciones .btn-primary {
  background: #fff;
  color: var(--color-primary-text);
  border-color: #fff;
}
.install-banner-acciones .btn-primary:hover { background: var(--color-bg-alt); }
.install-banner-cerrar {
  background: transparent;
  border: none;
  color: #fff;
  opacity: 0.8;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  padding: 4px;
}
.install-banner-cerrar:hover { opacity: 1; }

/* ============================================================
   TABS
   ============================================================ */
/* Cuando hay más pestañas de las que caben (p. ej. Estadísticas con 4: Plazas, Unidad
   Móvil, Pesajes, Trazabilidad), overflow-x:auto ya permite deslizar, pero sin ninguna
   pista visual de que hay más contenido la última pestaña simplemente se veía cortada
   a la mitad — parecía que solo existían las que entraban en pantalla. Este degradado
   (la técnica de "scroll shadow": dos capas fijas que hacen de sombra y dos que se
   mueven con el contenido para taparla apenas se llega a cada extremo) avisa que se
   puede seguir deslizando, sin agregar JS ni cambiar el marcado existente. */
.tabs {
  display: flex; gap: 4px; border-bottom: 1px solid var(--color-border); margin-bottom: 20px;
  overflow-x: auto;
  background:
    linear-gradient(to right, var(--color-bg-alt) 50%, transparent) left,
    linear-gradient(to left, var(--color-bg-alt) 50%, transparent) right,
    linear-gradient(to right, var(--color-border), transparent) left,
    linear-gradient(to left, var(--color-border), transparent) right;
  background-repeat: no-repeat;
  background-size: 24px 100%, 24px 100%, 10px 100%, 10px 100%;
  background-attachment: local, local, scroll, scroll;
}
.tab-btn {
  padding: 10px 16px; border: none; background: transparent;
  font-weight: 600; font-size: 14px; color: var(--color-text-secondary);
  cursor: pointer; border-bottom: 2px solid transparent; white-space: nowrap;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.tab-btn:hover { color: var(--color-text); }
.tab-btn.active { color: var(--color-primary-text); border-bottom-color: var(--color-primary); }

/* Selector de dominio (Estadísticas): agrupa las pestañas en "Conteo manual" y "Datos
   de pesajes" para que nunca convivan más de 6 botones a la vez en la fila de abajo —
   antes las 11 pestañas del módulo iban todas juntas y se cortaban en pantallas
   angostas (ver el degradado de scroll de .tabs, pensado quedó corto para esa cantidad).
   Cada dominio tiene su propio acento (gris pizarra / azul institucional) para que se
   note de un vistazo cuál está activo, incluso antes de leer la etiqueta. */
.dominio-switch {
  display: inline-flex; gap: 3px; padding: 3px; margin-bottom: 14px;
  background: var(--color-bg-alt); border: 1px solid var(--color-border); border-radius: 999px;
}
.dominio-btn {
  display: flex; align-items: center; gap: 7px; border: none; background: transparent;
  font-family: inherit; font-weight: 700; font-size: 13.5px; color: var(--color-text-secondary);
  padding: 8px 16px; border-radius: 999px; cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.dominio-btn:hover:not(.active) { color: var(--color-text); }
.dominio-btn.dominio-manual.active { background: var(--color-manual); color: #fff; }
.dominio-btn.dominio-pesajes.active { background: var(--color-primary); color: #fff; }
.dominio-count {
  font-size: 11px; font-weight: 700; padding: 1px 7px; border-radius: 999px;
  background: rgba(127, 127, 127, 0.18);
}
.dominio-btn.active .dominio-count { background: rgba(255, 255, 255, 0.28); }

/* ============================================================
   TABLAS
   ============================================================ */
.pagination-bar { display: flex; align-items: center; justify-content: center; gap: 16px; margin-top: 14px; }
.table-wrap { overflow-x: auto; border: 1px solid var(--color-border); border-radius: var(--radius-md); }
table.data-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.data-table thead th {
  background: var(--color-bg-alt);
  text-align: left;
  padding: 12px 14px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--color-text-secondary);
  border-bottom: 1px solid var(--color-border);
  white-space: nowrap;
}
.data-table th.sortable-th { cursor: pointer; user-select: none; }
.data-table th.sortable-th:hover { color: var(--color-text); }
.data-table th.sortable-th:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }
.data-table .sort-indicator { color: var(--color-primary-text); font-size: 10px; }
.data-table td { padding: 12px 14px; border-bottom: 1px solid var(--color-border); }
/* Botón "Ver más" de las tarjetas en celular (ver @media 720px más abajo): en la
   tabla normal de escritorio no hay nada que expandir, así que no ocupa columna. */
.data-table td.mobile-toggle { display: none; }
.data-table tbody tr { transition: background var(--transition-fast); }
.data-table tbody tr:nth-child(even) { background: var(--zebra-stripe); }
.data-table tbody tr:hover { background: var(--color-info-bg); }
.data-table .actions-cell { display: flex; gap: 6px; }
.data-table tbody tr.row-total { background: var(--color-info-bg); border-top: 2px solid var(--color-border); }
.data-table tbody tr.row-total:hover { background: var(--color-info-bg); }
.data-table tbody tr.row-highlight { background: var(--color-warning-bg); transition: background 2s ease; }

/* Antes era una segunda tarjeta blanca (borde + sombra) apilada justo encima de la
   tabla, compitiendo visualmente con ella. Al quitarle el borde/sombra y dejarla
   como una franja de herramientas sin caja propia, la tabla de abajo queda como el
   único contenedor real de la vista — menos "cajas dentro de cajas". */
.filters-bar {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end;
  margin-bottom: 18px; padding: 0;
  background: transparent; border: none;
}
.filters-bar .field { margin-bottom: 0; min-width: 160px; }

/* ============================================================
   ENCABEZADOS COMPACTOS — "⋯ Más opciones" y "Filtros ▾"
   ============================================================
   Reemplaza, en los módulos que lo piden, la fila de 3-4 botones secundarios
   (Imprimir, Exportar…) apilados junto a la acción principal: solo esta última
   queda siempre visible, el resto vive detrás de "⋯". Los filtros siguen el
   mismo principio — colapsados salvo que ya haya alguno activo (ver
   App.wireBotonDesplegable / App.wireDesplegablesGlobal). */
/* Fila [acción principal, botón ⋯]: independiente de .page-header > .flex (esa regla
   apila TODOS sus hijos en columna en celular, pensada para 3-4 botones sueltos — acá
   solo hay dos elementos de ancho fijo/flexible que deben seguir en fila siempre). */
/* Sin position:relative acá a propósito: .menu-mas se posiciona contra .page-header
   (más abajo), no contra esta fila — en celular esta fila no ocupa todo el ancho (solo
   el de sus botones), así que anclar el menú a SU borde derecho lo hacía sobresalir por
   la izquierda de la pantalla en vez de quedar dentro del área de contenido real. */
.acciones-compactas { display: flex; gap: 8px; align-items: flex-start; flex-wrap: wrap; }
.acciones-compactas > .btn-primary { flex: 1 1 auto; }
.acciones-compactas > .btn:not(.btn-primary) { flex-shrink: 0; }

.btn-mas {
  flex-shrink: 0; width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  background: var(--color-bg); color: var(--color-text-secondary);
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  font-size: 19px; font-weight: 800; letter-spacing: 1px; cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}
.btn-mas:hover { background: var(--color-bg-alt); color: var(--color-text); }
.btn-mas.abierto { background: var(--color-info-bg); color: var(--color-primary-text); border-color: var(--color-secondary); }

.menu-mas {
  position: absolute; top: 100%; right: 0; z-index: 60; margin-top: 6px;
  width: min(230px, calc(100vw - 48px));
  background: var(--color-bg); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-modal);
  padding: 6px; display: none; flex-direction: column; gap: 2px;
}
.menu-mas.abierto { display: flex; animation: modal-in var(--transition-fast); }
.menu-mas button, .menu-mas a {
  background: transparent; border: none; text-align: left; width: 100%;
  padding: 10px 10px; border-radius: var(--radius-sm); display: block;
  font-size: 13.5px; font-weight: 600; color: var(--color-text); cursor: pointer;
  text-decoration: none;
}
.menu-mas button:hover, .menu-mas a:hover { background: var(--color-bg-alt); }

.filtros-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--color-bg); color: var(--color-text);
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  padding: 9px 14px; font-size: 13.5px; font-weight: 700; cursor: pointer;
  margin-bottom: 18px;
}
.filtros-toggle:hover { border-color: var(--color-secondary); }
.filtros-toggle.abierto { border-color: var(--color-secondary); color: var(--color-primary-text); }
.filtros-toggle .badge-count {
  background: var(--color-primary); color: #fff; font-size: 11px; font-weight: 800;
  border-radius: 999px; padding: 1px 7px; line-height: 1.5;
}
.filtros-toggle .chev { color: var(--color-text-secondary); font-size: 11px; transition: transform .2s; }
.filtros-toggle.abierto .chev { transform: rotate(180deg); color: var(--color-secondary); }

.filtros-panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .25s ease; margin-top: -10px; }
.filtros-panel.abierto { grid-template-rows: 1fr; }
.filtros-panel-inner { overflow: hidden; min-height: 0; }
.filtros-panel .filters-bar { padding-top: 4px; margin-bottom: 18px; }
@media (prefers-reduced-motion: reduce) { .filtros-panel { transition: none; } }

/* Barra de acciones masivas (selección múltiple): mismo lenguaje visual que
   .filters-bar, pero con acento de color para distinguirla de un filtro más. */
.bulk-actions-bar {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
  margin-bottom: 16px; padding: 10px 16px; background: var(--color-info-bg);
  border: 1px solid var(--color-secondary); border-radius: var(--radius-md);
}
.input-sm { padding: 6px 10px; font-size: 13px; height: auto; }

.pagination { display: flex; align-items: center; gap: 6px; justify-content: flex-end; margin-top: 14px; }
.pagination button {
  min-width: 32px; height: 32px; border-radius: var(--radius-sm);
  border: 1px solid var(--color-border); background: var(--color-bg); cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}
.pagination button:hover:not(.active) { background: var(--color-bg-alt); border-color: var(--color-text-secondary); }
.pagination button.active { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }

/* Tablas → tarjetas apiladas en pantallas angostas */
@media (max-width: 720px) {
  .data-table thead { display: none; }
  .data-table, .data-table tbody, .data-table tr, .data-table td { display: block; width: 100%; }
  .table-wrap { border: none; }
  .data-table tr {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    margin-bottom: 12px;
    padding: 4px 14px;
  }
  .data-table tr:nth-child(even) { background: var(--color-bg); }
  .data-table td {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--color-border);
    text-align: right;
  }
  .data-table td:last-child { border-bottom: none; }
  .data-table td::before {
    content: attr(data-label);
    font-size: 12px; font-weight: 600; color: var(--color-text-secondary);
    text-align: left; margin-right: auto;
  }
  .data-table td.actions-cell { justify-content: flex-end; flex-wrap: wrap; }
  .data-table td.actions-cell::before { content: none; }

  /* La primera celda CON data-label (saltándose una celda de checkbox de selección
     masiva, que no trae data-label) es siempre el dato que identifica la fila —
     número de unidad, título del ticket, nombre de la plaza. En vez de mostrarla
     como un campo más ("Unidad: 103"), se destaca como título de la tarjeta: así
     se puede escanear la lista completa leyendo solo esa línea, en vez de tener
     que leer la etiqueta de cada campo para encontrar el dato que identifica la fila. */
  .data-table tr > td[data-label]:first-child,
  .data-table tr > td:not([data-label]) + td[data-label] {
    justify-content: flex-start;
    padding: 10px 0 8px;
    font-size: 15px;
    font-weight: 700;
  }
  .data-table tr > td[data-label]:first-child::before,
  .data-table tr > td:not([data-label]) + td[data-label]::before {
    content: none;
  }

  /* Tablas "chip" (data-table--chips, ver App.wireChipAccordion): en vez de tarjeta
     completa, la fila colapsada muestra solo la celda que la identifica (N° de unidad,
     nombre de la plaza, usuario…) — y el checkbox de selección masiva, si lo hay. El
     resto se revela recién al tocarla, en acordeón: una sola fila abierta a la vez por
     tabla. Reemplaza, para las listas largas que lo piden explícitamente, el modelo
     anterior de tarjeta siempre completa. */
  .data-table--chips td { display: none; }
  .data-table--chips tr > td:not([data-label]):first-child {
    display: flex; border-bottom: none;
  }
  .data-table--chips tr > td[data-label]:first-child,
  .data-table--chips tr > td:not([data-label]) + td[data-label] {
    display: flex;
    cursor: pointer;
    border-bottom: none;
  }
  /* .actions-cell trae su propio "display: flex" fuera de este @media (para acomodar
     los botones en fila en escritorio), con más especificidad que la regla de arriba
     que oculta todo por defecto — sin este par de reglas, los botones de acción
     quedarían visibles incluso con la fila colapsada. */
  .data-table--chips td.actions-cell { display: none; }
  .data-table--chips tr.chip-open > td.actions-cell { display: flex; }
  .data-table--chips tr.chip-open > td { display: flex; }
  .data-table--chips tr.chip-open > td[data-label]:first-child,
  .data-table--chips tr.chip-open > td:not([data-label]) + td[data-label] {
    border-bottom: 1px solid var(--color-border);
  }
  .data-table--chips tr:not(.chip-open) > td[data-label]:first-child:hover,
  .data-table--chips tr:not(.chip-open) > td:not([data-label]) + td[data-label]:hover,
  .data-table--chips tr > td[data-label]:first-child:focus-visible,
  .data-table--chips tr > td:not([data-label]) + td[data-label]:focus-visible {
    background: var(--color-info-bg);
    margin: 0 -14px; padding-left: 14px; padding-right: 14px;
    border-radius: var(--radius-sm);
  }
  /* Flecha que indica "tocar para ver más": mismo glifo ▾/▲ que ya usan los botones
     "Ver más" del resto de la app, para no introducir un lenguaje visual nuevo. */
  .data-table--chips tr > td[data-label]:first-child::after,
  .data-table--chips tr > td:not([data-label]) + td[data-label]::after {
    content: '▾';
    margin-left: auto; padding-left: 10px; flex-shrink: 0;
    color: var(--color-text-secondary); font-size: 12px;
    transition: transform .2s, color .2s;
  }
  .data-table--chips tr.chip-open > td[data-label]:first-child::after,
  .data-table--chips tr.chip-open > td:not([data-label]) + td[data-label]::after {
    transform: rotate(180deg);
    color: var(--color-secondary);
  }
  /* Franja de estado (mismo idioma visual que .toast): permite escanear la lista
     colapsada sabiendo qué fila necesita atención sin tener que abrirla. Opcional —
     solo aparece si el módulo le puso data-estado a la fila. */
  .data-table--chips tr[data-estado] { border-left: 4px solid var(--color-border); }
  .data-table--chips tr[data-estado="ok"] { border-left-color: var(--color-success); }
  .data-table--chips tr[data-estado="warn"] { border-left-color: var(--color-warning-graphic); }
  .data-table--chips tr[data-estado="danger"] { border-left-color: var(--color-danger); }
}

@media (max-width: 480px) {
  /* Con 3-4 botones de acción por fila (Registrar, Ubicación, Editar, Eliminar…), envueltos
     en línea quedaban muy chicos para tocar con el dedo (~29px de alto, bajo el mínimo
     recomendado de 44px). En una tarjeta ya apilada por campo, un botón por línea a lo
     ancho es más fácil de tocar sin perder tiempo. */
  .data-table td.actions-cell { flex-direction: column; align-items: stretch; }
  .data-table td.actions-cell .btn { width: 100%; padding: 13px 12px; }
}

/* ============================================================
   MODAL
   ============================================================ */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(15, 23, 32, 0.55);
  backdrop-filter: blur(2px);
  display: flex; align-items: center; justify-content: center;
  z-index: 500; padding: 20px;
  animation: modal-overlay-in var(--transition-base);
}
@keyframes modal-overlay-in { from { opacity: 0; } to { opacity: 1; } }
.modal { animation: modal-in var(--transition-base); }
@keyframes modal-in { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
.modal {
  background: var(--color-bg);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-modal);
  width: 100%; max-width: 560px;
  max-height: 90vh;
  display: flex; flex-direction: column;
}
.modal.modal-lg { max-width: 820px; }
.modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 22px; border-bottom: 1px solid var(--color-border);
}
.modal-header h3 { margin: 0; }
.modal-close { border: none; background: transparent; cursor: pointer; padding: 4px; color: var(--color-text-secondary); }
.modal-body { padding: 22px; overflow-y: auto; }
.modal-footer {
  padding: 16px 22px; border-top: 1px solid var(--color-border);
  display: flex; justify-content: flex-end; gap: 10px;
}

/* ============================================================
   DROPDOWN / PANEL NOTIFICACIONES
   ============================================================ */
.dropdown-panel {
  position: absolute; top: calc(100% + 8px); right: 0;
  width: 340px; max-height: 420px; overflow-y: auto;
  background: var(--color-bg); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-modal);
  z-index: 200;
}
.dropdown-panel .panel-header {
  padding: 14px 16px; border-bottom: 1px solid var(--color-border);
  display: flex; align-items: center; justify-content: space-between; font-weight: 600;
}
.notification-item { padding: 12px 16px; border-bottom: 1px solid var(--color-border); font-size: 13px; cursor: pointer; }
.notification-item:last-child { border-bottom: none; }
.notification-item.unread { background: var(--color-info-bg); }
.notification-item .time { font-size: 11px; color: var(--color-text-secondary); margin-top: 2px; }

/* Panel del asistente IA: mismo lenguaje visual que .dropdown-panel, pero más ancho/alto
   (transcripción de conversación) y con un pie fijo para el campo de pregunta. */
.asistente-panel { width: 380px; max-height: 520px; display: flex; flex-direction: column; }
.asistente-body { flex: 1; min-height: 220px; max-height: 360px; overflow-y: auto; padding: 12px 14px; }
.asistente-vacio { font-size: 13px; color: var(--color-text-secondary); line-height: 1.5; padding: 8px 2px; }
.asistente-msg { font-size: 13.5px; line-height: 1.5; padding: 9px 12px; border-radius: var(--radius-sm); margin-bottom: 8px; max-width: 92%; }
.asistente-msg-usuario { background: var(--color-primary); color: #fff; margin-left: auto; }
.asistente-msg-ia { background: var(--color-bg-alt); }
.asistente-fuentes { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.asistente-fuente {
  font-size: 12px; padding: 4px 9px; border-radius: 999px; border: 1px solid var(--color-border);
  background: var(--color-bg); color: var(--color-text); cursor: pointer;
}
.asistente-fuente:hover { background: var(--color-bg-alt); }
.asistente-form { display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--color-border); }
.asistente-form .input { flex: 1; }
/* En mobile el botón del asistente queda cerca del borde izquierdo del header (es el
   primer ícono de header-actions), así que anclar el panel con right:0 relativo a un
   contenedor tan angosto lo deja mayormente fuera de pantalla hacia la izquierda. Se
   ancla directo al viewport en vez de al botón. */
@media (max-width: 900px) {
  .asistente-panel {
    position: fixed;
    top: calc(var(--header-height) + 8px);
    left: 12px; right: 12px;
    width: auto; max-width: none;
    max-height: calc(100vh - var(--header-height) - 24px);
  }
}

/* ============================================================
   ACCORDION / TOOLTIP / TIMELINE
   ============================================================ */
.accordion-item { border: 1px solid var(--color-border); border-radius: var(--radius-sm); margin-bottom: 8px; overflow: hidden; }
.accordion-trigger {
  width: 100%; text-align: left; padding: 12px 14px; background: var(--color-bg-alt);
  border: none; font-weight: 600; cursor: pointer; display: flex; justify-content: space-between; align-items: center;
}
.accordion-panel { padding: 14px; display: none; }
.accordion-item.open .accordion-panel { display: block; }

[data-tooltip] { position: relative; }
/* Solo en dispositivos con hover real (mouse/trackpad): en pantallas táctiles
   ":hover" se activa con el toque y varios navegadores lo dejan "pegado" hasta el
   próximo toque en otro lado — un tooltip fantasma flotando sobre el siguiente
   elemento que la persona mira. */
@media (hover: hover) {
  [data-tooltip]:hover::after {
    content: attr(data-tooltip);
    position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%);
    background: #222; color: #fff; padding: 4px 8px; border-radius: 4px; font-size: 12px;
    white-space: nowrap; z-index: 300;
  }
}

.timeline { border-left: 2px solid var(--color-border); margin-left: 8px; padding-left: 20px; }
.timeline-item { position: relative; padding-bottom: 18px; }
.timeline-item::before {
  content: ''; position: absolute; left: -25px; top: 4px;
  width: 10px; height: 10px; border-radius: 50%; background: var(--color-primary);
}
.timeline-item .timeline-date { font-size: 12px; color: var(--color-text-secondary); }

.alerta-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border-radius: var(--radius-sm);
  border-left: 4px solid var(--color-border);
  background: var(--color-bg-subtle, rgba(0,0,0,0.02));
  margin-bottom: 8px;
}
.alerta-row:last-child { margin-bottom: 0; }
.alerta-row.alerta-danger { border-left-color: var(--color-danger); }
.alerta-row.alerta-warning { border-left-color: var(--color-warning-graphic); }
.alerta-row.alerta-neutral { border-left-color: var(--color-text-secondary); }
.alerta-icono { font-size: 18px; flex-shrink: 0; }
.alerta-cuerpo { flex: 1; min-width: 0; }
.alerta-titulo { font-weight: 600; font-size: 14px; }
.alerta-ver { flex-shrink: 0; }

/* ============================================================
   TRANSICIONES DE VISTA (View Transitions API nativa)
   ============================================================ */
/* Sin selectores propios no hay nada que estilizar: el navegador ya anima un
   cross-fade por defecto entre ::view-transition-old(root) y -new(root). Solo
   se ajusta la duración/curva para que calce con el resto de las transiciones
   de la app en vez de quedarse con los 250ms/ease por defecto del navegador. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--transition-base);
  animation-timing-function: cubic-bezier(.4, 0, .2, 1);
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* ============================================================
   LOADER / SKELETON / EMPTY STATE
   ============================================================ */
.loader {
  width: 28px; height: 28px; border-radius: 50%;
  border: 3px solid var(--color-border); border-top-color: var(--color-primary);
  animation: spin 0.8s linear infinite; margin: 24px auto;
}
@keyframes spin { to { transform: rotate(360deg); } }
.loader-sm { width: 16px; height: 16px; border-width: 2px; margin: 0; display: inline-block; vertical-align: middle; }

.skeleton {
  background: linear-gradient(90deg, var(--color-bg-alt) 25%, rgba(0,0,0,0.04) 37%, var(--color-bg-alt) 63%);
  background-size: 400% 100%;
  animation: skeleton-loading 1.4s ease infinite;
  border-radius: var(--radius-sm);
}
@keyframes skeleton-loading { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

.empty-state { text-align: center; padding: 48px 20px; color: var(--color-text-secondary); }
.empty-state svg { width: 48px; height: 48px; margin-bottom: 12px; opacity: .6; }

/* Los placeholders "aún no hay datos para graficar" (Tendencia, Comparativa) eran
   antes solo texto suelto flotando en un bloque en blanco, sin nada que anclara la
   mirada — se les agrega el mismo ícono discreto que .empty-state, vía ::before para
   no tener que tocar el HTML que ya arma cada módulo. */
.chart-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; text-align: center;
}
.chart-empty::before {
  content: '';
  width: 40px; height: 40px;
  opacity: .45;
  background-color: var(--color-text-secondary);
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3 3v18h18'/><path d='M18.4 8.6 12 15l-3-3-4 4'/></svg>") center / contain no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3 3v18h18'/><path d='M18.4 8.6 12 15l-3-3-4 4'/></svg>") center / contain no-repeat;
}

/* ============================================================
   GAUGE (velocímetro de operatividad)
   ============================================================ */
.gauge-card { text-align: center; }
.gauge-wrap { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.gauge-svg-wrap {
  width: 100%;
  max-width: 260px;
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: transform var(--transition-fast);
}
.gauge-svg-wrap:hover, .gauge-svg-wrap:focus-visible { transform: scale(1.03); }
.gauge-svg { width: 100%; height: auto; display: block; }
.gauge-tick { font-size: 11px; font-weight: 600; fill: var(--color-text-secondary); }
.gauge-needle { transform-box: view-box; }
.gauge-value { font-size: 34px; font-weight: 700; line-height: 1.15; margin-top: 2px; }
.gauge-caption { font-size: 13px; color: var(--color-text-secondary); }

/* ============================================================
   MAPA
   ============================================================ */
/* El mapa ocupa todo el ancho disponible; el riel de herramientas y el panel
   flotante (ver más abajo) se posicionan encima con position:absolute, así que
   .map-page solo necesita ser el contenedor de referencia para ese posicionamiento. */
.map-page { position: relative; }
/* "Pantalla completa" (del layout normal, no confundir con .map-page--fullscreen):
   ocupa el alto disponible bajo el header y el título de la página, no un tamaño
   fijo arbitrario. En pantallas angostas se vuelve a un alto fijo cómodo, para no
   dejar el mapa demasiado bajo. */
#gis-map {
  /* position+z-index (no solo position) es lo que de verdad encierra a Leaflet en su
     propio contexto de apilamiento: sus paneles internos usan z-index hasta 1000
     (controles) pensando que quedan contenidos adentro, pero sin un z-index explícito
     acá esos valores compiten directamente contra el header (100) y la sidebar (90) de
     toda la app — con tiles reales cargados (no en un entorno sin internet, donde el
     panel de tiles queda vacío y el problema no se nota visualmente) el mapa terminaba
     pintándose por encima de la sidebar y del menú de usuario en vez de quedar debajo. */
  position: relative;
  z-index: 0;
  height: calc(100vh - 200px);
  min-height: 600px;
  width: 100%;
  background: var(--color-bg-alt);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-card);
}
@media (max-width: 900px) { #gis-map { height: 520px; min-height: 0; } }

/* Riel de íconos flotante: reemplaza el antiguo panel lateral siempre visible.
   Cada botón abre/cierra el panel de esa herramienta (.map-toolpanel) — así el
   mapa recupera todo el ancho y solo se cede espacio cuando la persona lo pide. */
.map-toolrail {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 4px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
}
.map-tool-btn {
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-secondary);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.map-tool-btn .ic { width: 20px; height: 20px; }
.map-tool-btn:hover { background: var(--color-bg-alt); color: var(--color-text); }
.map-tool-btn[aria-pressed="true"] { background: var(--color-primary); color: #fff; }
.map-tool-btn[aria-pressed="true"]:hover { background: var(--color-primary-dark); }

/* Panel de la herramienta activa: aparece junto al riel, con la misma sección
   interna que antes vivía siempre expandida en el panel lateral (mismos IDs,
   mismos controles) — solo cambia dónde y cuándo se muestra. */
.map-toolpanel {
  position: absolute;
  top: 12px;
  left: 62px;
  z-index: 11;
  width: 290px;
  max-height: calc(100% - 24px);
  display: flex;
  flex-direction: column;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-modal);
  animation: modal-in var(--transition-base);
}
.map-toolpanel[hidden] { display: none; }
.map-toolpanel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 8px 12px 16px;
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
}
.map-toolpanel-header h3 { margin: 0; font-size: 14px; font-weight: 700; }
.map-toolpanel-body {
  padding: 14px 16px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}
@media (max-width: 640px) {
  .map-toolpanel {
    left: 12px;
    right: 12px;
    top: 58px;
    width: auto;
    max-height: calc(100% - 70px);
  }
}

/* Aviso de "mapa base no disponible" (ver reintentarTileFallido/mostrarAlertaTiles en
   map.js): en vez de dejar el mapa en blanco sin explicación cuando el proveedor de
   tiles rechaza tráfico, se avisa explícitamente — los puntos de control (que vienen
   de la propia API, no de OSM) siguen andando igual mientras tanto. */
.map-tiles-alerta {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 12;
  max-width: min(520px, calc(100% - 100px));
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--color-warning-bg);
  color: var(--color-warning-text);
  border: 1px solid var(--color-warning-graphic);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 10px 14px;
  font-size: 13px;
}
.map-tiles-alerta.hidden { display: none; }
.map-tiles-alerta .btn { flex-shrink: 0; }
@media (max-width: 640px) {
  .map-tiles-alerta { left: 12px; right: 12px; top: 58px; transform: none; max-width: none; flex-direction: column; align-items: stretch; text-align: center; }
}

/* Botón "Pantalla completa" del mapa (distinto del modo fullscreen del navegador):
   expande .map-page para ocupar el viewport. A diferencia de la Sala de Situación
   (pensada como pantalla no interactiva, sin necesidad de sus controles), acá sí se
   sigue trabajando activamente — buscar, revisar notificaciones, cambiar de cuenta —
   así que empieza debajo de la cabecera (top: header-height) y queda por debajo de
   ella en z-index, en vez de taparla: antes el mapa ampliado cubría también el
   buscador, las notificaciones y el menú de usuario, dejándolos inaccesibles hasta
   salir de pantalla completa. Al no tener columnas (el riel/panel son absolutos),
   no necesita ningún ajuste adicional para verse bien en mobile. */
.map-page--fullscreen {
  position: fixed;
  top: var(--header-height); left: 0; right: 0; bottom: 0;
  z-index: 95;
  background: var(--color-bg);
  padding: 12px;
}
.map-page--fullscreen #gis-map {
  height: calc(100vh - var(--header-height) - 24px);
  max-height: calc(100vh - var(--header-height) - 24px);
  min-height: 0;
}
/* El botón de pantalla completa vive en .page-header, que .map-page--fullscreen
   (fixed) termina cubriendo visualmente aunque ya no tape la cabecera global.
   Mientras dura el modo fullscreen, el botón flota por encima del mapa (debajo
   de la cabecera global, no sobre ella) para que siempre sea visible. */
.btn-map-fullscreen--flotante {
  position: fixed;
  top: calc(var(--header-height) + 12px);
  right: 20px;
  z-index: 96;
  box-shadow: var(--shadow-card);
}

.map-legend-item { display: flex; align-items: center; gap: 8px; padding: 6px 0; font-size: 13px; }
.map-legend-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
.leaflet-popup-content h4 { margin: 0 0 6px; color: var(--color-primary-text); font-size: 14px; }
.leaflet-popup-content p { margin: 2px 0; font-size: 13px; }

/* Controles de Leaflet (zoom, atribución) modernizados para calzar con el
   sistema de diseño de la app en vez del look por defecto de Leaflet. */
.leaflet-bar { border-radius: var(--radius-sm) !important; box-shadow: var(--shadow-card) !important; overflow: hidden; }
.leaflet-bar a { border-color: var(--color-border) !important; }
.leaflet-control-attribution { border-radius: var(--radius-sm) 0 0 0 !important; font-size: 10.5px !important; }

/* Foco de teclado sobre marcadores del mapa (Leaflet los hace focalizables por defecto):
   el anillo global de :focus-visible queda tapado por marcadores vecinos sin este z-index. */
.leaflet-marker-icon:focus-visible,
.leaflet-interactive:focus-visible {
  outline: 3px solid var(--color-secondary);
  outline-offset: 2px;
  z-index: 1000 !important;
}

/* Mapa en modo oscuro: se invierten los tiles de OSM y se re-tiñen los controles de Leaflet */
.map-dark .leaflet-tile-pane { filter: invert(1) hue-rotate(180deg) brightness(0.95) contrast(0.9); }
:root[data-theme='dark'] .leaflet-popup-content-wrapper,
:root[data-theme='dark'] .leaflet-popup-tip { background: var(--color-bg); color: var(--color-text); }
:root[data-theme='dark'] .leaflet-bar a { background: var(--color-bg); color: var(--color-text); border-color: var(--color-border); }
:root[data-theme='dark'] .leaflet-bar a:hover { background: var(--color-bg-alt); }
:root[data-theme='dark'] .leaflet-control-attribution { background: rgba(16, 22, 29, 0.8); color: var(--color-text-secondary); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .leaflet-popup-content-wrapper,
  :root:not([data-theme='light']) .leaflet-popup-tip { background: var(--color-bg); color: var(--color-text); }
  :root:not([data-theme='light']) .leaflet-bar a { background: var(--color-bg); color: var(--color-text); border-color: var(--color-border); }
}

/* Minimapa de referencia: control propio de Leaflet en la esquina inferior derecha,
   con un segundo mapa (no interactivo) sincronizado al principal. */
.map-minimapa {
  width: 150px;
  height: 150px;
  border-radius: var(--radius-md);
  border: 2px solid #fff;
  box-shadow: var(--shadow-modal);
  overflow: hidden;
  cursor: default;
}
.map-minimapa.map-dark .leaflet-tile-pane { filter: invert(1) hue-rotate(180deg) brightness(0.95) contrast(0.9); }
@media (max-width: 900px) { .map-minimapa { width: 110px; height: 110px; } }

/* Exportar vista del mapa (impresión a PDF): solo el mapa, sin sidebar ni el resto de la app. */
@media print {
  body.map-exportando > *:not(#app-shell) { display: none !important; }
  body.map-exportando .app-header,
  body.map-exportando .app-sidebar,
  body.map-exportando .app-footer,
  body.map-exportando .page-header,
  body.map-exportando .map-toolrail,
  body.map-exportando .map-toolpanel,
  body.map-exportando .leaflet-control-zoom,
  body.map-exportando .map-minimapa {
    display: none !important;
  }
  body.map-exportando .app-main { padding: 0 !important; margin: 0 !important; }
  body.map-exportando .map-page { display: block !important; }
  body.map-exportando #gis-map {
    width: 100% !important;
    height: 100vh !important;
    min-height: 0 !important;
    border: none !important;
    box-shadow: none !important;
  }
}

/* ============================================================
   CALENDARIO
   ============================================================ */
.calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
@media (max-width: 640px) {
  .calendar-grid { gap: 3px; }
  .calendar-cell { min-height: 56px; padding: 4px; font-size: 10.5px; }
  .calendar-day-name { font-size: 10px; }
  .calendar-event-chip { display: none; }
  .calendar-cell.has-events .day-number::after { content: ' •'; color: var(--color-primary-text); }
}
.calendar-day-name { text-align: center; font-size: 12px; color: var(--color-text-secondary); padding-bottom: 6px; font-weight: 600; }
.calendar-cell {
  min-height: 92px; border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  padding: 6px; font-size: 12px; background: var(--color-bg); cursor: pointer;
}
.calendar-cell:hover { border-color: var(--color-secondary); }
.calendar-cell.today { border-color: var(--color-primary); border-width: 2px; }
.calendar-cell.out-of-month { opacity: .4; }
.calendar-cell .day-number { font-weight: 700; margin-bottom: 4px; }
.calendar-cell .day-events { display: flex; flex-direction: column; gap: 2px; }
.calendar-event-chip {
  font-size: 10.5px; padding: 1px 5px; border-radius: 4px; background: var(--color-info-bg); color: var(--color-primary-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.calendar-event-chip.holiday { background: var(--color-danger-bg); color: var(--color-danger-text); }
.calendar-nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }

.mencion { color: var(--color-primary-text); font-weight: 600; background: var(--color-info-bg); padding: 0 3px; border-radius: 3px; }

/* Tickets: vista Kanban (alternativa a la tabla, arrastrar y soltar por estado) */
.kanban-board {
  display: grid;
  grid-template-columns: repeat(3, minmax(240px, 1fr));
  gap: 14px;
  align-items: start;
}
@media (max-width: 900px) { .kanban-board { grid-template-columns: 1fr; } }
.kanban-columna { background: var(--color-bg-alt); border-radius: var(--radius-md); border: 1px solid var(--color-border); display: flex; flex-direction: column; max-height: calc(100vh - 320px); min-height: 200px; }
.kanban-columna-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 12px; font-weight: 700; font-size: 13px; border-bottom: 1px solid var(--color-border); }
.kanban-columna-body { flex: 1; overflow-y: auto; padding: 8px; display: flex; flex-direction: column; gap: 8px; transition: background var(--transition-fast); }
.kanban-columna-body--sobre { background: var(--color-info-bg); }
.kanban-card {
  background: var(--color-bg); border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  padding: 10px; cursor: grab; box-shadow: var(--shadow-card);
}
.kanban-card:hover { border-color: var(--color-secondary); }
.kanban-card:focus-visible { outline: 3px solid var(--color-secondary); outline-offset: 2px; }
.kanban-card--arrastrando { opacity: .4; }

/* Sala de situación: modo pantalla completa para una pantalla dedicada de monitoreo. */
.situacion-page--fullscreen {
  position: fixed;
  inset: 0;
  z-index: 900;
  background: var(--color-bg);
  padding: 20px;
  overflow-y: auto;
}
/* Igual que .btn-map-fullscreen--flotante: en pantalla completa el contenido (fixed,
   z-index alto) cubre visualmente el .page-header donde vive el botón que la activó. */
.btn-fullscreen-flotante {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 950;
  box-shadow: var(--shadow-card);
}

/* Utilidades */
.flex { display: flex; }
.flex-between { display: flex; align-items: center; justify-content: space-between; }
.gap-8 { gap: 8px; } .gap-12 { gap: 12px; } .gap-16 { gap: 16px; }
.mt-8 { margin-top: 8px; } .mt-16 { margin-top: 16px; } .mt-24 { margin-top: 24px; }
.mb-0 { margin-bottom: 0; }
.text-center { text-align: center; }
.text-muted { color: var(--color-text-secondary); }
.text-danger { color: var(--color-danger-text); }
.w-100 { width: 100%; }

/* ============================================================
   IMPRESIÓN / REPORTES PDF (Ctrl+P sobre una vista ya filtrada)
   ============================================================ */
.print-only { display: none; }

@media print {
  .app-header, .app-sidebar, .app-footer, .skip-link,
  .filters-bar, .pagination-bar, .btn, .header-search,
  .modal-overlay, .toast-container, .global-search-results,
  .page-header select, .page-header .field {
    display: none !important;
  }
  .data-table:not(.data-table--sin-acciones) th:last-child,
  .data-table:not(.data-table--sin-acciones) td:last-child { display: none; }

  .app-main { margin-left: 0 !important; width: 100% !important; }
  .content-max { max-width: none !important; padding: 0 !important; }
  body { background: #fff !important; color: #000 !important; }
  .card, .table-wrap { box-shadow: none !important; border: 1px solid #999 !important; break-inside: avoid; }
  .badge { border: 1px solid currentColor; }

  .print-only { display: block; margin-top: 24px; padding-top: 12px; border-top: 1px solid #999; font-size: 11px; color: #555; }
}

/* ============================================================
   GUÍA DE ESTILO (solo administradores)
   ============================================================ */
.guia-swatch-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 14px; }
.guia-swatch { display: flex; flex-direction: column; gap: 6px; }
.guia-swatch-muestra {
  height: 52px; border-radius: var(--radius-sm); border: 1px solid var(--color-border);
  display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 18px;
}
.guia-swatch-meta { display: flex; flex-direction: column; font-size: 12px; }
.guia-swatch-meta code { font-size: 11px; color: var(--color-text-secondary); }

.guia-tipo-fila { display: flex; align-items: baseline; gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--color-border); }
.guia-tipo-fila:last-child { border-bottom: none; }
.guia-tipo-fila code { font-size: 12px; color: var(--color-text-secondary); font-weight: 400; }

.guia-radios { display: flex; gap: 16px; }
.guia-radio-muestra {
  width: 88px; height: 64px; background: var(--color-bg-alt); border: 1px dashed var(--color-border);
  display: flex; align-items: center; justify-content: center; text-align: center; font-size: 12px; color: var(--color-text-secondary);
}
.guia-sombras { display: flex; gap: 20px; }
.guia-sombra-muestra {
  width: 96px; height: 64px; background: var(--color-bg); border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--color-text-secondary);
}
.guia-transiciones { display: flex; gap: 20px; }
.guia-transicion-muestra {
  width: 96px; height: 64px; background: var(--color-primary); color: #fff; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center; font-size: 12px; cursor: default;
}
.guia-transicion-muestra:hover { transform: scale(1.08); }
