/* ═══════════════════════════════════════════
   LOGO DE MARCA
   El resto de la pantalla de login vive en css/login.css.

   Aquí había un bloque de login completo, superviviente del diseño
   anterior. Como components.css se carga DESPUÉS de login.css, sus
   reglas ganaban: el botón salía con degradado pese a definirse sólido
   en login.css, y la pantalla conservaba unos gradientes cian que
   login.css documenta como retirados a propósito ("el canvas los
   provee"). Se eliminó: .login-card, .login-logo-text, .login-hint,
   .form-group y .form-input no los usaba nadie; #login-screen,
   .btn-login y .login-error estaban duplicados y ahora los define
   solo login.css.
═══════════════════════════════════════════ */
.login-logo { display: flex; align-items: center; gap: 12px; margin-bottom: 28px; }
.login-logo-icon {
  width: 40px; height: 40px; border-radius: var(--radius-sm);
  background: var(--color-field);
  display: flex; align-items: center; justify-content: center;
}
.login-logo-icon svg { width: 22px; height: 22px; fill: var(--color-on-field); }

/* ═══════════════════════════════════════════
   SHARED COMPONENTS
═══════════════════════════════════════════ */

/* ── Page header ──
   Antetítulo versalita sobre un titular condensado grande, con las
   acciones alineadas a la línea base inferior. El <p> descriptivo
   pasa a hacer de antetítulo cuando lleva la clase .kicker. */
.page-header {
  margin-bottom: 20px; display: flex; align-items: flex-end;
  justify-content: space-between; gap: 14px; flex-wrap: wrap;
}
.page-header h1 {
  font-family: var(--font-heading);
  font-size: 38px; font-weight: 600;
  line-height: .95; letter-spacing: .01em;
}
.page-header p {
  font-size: 13px; color: var(--text2); margin-top: 6px; max-width: 84ch;
}
/* El antetítulo va ANTES del h1 en el marcado. */
.page-header .kicker {
  font-family: var(--font-heading);
  font-size: 10px; font-weight: 500;
  letter-spacing: var(--track-kicker); text-transform: uppercase;
  color: var(--color-text-3);
  margin: 0 0 4px;
}
.page-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* ── Stat cards ──
   Piezas en relieve: rótulo versalita, cifra condensada grande y una glosa en
   monoespaciada. Sin icono teñido: en este sistema el número es la figura.
   Dejaron de ser dibujos de línea el 2026-08-28 — ver la nota de `.card`. */
.stat-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  /* El hueco creció con el relieve: una sombra de 18px de difuminado necesita
     sitio para caer, y con 16px las de dos tarjetas contiguas se pisaban y la
     rejilla parecía una sola mancha. */
  gap: 26px; margin-bottom: 28px;
}
.stat-card {
  position: relative;
  /* El relieve exige que la pieza sea DEL MISMO color que el fondo: es lo que
     la hace parecer extruida y no pegada encima. Por eso `--color-bg` y no
     `--color-surface`, y por eso no lleva filete: la forma la dibujan las dos
     luces, y un borde encima las delata. */
  background: var(--color-bg); border: none;
  border-radius: var(--radius-card); padding: 16px 18px;
  box-shadow: var(--relieve-sm);
  display: flex; flex-direction: column; gap: 6px;
  transition: box-shadow var(--transition);
}
/* Al pasar por encima se hunde en vez de levantarse más. Es la única
   interacción que el relieve expresa bien, y de paso da un afordance que el
   filete de un píxel no daba. */
.stat-card:hover { box-shadow: var(--relieve-hundido); }
/* La tarjeta KPI del wireframe no lleva icono: la cifra es la figura,
   y un icono teñido de verde o ámbar metería color decorativo, que
   este sistema reserva para el acero. El marcado sigue emitiendo
   .stat-icon, así que se oculta aquí en vez de tocarlo en cada vista. */
.stat-icon { display: none; }
.stat-value {
  font-family: var(--font-heading);
  font-size: 42px; font-weight: 600;
  letter-spacing: 0; line-height: .9;
  order: 2;
}
.stat-label {
  font-family: var(--font-heading);
  font-size: 10px; font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--text2);
  order: 1;
}
.stat-delta {
  font-family: var(--font-mono);
  font-size: 10.5px; color: var(--text3);
  order: 3;
}
/* .stat-card envuelve valor/rótulo/glosa en un <div>; se aplana para
   que el orden de arriba gobierne los tres. */
.stat-card > div:not(.stat-icon) { display: contents; }

/* ── Card ──
   El panel del sistema. Cabecera versalita condensada sobre una pieza en
   relieve.

   Era un dibujo de línea —fondo transparente, filete de un píxel, esquinas
   rectas y marcas de registro— siguiendo la dirección «Industry 5b». Se cambió
   el 2026-08-28: a lo largo de una jornada, una pantalla entera resuelta sólo
   con filetes de un píxel cansa la vista, porque todo pesa lo mismo y nada
   agrupa. El relieve reintroduce jerarquía sin meter color.

   Las marcas de registro se retiraron de `.card` y `.stat-card` con el cambio:
   son cruces técnicas de esquina recta, y sobre una caja redondeada flotaban
   fuera del vértice. Siguen disponibles en la clase `.marcas` para quien las
   pida a propósito. */
.card {
  position: relative;
  background: var(--color-bg); border: none;
  border-radius: var(--radius-card);
  box-shadow: var(--relieve);
  /* Sigue en `visible` a propósito: dentro de las tarjetas hay desplegables
     posicionados en absoluto que un `hidden` recortaría. El contenido es
     transparente, así que las esquinas redondeadas se leen igual. */
  overflow: visible;
}
.card-header {
  padding: 13px 18px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.card-header h3 {
  font-family: var(--font-heading);
  font-size: 11.5px; font-weight: 600;
  letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--color-text-strong);
}
.card-header .sub { font-family: var(--font-mono); font-size: 10.5px; color: var(--text3); }
.card-body { padding: var(--card-pad); }

/* ── Buttons ──
   Rótulo condensado en versalitas, caja cuadrada de filete. El
   primario es el ÚNICO objeto macizo del área de trabajo: relleno de
   acento y texto en papel. Nada de traslación al pasar el cursor: en
   un wireframe los objetos no flotan, se tiñen. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 9px 16px; border: none;
  border-radius: var(--radius-sm); background: var(--color-bg);
  box-shadow: var(--relieve-sm);
  color: var(--text);
  font-family: var(--font-heading);
  font-size: 11.5px; font-weight: 600;
  letter-spacing: var(--track-micro); text-transform: uppercase;
  line-height: 1.2;
  cursor: pointer;
  transition: box-shadow var(--transition), background var(--transition), color var(--transition);
  user-select: none; white-space: nowrap;
}
.btn svg { stroke-width: 1.5; }
.btn:hover { box-shadow: var(--relieve); transform: none; }
/* Pulsar hunde la pieza. Es literalmente lo que hace un botón físico, y es la
   razón por la que el relieve compensa haber perdido el filete: el afordance
   pasa del contorno al volumen. */
.btn:active { box-shadow: var(--relieve-hundido); transform: none; }
.btn:disabled { opacity: .45; cursor: not-allowed; transform: none; box-shadow: var(--relieve-sm); }
/* ── Botón primario ──
   Cápsula que se levanta al pasar por encima y suelta un aro que se expande y
   se desvanece. Es la única acción de la pantalla que se comporta así: el
   relieve la separaba del fondo, pero no del resto de botones, y en un panel
   con ocho acciones hace falta saber cuál es LA acción.

   La referencia original resolvía el aro con un `::after` a `z-index: -1` del
   mismo color que el botón: al crecer, asoma por los bordes. Aquí NO funciona.
   Un `z-index` negativo pinta por detrás del fondo del contexto de apilamiento,
   y estos botones viven dentro de `.card`, que desde el paso al relieve tiene
   fondo opaco: el aro quedaría escondido debajo de la tarjeta. Se resuelve con
   el aro POR DELANTE y una animación, que además no tapa el rótulo porque
   empieza translúcido y sólo crece hacia fuera. */
.btn.primary {
  /* Imprescindible: sin esto el `::after` del aro se ancla al antepasado
     posicionado más cercano —la tarjeta— y se expande sobre el panel entero. */
  position: relative;
  background: var(--color-brand-fill);
  color: var(--color-on-brand);
  border-radius: var(--radius-pill);
  padding: 10px 22px;
  box-shadow: var(--relieve-sm);
  transition: transform var(--transition), box-shadow var(--transition),
              background var(--transition);
}
.btn.primary:hover {
  background: var(--color-brand-fill-hover);
  transform: translateY(-3px);
  box-shadow: var(--relieve), var(--shadow-lg);
}
.btn.primary:active {
  background: var(--color-brand-fill-pressed);
  transform: translateY(-1px);
  box-shadow: var(--relieve-sm), var(--shadow);
}

.btn.primary::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--color-brand-fill);
  opacity: 0;
  pointer-events: none;   /* el aro no debe robar el clic */
}
.btn.primary:hover::after { animation: aro-primario .55s ease-out; }

@keyframes aro-primario {
  from { opacity: .45; transform: scale(1); }
  to   { opacity: 0;   transform: scaleX(1.35) scaleY(1.7); }
}

/* Un primario pequeño conserva la cápsula pero no la holgura: `.btn.sm` define
   su relleno después, y sin esto el `padding` de arriba lo ganaba por
   especificidad y descuadraba las barras de herramientas. */
.btn.sm.primary { padding: 6px 14px; }

/* Quien pide menos movimiento se queda con el color y el volumen, que ya
   distinguen el botón de sobra; se va el desplazamiento y el aro. */
@media (prefers-reduced-motion: reduce) {
  .btn.primary:hover, .btn.primary:active { transform: none; }
  .btn.primary:hover::after { animation: none; }
}
/* Las variantes de estado se quedan en filete teñido: sólo el
   primario es macizo, o dejarían de leerse como un solo sistema. */
.btn.success { color: var(--green); }
.btn.success:hover { background: var(--green-dim); box-shadow: var(--relieve); }
.btn.danger  { color: var(--red);   }
.btn.danger:hover { background: var(--red-dim); box-shadow: var(--relieve); }
.btn.amber   { color: var(--amber); }
.btn.amber:hover { background: var(--amber-dim); box-shadow: var(--relieve); }
.btn.sm { padding: 5px 10px; font-size: 10px; }

/* ── Badge ──
   Etiqueta teñida desde la rampa. SIN relieve, y no por olvido: mide unos
   20px de alto, y una sombra de 12px de difuminado alrededor de una pieza de
   ese tamaño no lee como volumen, lee como suciedad. El color ya la separa. */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--radius-xs);
  font-size: 11px; font-weight: 500; letter-spacing: .02em;
  border: 1px solid transparent;
}
.badge.sky   { background: var(--sky-dim);   color: rgb(var(--p-steel-800-rgb)); border-color: rgb(var(--p-brand-rgb) / .25); }
.badge.green { background: var(--green-dim); color: var(--green); border-color: rgb(var(--p-green-rgb) / .25); }
.badge.red   { background: var(--red-dim);   color: var(--red);   border-color: rgb(var(--p-red-rgb) / .25); }
.badge.amber { background: var(--amber-dim); color: var(--amber); border-color: rgb(var(--p-amber-rgb) / .25); }

/* ── Table ──
   Cabecera versalita condensada sobre el papel, reglas interiores un
   paso más claras que el filete del panel, y los DATOS de identidad
   —patente, IMEI, fecha— en monoespaciada (clase .dato). */
/* La envoltura NO lleva relieve: vive dentro de una `.card` que ya lo trae, y
   dos relieves anidados se anulan — el ojo pierde cuál es la superficie. */
.table-wrap {
  border-radius: var(--radius-sm); border: 1px solid var(--border);
  overflow: auto; max-height: 520px;
}
table { width: 100%; border-collapse: collapse; }
thead th {
  position: sticky; top: 0; background: var(--color-bg);
  padding: 9px 18px; text-align: left;
  font-family: var(--font-heading);
  font-size: 9.5px; font-weight: 500;
  letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--text2); border-bottom: 1px solid var(--color-rule-strong);
  white-space: nowrap; z-index: 1;
}
tbody td { padding: var(--row-pad); font-size: 13px; border-bottom: 1px solid var(--color-rule); vertical-align: middle; }
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover td { background: var(--color-surface-glass); }

/* Datos de identidad y medida, dondequiera que aparezcan.
   No parten nunca a mitad de valor: una patente o un RUT cortado en
   dos líneas deja de leerse como un identificador. */
.dato, td .dato, .mono {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0;
  white-space: nowrap;
}

/* ── Columna de acciones anclada a la derecha ──────────────────────────────
   Las cuatro tablas del panel terminan en «Acciones». Cuando la tabla es más
   ancha que su contenedor, esa columna se salía del área visible: el botón de
   editar quedaba con 0 px a la vista y sólo se alcanzaba descubriendo una barra
   de scroll de 4 px. Anclada, permanece accesible a cualquier ancho.

   El fondo tiene que ser opaco —si no, el contenido pasa por debajo y se lee
   encima— y los bordes se dibujan con box-shadow porque border-collapse:collapse
   se los come a las celdas posicionadas.
   ───────────────────────────────────────────────────────────────────────── */
.table-wrap thead th:last-child,
.table-wrap tbody td:last-child {
  position: sticky;
  right: 0;
  background: var(--color-surface);
  box-shadow: inset 1px 0 0 var(--color-border),
              inset 0 -1px 0 var(--color-border);
}
.table-wrap thead th:last-child {
  background: var(--color-surface-2);
  z-index: 3;               /* por encima de la cabecera fija (1) y de las celdas (2) */
}
.table-wrap tbody td:last-child { z-index: 2; }
.table-wrap tbody tr:last-child td:last-child { box-shadow: inset 1px 0 0 var(--color-border); }

/* El resaltado de fila se apila sobre el fondo opaco de la celda anclada,
   porque una celda sticky no puede ser translúcida. */
.table-wrap tbody tr:hover td:last-child {
  background:
    linear-gradient(var(--color-surface-glass), var(--color-surface-glass)),
    var(--color-surface);
}

/* Una cadena larga sin espacios —un RUT mal pegado, un token— ensanchaba la
   tabla en cientos de píxeles.
   break-word y no anywhere: anywhere deja que la celda reduzca su ancho mínimo,
   y el navegador aprovecha para partir también los valores normales —la patente
   TEST01 salía como «TEST0 / 1» y el IMEI en tres líneas—. break-word sólo
   interviene cuando la palabra de verdad no cabe.

   El max-width acota cuánto puede estirarse una celda por su contenido: con una
   cadena de 50 caracteres la tabla pasaba de 831 a 1235 px y ahora se queda en
   1041. No la contiene del todo —el algoritmo de tabla puede ignorar max-width—
   pero eso ya no hace daño: la columna de acciones va anclada. */
.table-wrap tbody td { overflow-wrap: break-word; max-width: 260px; }

/* La barra de scroll global mide 4 px, suficiente para un scroll vertical
   discreto pero invisible cuando es el único indicio de que hay columnas
   ocultas a la derecha. */
.table-wrap::-webkit-scrollbar { width: 9px; height: 9px; }
.table-wrap::-webkit-scrollbar-thumb { background: var(--color-border-heavy); }
.table-wrap::-webkit-scrollbar-thumb:hover { background: var(--color-scrollbar-hover); }

/* ── Input / textarea ──
   HUNDIDOS, al revés que los botones. Es la mitad del sistema que hace que el
   relieve signifique algo: si todo sobresale, nada sobresale. Un campo es un
   hueco donde se deja algo; una pieza que se levanta invita a pulsarla. */
.input, .textarea {
  width: 100%; background: var(--color-bg); border: none;
  border-radius: var(--radius-sm); color: var(--text); padding: 9px 12px;
  min-height: 40px;
  box-shadow: var(--relieve-hundido);
  font-size: 13.5px; font-family: inherit; outline: none;
  transition: box-shadow var(--transition), outline-color var(--transition);
  appearance: none; -webkit-appearance: none;
}
.input::placeholder, .textarea::placeholder { color: var(--text3); }
.input:hover, .textarea:hover { background: var(--color-bg); }
/* El foco conserva el contorno de acento del kit: es el único indicador que
   funciona para quien navega con teclado, y una sombra no lo sustituye. */
.input:focus, .textarea:focus {
  outline: 2px solid var(--color-brand);
  outline-offset: 1px;
  box-shadow: var(--relieve-hundido);
  background: var(--color-bg);
}
select.input {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%237a7a7d' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
  padding-right: 32px; cursor: pointer;
}
select.input:focus { border-color: var(--color-brand); box-shadow: none; }
select.input option { background: var(--color-bg); color: var(--color-text); }
.textarea { min-height: 100px; resize: vertical; }
/* La etiqueta de campo es versalita condensada, como en el kit. */
.label {
  display: block;
  font-family: var(--font-heading);
  font-size: 10px; font-weight: 500;
  letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--text2); margin-bottom: 7px;
}

/* Search bar */
.search-bar {
  display: flex; align-items: center; gap: 9px;
  background: var(--color-bg); border: none;
  border-radius: var(--radius-sm); padding: 0 12px; min-height: 34px;
  box-shadow: var(--relieve-hundido);
}
.search-bar:focus-within { outline: 2px solid var(--color-brand); outline-offset: 1px; }
.search-bar svg { width: 15px; height: 15px; color: var(--text3); flex-shrink: 0; stroke-width: 1.5; }
.search-bar input {
  border: none; background: transparent; outline: none;
  color: var(--text); font-size: 12.5px; font-family: inherit;
  flex: 1; min-width: 120px; padding: 7px 0;
}
.search-bar input::placeholder { color: var(--text3); }

/* Empty state */
.empty-state { text-align: center; padding: 60px 20px; color: var(--text2); }
.empty-state svg { width: 40px; height: 40px; margin-bottom: 14px; opacity: .35; stroke-width: 1.5; }
.empty-state p { font-size: 14px; }
.empty-state small { font-family: var(--font-mono); font-size: 11px; color: var(--text3); }

/* Toast */
#toast {
  position: fixed; right: 20px; bottom: 20px; z-index: 200;
  background: var(--color-bg); border: none;
  border-radius: var(--radius); padding: 13px 18px; min-width: 260px;
  box-shadow: var(--relieve), var(--shadow-lg);
  box-shadow: var(--shadow); animation: slideUp .2s ease; display: none;
}
#toast.show { display: block; }
#toast strong {
  font-family: var(--font-heading);
  font-size: 11.5px; font-weight: 600;
  letter-spacing: var(--track-label); text-transform: uppercase;
}
#toast p { font-size: 12.5px; color: var(--text2); margin-top: 3px; }
@keyframes slideUp {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ═══════════════════════════════════════════
   MODAL — scroll controlado en todas las modales
═══════════════════════════════════════════ */
.modal-overlay {
  position: fixed; inset: 0; z-index: 80;
  background: var(--color-scrim); backdrop-filter: blur(4px);
  display: none; align-items: center; justify-content: center;
  padding: 16px;
}
.modal-overlay.show { display: flex; }

.modal {
  width: min(600px, 100%);
  background: var(--color-bg);
  border: none;
  border-radius: var(--radius-card);
  /* La modal conserva la sombra proyectada CLÁSICA además del relieve: flota
     sobre un velo oscuro, y ahí el relieve solo no basta para despegarla del
     fondo — necesita proyectar. */
  box-shadow: var(--relieve), var(--shadow-lg);
  animation: fadeIn .2s ease;
  /* ── Scroll controlado ── */
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Las modales que enseñan una TABLA —historial de cambios, unidades sin
   destino, certificados— no caben en 600px. Es lo único que cambia respecto a
   `.modal`: el resto del contrato (fondo, filete, esquinas rectas, scroll
   controlado) se hereda, que es justamente lo que se perdía cuando cada una
   se dibujaba con estilos en línea. */
.modal.ancha { width: min(900px, 100%); }

.modal-header {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between;
  flex-shrink: 0;   /* no se comprime */
}
.modal-header h3 {
  font-family: var(--font-heading);
  font-size: 12px; font-weight: 600;
  letter-spacing: var(--track-label); text-transform: uppercase;
}

.modal-body {
  padding: 18px;
  display: grid;
  gap: 14px;
  overflow-y: auto;   /* scroll cuando el contenido es largo */
  flex: 1;            /* ocupa el espacio restante */
  min-height: 0;      /* necesario para que flex+overflow funcione en todos los browsers */
}

.modal-footer {
  padding: 14px 18px;
  border-top: 1px solid var(--border);
  display: flex; gap: 8px; justify-content: flex-end;
  flex-shrink: 0;   /* no se comprime */
}

/* Divider — el sistema prefiere el blanco; usar sólo donde ya estaba. */
.hr { height: 1px; background: var(--color-rule-strong); margin: 16px 0; }

/* Toolbar */
.toolbar {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; margin-bottom: 16px;
}
.toolbar-right { margin-left: auto; display: flex; gap: 8px; align-items: center; }

/* Mono — el alias antiguo apunta ya al token del sistema. */
.mono { font-family: var(--font-mono); }


/* ═══════════════════════════════════════════
   MODAL DESTINOS / INTEGRACIONES
   (generada dinámicamente en _openDestModalBase)
═══════════════════════════════════════════ */
.dest-modal-shell {
  width: min(940px, 96vw);
  background: var(--color-bg);
  border: none;
  border-radius: var(--radius-card);
  box-shadow: var(--relieve), var(--shadow-lg);
  display: flex;
  flex-direction: column;
  max-height: 88vh;
  overflow: hidden;
  animation: fadeIn .2s ease;
}
.dest-modal-header {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;
  gap: 12px;
}
.dest-modal-content {
  display: flex;
  flex: 1;
  overflow: hidden;
  min-height: 0;
}
.dest-modal-sidebar {
  width: 200px;
  flex-shrink: 0;
  border-right: 1px solid var(--border);
  overflow-y: auto;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.dest-modal-body {
  flex: 1;
  overflow-y: auto;
  padding: 18px;
  min-width: 0;
}

/* Botones del sidebar */
.dest-sidebar-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  background: transparent;
  cursor: pointer;
  text-align: left;
  width: 100%;
  font-family: inherit;
  transition: background var(--transition), border-color var(--transition);
}
.dest-sidebar-btn:hover {
  background: var(--color-surface-glass-strong);
  border-color: var(--border);
}
.dest-sidebar-btn.active {
  background: var(--sky-dim);
  border-color: rgb(var(--p-brand-rgb) / .2);
}
.dest-sidebar-dot {
  width: 8px;
  height: 8px;
  border-radius: 0;
  flex-shrink: 0;
}
.dest-sidebar-name {
  flex: 1;
  font-size: 12px;
  font-weight: 500;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.dest-sidebar-count {
  font-size: 11px;
  color: var(--text3);
  flex-shrink: 0;
}

/* Stats del detalle */
.dest-detail-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 14px;
}
.dest-stat-card {
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
}
.dest-stat-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .5px;
  text-transform: uppercase;
  color: var(--text3);
  margin-bottom: 5px;
}
.dest-stat-value {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
}
.dest-stat-sub {
  font-size: 12px;
  color: var(--sky);
  margin-top: 3px;
}

/* ═══════════════════════════════════════════
   TABLA DE CAMPOS GPS (orgs.js)
═══════════════════════════════════════════ */
.field-row-grid {
  display: grid;
  grid-template-columns: 22px 1fr 1fr 1fr 68px 30px;
  gap: 6px;
  align-items: center;
  padding: 5px 6px;
  border-radius: var(--radius-sm);
  transition: background var(--transition);
}
.field-row-grid:hover {
  background: var(--color-surface-glass);
}
.drag-handle {
  color: var(--text3);
  cursor: grab;
  font-size: 14px;
  text-align: center;
  padding-top: 1px;
  user-select: none;
}
.drag-handle:active { cursor: grabbing; }
.drag-handle:hover { color: var(--text2); }

/* Select de fuente GPS — colores por categoría */
.src-gps    { background: var(--sky-glow)   !important; border-color: rgb(var(--p-brand-rgb) / .2)  !important; }
.src-unit   { background: var(--green-dim)  !important; border-color: rgb(var(--p-green-rgb) / .2)  !important; }
.src-fixed  { background: var(--amber-dim)  !important; border-color: rgb(var(--p-amber-rgb) / .2)  !important; }

/* Required toggle */
.req-toggle {
  font-size: 11px;
  padding: 4px 6px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border2);
  background: transparent;
  color: var(--text3);
  cursor: pointer;
  width: 100%;
  font-family: inherit;
  transition: background var(--transition), color var(--transition);
  text-align: center;
}
.req-toggle.on {
  background: var(--sky-dim);
  border-color: rgb(var(--p-brand-rgb) / .3);
  color: var(--sky);
}

/* Vista previa del payload */
.payload-preview {
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.7;
  color: var(--sky);
  background: var(--bg2);
  border: 1px solid var(--border);
  padding: 14px 16px;
  border-radius: var(--radius-sm);
  overflow-x: auto;
  margin: 0;
}

/* Leyenda de fuentes */
.source-legend {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  padding: 8px 12px;
  background: var(--bg2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-bottom: 12px;
}
.source-legend-item {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: var(--radius-sm);
  font-weight: 500;
}

/* ═══════════════════════════════════════════
   Combo buscable (searchable select)
   Estaba inyectado desde js/app/12-destinos-modal.js con
   createElement('style'); movido aquí sin cambios de aspecto.
   Corregido de paso var(--text1), que no existe en tokens.css
   —el color caía por herencia— por var(--text).
   ═══════════════════════════════════════════ */
.sf-wrap { position: relative; }

.sf-input {
  width: 100%; padding: 7px 10px; font-size: 13px;
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: var(--radius-sm); color: var(--text);
  cursor: pointer; box-sizing: border-box;
}
.sf-input:focus { outline: none; border-color: var(--sky); }

.sf-dropdown {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0;
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: var(--radius-sm); z-index: 999;
  max-height: 220px; overflow-y: auto;
  box-shadow: var(--shadow);
  display: none;
}
.sf-dropdown.open { display: block; }

.sf-option {
  padding: 8px 12px; font-size: 13px; cursor: pointer;
  color: var(--text); white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; transition: background .1s;
}
.sf-option:hover,
.sf-option.active { background: var(--surface3, var(--color-border)); }
.sf-option.placeholder { color: var(--text3); font-style: italic; }

/* ═══════════════════════════════════════════
   INTERRUPTOR DE TEMA — claro / oscuro
   Basado en el switch de Uiverse.io de satyamchaudharydev.
   Los colores viven en tokens.css como --p-switch-*: son sol y luna,
   no siguen la paleta del sistema y no cambian con el tema.
═══════════════════════════════════════════ */
.switch {
  display: block;
  --width-of-switch: 3.5em;
  --height-of-switch: 2em;
  /* tamaño del icono deslizante — sol y luna */
  --size-of-icon: 1.4em;
  /* hace de padding interior del carril */
  --slider-offset: 0.3em;
  position: relative;
  width: var(--width-of-switch);
  height: var(--height-of-switch);
  /* El interruptor vive en una topbar de 11px; sin esto heredaría ese
     tamaño y los `em` lo dejarían diminuto. */
  font-size: 11px;
  flex-shrink: 0;
}

/* Oculta el checkbox nativo sin sacarlo del árbol de accesibilidad:
   sigue siendo el control real, recibe foco y responde al teclado. */
.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

.slider {
  position: absolute;
  cursor: pointer;
  top: 0; left: 0; right: 0; bottom: 0;
  background-color: rgb(var(--p-switch-track-rgb));
  transition: .4s;
  border-radius: 30px;
}

.slider:before {
  position: absolute;
  content: "";
  height: var(--size-of-icon, 1.4em);
  width:  var(--size-of-icon, 1.4em);
  border-radius: 20px;
  left: var(--slider-offset, 0.3em);
  top: 50%;
  transform: translateY(-50%);
  background: linear-gradient(40deg,
              rgb(var(--p-switch-sun-a-rgb)),
              rgb(var(--p-switch-sun-b-rgb)) 70%);
  transition: .4s;
}

.switch input:checked + .slider {
  background-color: rgb(var(--p-switch-track-on-rgb));
}

.switch input:checked + .slider:before {
  left: calc(100% - (var(--size-of-icon, 1.4em) + var(--slider-offset, 0.3em)));
  background: rgb(var(--p-switch-track-on-rgb));
  /* El segundo inset talla la luna: cambiar su desplazamiento cambia
     la fase y la dirección del creciente. */
  box-shadow: inset -3px -2px 5px -2px rgb(var(--p-switch-moon-a-rgb)),
              inset -10px -4px 0 0   rgb(var(--p-switch-moon-b-rgb));
}

/* El foco no puede quedarse en el checkbox invisible: se traslada al
   carril, que es lo que el usuario ve. */
.switch input:focus-visible + .slider {
  outline: 2px solid var(--color-brand);
  outline-offset: 2px;
}

/* Respeta a quien pide menos movimiento. */
@media (prefers-reduced-motion: reduce) {
  .slider, .slider:before { transition: none; }
}

/* Multiempresa: lo que es sólo de la plataforma (auditoría, snapshots, roles)
   no se le pinta a un usuario de empresa. La API se lo negaría igualmente. */
body.es-empresa .solo-plataforma { display: none !important; }
/* Y al revés: lo que sólo tiene sentido dentro de una empresa. */
body:not(.es-empresa) .solo-empresa { display: none !important; }
