/* PALETA ÚNICA DE LA SPA — tema HMI High-Performance / ISA-101 (doc 12 §2), valores del
   `docs/PLAN-UX-LIVE-BANDAS.md` §6.2 (paso 1 de su §8).

   Norma que no cambia con el tema: campo gris de bajo contraste (nunca blanco puro — deslumbra y le roba
   contraste al ámbar), el COLOR se reserva al estado, y el estado NUNCA va solo por color: lleva glifo y
   etiqueta de texto (§6.3 del plan: bajo deuteranopía el verde y el rojo convencionales se separan 2,1
   sobre 100, o sea el mismo color; re-escalonados llegan a 6,7 y siguen sin alcanzar solos).

   ESTE ES EL ÚNICO ARCHIVO CON PALETA. Antes eran dos —`shared/ui/tokens.css` traía un segundo
   vocabulario `--campo-*` para las mismas superficies— y dos vocabularios para una sola pregunta es el
   patrón que este repo ya pagó seis veces. Fuera de acá no hay color: lo fija la guarda G-1 de
   `sistemaDeDiseno.test.ts` (ADR-0062), con su lista de deuda y sus excepciones técnicas (el mapa pinta en
   un lienzo donde `var()` no se evalúa). Sobre el acento va `--field`, nunca `#fff`: el acento cambia con
   el tema y en oscuro es claro.

   Los contrastes de abajo están MEDIDOS contra la superficie donde el token se usa, no estimados, y los
   fija ese mismo test: un valor que se retoca a ojo deja de cumplir sin que nadie se entere. */
:root {
  /* ---- Superficies. De atrás hacia adelante: lienzo → panel → encabezado → campo de dato. ---- */
  --canvas: #d5d9dd; /* fondo de la app */
  --surface: #e3e7ea; /* panel, rail, cabecera */
  --surface-2: #edf0f2; /* encabezado de tabla, ítem activo */
  --field: #f7f8f9; /* fila de dato, input */
  --line: #b4bcc3; /* borde estructural */
  --line-soft: #c9d0d6; /* separador de filas */

  /* ---- Tinta. Tres niveles y no más: valor, texto corriente, etiqueta. ---- */
  --ink: #161b20; /* 13,9:1 — valores y títulos */
  --ink-2: #3f4a53; /* 7,3:1  — texto corriente */
  /* ⚠ Deliberadamente más oscuro que un "muted" habitual: la unidad y la marca de tiempo se leen de
     reojo, así que pasan 4,5:1 incluso sobre el LIENZO, que es la superficie más exigente (4,58:1). */
  --ink-3: #565f67;

  /* ---- Acento: UNO SOLO (principio 2 del plan §6.1). ----
     Acá vivían dos azules de interacción, `--info` (#1c5fb0) y `--accent` (#4a90d9), y ninguna regla
     sabía cuál le tocaba. Se funden en éste, que es el que pasa 6,1:1 sobre el panel. */
  --accent: #14549c;
  /* Variación con signo (`BarrasConSigno`, v1.40): verde si sube, rojo si baja. Propios a propósito, no --operativo ni
     --falla: una variación de producción no es un estado ni una alarma. ≥ 4,5:1 sobre --surface. */
  --variacion-sube: #2e7d32;
  --variacion-baja: #b3261e;
  /* Modo Configuración (D-NAV-6). Violeta a propósito: no es ningún estado de HP-HMI (verde, azul, ámbar, rojo, gris), así
     que la banda no se lee como alarma ni como «parado». 7,0:1 sobre --surface. */
  --modo-config: #5b3f8f;

  /* ---- Estado. Cinco, y son los cinco de `EstadoPresentacion` (Parado: dueño 2026-10-04). ----
     El color es el TERCER canal (glifo + etiqueta primero). Los valores están re-escalonados —verde
     corrido al azul-verde, rojo hundido en luminosidad— justamente para que la severidad se codifique
     también en luminancia y no sólo en tono. */
  --operativo: #00734a; /* círculo lleno */
  --parado: #1f5fa6; /* cuadrado — azul: detenido sin falla; el gris ya es «sin comunicación» */
  --desconocido: #a87400; /* triángulo */
  --falla: #a01a12; /* rombo */
  --sincom: #6b7580; /* círculo lleno gris oscuro — gris a propósito: es la AUSENCIA de estado */

  /* ---- Interacción y superficies derivadas (no las fija §6.2; valores heredados del módulo CAMPO). ---- */
  --hover: #e2e6e9; /* fila/nodo bajo el cursor */
  --sel: #d7e3ee; /* seleccionado */
  --sel-border: #9db8cf;
  --overlay: rgba(22, 27, 32, 0.55); /* velo del modal, derivado de --ink */
  /* El anillo de foco se DERIVA del acento en vez de repetirlo: era un tercer azul escrito a mano. */
  --focus-ring: 0 0 0 2px color-mix(in srgb, var(--accent) 55%, transparent);

  /* ---- Tintes de estado: fondo del tono + tinta del mismo tono. ----
     Son token y no literal porque un tinte claro sobre fondo oscuro es ilegible: son exactamente los
     valores que el tema tiene que dar vuelta, y en las barras de umbral el color ES el dato. */
  --tinte-warn-ink: #8a5a10;
  --tinte-warn-bg: #fbf3e2;
  --tinte-warn-border: #e0c48a;
  --zona-ok: #cfe8cf;
  --zona-warn: #f3e2b3;
  --zona-alarm: #efc7c2;
  --lote: #f5a623; /* límites de lote (capa PERUPETRO del mapa), sobre satélite */
  --lote-etiqueta: #00e5ff; /* nombre del lote sobre el mapa: cian, se lee sobre el desierto */
  /* Límite de lote sobre el mapa base neutro de *Ahora* (rediseño 2026-10-25): gris fino, no compite con el estado. */
  --mapa-limite: #6f7a84;
  /* Borde del marcador del pozo: lo separa del mapa base, satelital o neutro. Blanco en los dos temas (2026-10-28). */
  --mapa-marcador-borde: #ffffff;

  /* ---- Métrica: UNA escala de espaciado y UNA de radios (paso 1 del plan §8). ----
     Había `--radius: 4px` conviviendo con `--radius-sm: 4px` y `--radius-md: 6px`: dos nombres para el
     mismo píxel. Queda la escala sm/md y `--gap` deja de ser un tercer 12 px suelto. */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --radius-sm: 4px;
  --radius-md: 6px;
  /* Marcador del mapa: 16 px de partida; `IntegratedMap` lo cambia sobre el lienzo según el zoom (2026-10-28). */
  --tam-marcador: 16px;
  --gap: var(--sp-3);

  /* Dos niveles de elevación, discreta y nunca dramática (principio 4: densidad con aire). */
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.08);
  --shadow-2: 0 2px 8px rgba(0, 0, 0, 0.12);

  /* Transiciones ≤120 ms que NUNCA tocan un valor numérico (principio 4). */
  --t-fast: 120ms ease;
  --t-med: 150ms ease;

  /* Íconos que trae dibujados una librería (el zoom de MapLibre: gris #333 en una imagen, no en `color`). En claro van
     como vienen; en oscuro se dan vuelta para que no se pierdan sobre el panel. */
  --filtro-icono-ajeno: none;

  /* Tipografía. */
  /* IBM Plex Sans (dueño 2026-10-23): diseñada para interfaces técnicas, cifras de ancho fijo y la «l» y el «1» que no se
     confunden. Se sirve desde la app (@fontsource, main.tsx); las demás son el respaldo si el archivo no carga. */
  --font-ui:
    'IBM Plex Sans', 'Segoe UI Variable', 'Segoe UI', system-ui, -apple-system, Roboto, sans-serif;
  --fs-sm: 12px;
  --fs-md: 13px;
  --fs-lg: 15px;
  --fs-xl: 18px;

  font-family: var(--font-ui);
  color-scheme: light;
}

/* ISA OSCURO. No es "el claro invertido": los tonos de estado se ACLARAN, porque un rojo #a01a12 sobre
   fondo oscuro pierde justamente el contraste que lo hace leerse como alarma.

   `color-scheme: dark` no es decorativo: sin él, los controles nativos (select, checkbox, scrollbar) y
   el autocompletado del navegador siguen pintándose claros y quedan como parches blancos.

   🔴 EL SELECTOR VA EN CASTELLANO Y NO ES UNA PREFERENCIA DE ESTILO. Este bloque se escribió una vez
   como `[data-theme='dark']` y estuvo MUERTO desde que se entregó: `aplicarTema()` escribe en
   `data-theme` el valor del catálogo (`ui.tema` de V0029, que vale `claro`/`oscuro`), así que `dark` no
   matcheaba nunca. El nombre del selector no es nuestro: es DATO, y lo elige el catálogo. */
:root[data-theme='oscuro'] {
  --canvas: #1a1d21;
  --surface: #23272b;
  --surface-2: #2c3136;
  --field: #16191c;
  --line: #3d444b;
  --line-soft: #31373d;

  --ink: #e8ebed; /* 12,6:1 */
  --ink-2: #b0b8bf; /* 7,5:1 */
  --ink-3: #8b949c; /* 4,9:1 */

  --accent: #5b9bd5; /* 5,1:1 */
  --variacion-sube: #66bb6a;
  --variacion-baja: #ef6b5e;
  --modo-config: #b9a6e8; /* 6,8:1 */

  --operativo: #2bb894;
  --parado: #5b9bd5;
  --desconocido: #dfa63c;
  --falla: #f2564a;
  --sincom: #79838c;

  --hover: #33383c;
  --sel: #2d3d4c;
  --sel-border: #4a6a86;
  --overlay: rgba(0, 0, 0, 0.65);

  --tinte-warn-ink: #e8c07d;
  --tinte-warn-bg: #3a3222;
  --tinte-warn-border: #6b5a33;
  --zona-ok: #2c4a2e;
  --zona-warn: #4d4426;
  --zona-alarm: #4d2e2b;
  --lote: #f5a623; /* límites de lote (capa PERUPETRO del mapa), sobre satélite */
  --lote-etiqueta: #00e5ff; /* nombre del lote sobre el mapa: cian, se lee sobre el desierto */
  --mapa-limite: #8b949c;
  --mapa-marcador-borde: #ffffff;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-2: 0 2px 8px rgba(0, 0, 0, 0.55);

  --filtro-icono-ajeno: invert(0.85);

  color-scheme: dark;
}

/* SISTEMA — el tercer tema (D-UX-4). No tiene paleta propia a propósito: `aplicarTema()` pregunta al SO
   con `matchMedia` y escribe el tema RESUELTO en `data-theme`, así que acá abajo siguen habiendo dos
   paletas y no tres. Duplicar el bloque oscuro dentro de un `@media (prefers-color-scheme: dark)` sería
   un segundo lugar donde vive el mismo color, que es lo que este paso vino a eliminar.
   Lo que el plan §6.4 pide del SO además de claro/oscuro —`forced-colors` y `AccentColor` con reserva—
   es el paso 7 y todavía no está. */

/* Foco visible de los controles del módulo CAMPO. Viene de `shared/ui/tokens.css`, que se fundió acá.
   ⚠ Conserva su alcance `.campo` a propósito: extenderlo a toda la SPA suena a mejora pero cambia el
   comportamiento —`outline: none` global y un radio impuesto a todo lo que reciba foco, incluido lo
   redondo— y este paso unifica la PALETA, no el foco. Sale del paso 3 (shell nuevo), que reescribe estas
   pantallas de todos modos. */
.campo :focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}

* {
  box-sizing: border-box;
}

html,
body,
#root {
  margin: 0;
  height: 100%;
}

body {
  background: var(--canvas);
  color: var(--ink);
  font-size: 14px;
}

a {
  color: var(--accent);
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}

/* El tamaño de la consola en esta pantalla (`escalaPantalla.ts`, dueño 2026-10-23): todo crece en la misma proporción.
   `zoom` en la raíz agranda también los portales y el mapa. Lo que se mide en `vh` también se agranda, y se saldría de la
   pantalla: por eso las alturas relativas a la pantalla usan `--alto-pantalla`, que divide por la escala, y nunca `vh`. */
:root {
  --alto-pantalla: 100vh;
}
:root[data-escala='grande'] {
  zoom: 1.25;
  --alto-pantalla: calc(100vh / 1.25);
}
:root[data-escala='muy_grande'] {
  zoom: 1.5;
  --alto-pantalla: calc(100vh / 1.5);
}

/* Los controles de texto nativos toman el tema (ADR-0062 §2.5: un control que no lo toma es defecto del sistema). Una
   regla de pantalla que les pone borde les quita la apariencia nativa y el navegador los pintaba claros en el oscuro
   (búsqueda de Alarmas, 2026-10-23). `:where()` deja la especificidad en cero: cualquier clase de pantalla sigue ganando. */
:where(
  input:not([type='checkbox'], [type='radio'], [type='range'], [type='color']),
  select,
  textarea
) {
  background-color: var(--field);
  color: var(--ink);
}

/* Tonos de calidad/severidad (NE 107). El texto lleva SIEMPRE etiqueta, no solo color. */
.tone-normal {
  color: var(--ink);
}
.tone-warn {
  color: var(--desconocido);
}
.tone-alarm {
  color: var(--falla);
}
.tone-muted {
  color: var(--ink-3);
}

/* Un valor no-fresco se atenúa (no se pinta como fresco). */
.is-stale {
  opacity: 0.62;
  font-style: italic;
}

/* Layout del shell. */
/* Shell de dos niveles (paso 3 del plan §8): cabecera + cajón + contenido.
   La rejilla tiene DOS columnas y el cajón ocupa la primera; cerrarlo es llevar esa columna a 0, no
   desmontar el nodo. Así el cajón anima, conserva su estado y el lector de pantalla no ve aparecer y
   desaparecer un `<nav>` entero cada vez.
   El objetivo de diseño es 1366 × 768 (D-UX-5): con la barra del navegador quedan ~600 px de alto útil,
   así que la cabecera es de una línea y el alto lo consume el contenido, no la navegación. */
.app {
  display: grid;
  grid-template-rows: auto 1fr;
  grid-template-columns: 0 1fr;
  height: 100%;
  transition: grid-template-columns var(--t-med);
}
.app[data-cajon='fijo'] {
  /* 200 px (antes 220): el ancho que cede el menú va al contenido (dueño 2026-10-27). */
  grid-template-columns: 200px 1fr;
}

/* El ícono que abre y cierra (regla 1). */

/* Conmutador de módulo (D-UX-1). Los tres siempre presentes: OPS sin licencia es vitrina, no un hueco. */
.modulos {
  display: flex;
  gap: var(--sp-1);
  margin-left: var(--sp-2);
}
.modulos .modulo {
  padding: var(--sp-1) var(--sp-3);
  border-radius: var(--radius-sm);
  color: var(--ink-2);
  font-weight: 600;
}
.modulos .modulo:hover {
  background: var(--hover);
  text-decoration: none;
}
.modulos .modulo.sel {
  background: var(--sel);
  border-bottom: 2px solid var(--accent);
  color: var(--ink);
}

/* Conmutador de módulo convergente para pantallas pequeñas (móvil) */

/* Menú de 3 puntitos para usuario y salida en pantallas pequeñas */

/* El cajón. Overflow oculto para que el contenido no se derrame cuando la columna vale 0. */
.cajon {
  overflow: hidden auto;
  background: var(--surface);
  border-right: 1px solid var(--line);
}
.cajon ul {
  list-style: none;
  margin: 0;
  padding: var(--sp-2) 0;
}
.cajon li {
  white-space: nowrap;
}
.cajon a,
.cajon-grupo {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--sp-3);
  width: 100%;
  padding: var(--sp-2) var(--sp-4);
  color: var(--ink-2);
  background: none;
  border: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.cajon a:hover,
.cajon-grupo:hover {
  background: var(--hover);
  text-decoration: none;
}
.cajon a.sel {
  background: var(--sel);
  color: var(--ink);
  font-weight: 600;
  /* El borde lleva el estado de "dónde estoy"; el color solo no alcanza (misma regla que el semáforo). */
  box-shadow: inset 3px 0 0 var(--accent);
}
/* Ícono + nombre + contador (sistema de componentes, dueño 2026-10-23). El ícono es tinta: nunca lleva estado. */
.cajon svg {
  flex-shrink: 0;
}
.cajon .cajon-texto {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cajon .cajon-contador {
  margin-left: auto;
  min-width: 18px;
  padding: 0 6px;
  border: 1px solid var(--tinte-warn-border);
  border-radius: 9px;
  background: var(--tinte-warn-bg);
  color: var(--tinte-warn-ink);
  font-size: 11px;
  font-weight: 600;
  line-height: 16px;
  text-align: center;
}

/* Los Recientes: el glifo de estado ocupa la columna de los íconos, para que los nombres queden alineados. */
.cajon .estado-glifo {
  gap: var(--sp-3);
}
.cajon .estado-glifo-marca {
  width: 18px;
}

/* Cabeza del cajón en pantalla ancha: el nombre del módulo. El cajón se maneja desde el módulo (dueño 2026-10-23). */
.cajon .cajon-cabeza {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-3) var(--sp-1) var(--sp-4);
}
.cajon .cajon-modulo {
  flex: 1;
  color: var(--ink-3);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
}

/* Menú asomado (mouse sobre el módulo) y de paso (un clic), dueño 2026-10-23: FLOTAN sobre la pantalla. La columna sigue
   en 0 —no empujan el contenido— y no hay velo —no la oscurecen—; sólo la sombra los separa de lo que tapan. Así pasar
   el mouse y luego hacer clic no mueve nada. */
.app[data-cajon='asomado'] .cajon,
.app[data-cajon='de-paso'] .cajon {
  position: relative;
  z-index: 15;
  width: 200px;
  box-shadow: var(--shadow-2);
}

/* Menú angosto: sólo íconos, 56 px, objetivo de 44 px. El nombre va en aria-label y en la ayuda. */
.app[data-cajon='angosto'] {
  grid-template-columns: 56px 1fr;
}
.cajon .cajon-angosto {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: var(--sp-2) 0;
}
.cajon .cajon-angosto a,
.cajon .cajon-angosto button {
  position: relative;
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border-radius: var(--radius-md);
}
.cajon .cajon-angosto button:hover {
  background: var(--hover);
}
.cajon .cajon-angosto button.sel {
  background: var(--sel);
  color: var(--ink);
  box-shadow: inset 3px 0 0 var(--accent);
}
.cajon .cajon-insignia {
  position: absolute;
  top: 5px;
  right: 3px;
  min-width: 15px;
  padding: 0 3px;
  box-sizing: border-box;
  border: 1px solid var(--tinte-warn-border);
  border-radius: 8px;
  background: var(--tinte-warn-bg);
  color: var(--tinte-warn-ink);
  font-size: 10px;
  font-weight: 700;
  line-height: 13px;
  text-align: center;
}

/* Rótulo de sección (Configuración, D-NAV-6; Recientes de Live): texto, no destino. */
.cajon .cajon-seccion {
  padding: var(--sp-3) var(--sp-4) var(--sp-1);
  color: var(--ink-3);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
}
.cajon .cajon-seccion:first-child {
  padding-top: var(--sp-1);
}
/* La banda del modo: Configuración se reconoce de un vistazo, en cualquier pantalla y con el cajón cerrado. */
.app[data-modo='configuracion'] .cab {
  border-bottom: 3px solid var(--modo-config);
}

/* Cabecera + franja de alarma: una sola fila de la rejilla, de punta a punta. */
.app-arriba {
  grid-column: 1 / -1;
  position: relative;
  z-index: 20;
}

/* Franja de alarma (ISA-18.2): la de mayor prioridad sin reconocer. Fondo de dato, borde inferior con el color de su
   prioridad (el mismo de su etiqueta); nunca un fondo teñido ni parpadeo. */
.franja-alarma {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 34px;
  padding: 0 var(--sp-4);
  background: var(--field);
  border-bottom: 2px solid var(--line);
  font-size: var(--fs-md);
  white-space: nowrap;
}
.franja-alarma[data-prioridad='critica'],
.franja-alarma[data-prioridad='alta'] {
  border-bottom-color: var(--falla);
}
.franja-alarma[data-prioridad='media'] {
  border-bottom-color: var(--desconocido);
}
.franja-causa {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--ink-2);
}
.franja-codigo {
  font-family: inherit;
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.franja-cuando,
.franja-otras {
  color: var(--ink-3);
}
.franja-otras {
  margin-left: auto;
}
.franja-btn {
  height: 26px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--ink);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
}
.franja-btn:hover {
  background: var(--hover);
}
.franja-btn:disabled {
  color: var(--ink-3);
  cursor: progress;
}
.franja-ver {
  color: var(--accent);
  font-weight: 500;
  text-decoration: none;
}
@media (max-width: 860px) {
  .franja-codigo,
  .franja-cuando {
    display: none;
  }
}
/* Un solo nivel de sangría, porque no hay un tercer nivel que sangrar. Alineada con el texto de su grupo, no con el
   ícono: 16 de margen + 18 de ícono + 12 de separación. */
.cajon-hijos a {
  padding-left: 46px;
  font-size: var(--fs-md);
}

/* El velo sólo existe cuando el cajón flota. En laptop y SCADA el cajón empuja y no hay nada que velar. */
.cajon-velo {
  display: none;
}

/* Tablet y celular: el cajón flota sobre un velo y se cierra al elegir o al tocar afuera (§5).
   El punto de quiebre es el borde inferior del rango "tablet" del plan: por debajo, 220 px de cajón
   fijos se comen un tercio del ancho útil. */
@media (max-width: 1024px) {
  .app,
  .app[data-cajon='fijo'] {
    grid-template-columns: 1fr;
  }
  .cajon {
    position: fixed;
    z-index: 20;
    top: 0;
    bottom: 0;
    left: 0;
    width: 260px;
    transform: translateX(-100%);
    transition: transform var(--t-med);
    box-shadow: var(--shadow-2);
  }
  .app[data-cajon='de-paso'] .cajon,
  .app[data-cajon='asomado'] .cajon {
    transform: none;
  }
  /* En tablet y celular lo abierto con el dedo lleva velo: tapa casi toda la pantalla. El asomado (mouse) no. */
  .app[data-cajon='de-paso'] .cajon-velo {
    display: block;
    position: fixed;
    z-index: 10;
    inset: 0;
    background: var(--overlay);
  }
  /* Objetivo táctil ≥ 44 px (§5). */
  .cajon a,
  .cajon-grupo {
    padding: var(--sp-3) var(--sp-4);
  }
}

/* Quien pidió menos movimiento no quiere que un panel se deslice por la pantalla. */
@media (prefers-reduced-motion: reduce) {
  .app,
  .cajon {
    transition: none;
  }
}
.app-brand {
  font-weight: 700;
  letter-spacing: 0.5px;
}
.app-main {
  overflow: auto;
  padding: 10px 14px 12px;
  height: 100%;
  min-height: 0;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}

/* Rejilla y tarjetas de widget. */
.widget-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: var(--gap);
}
.widget {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
}
.widget-label {
  font-size: 12px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.widget-value {
  font-size: 26px;
  font-variant-numeric: tabular-nums;
  margin-top: 4px;
}
.widget-unit {
  font-size: 13px;
  color: var(--ink-3);
  margin-left: 4px;
}
.widget-foot {
  margin-top: 6px;
  font-size: 11px;
}

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 10px;
  border: 1px solid currentColor;
  font-size: 12px;
  font-weight: 600;
}

/* Vacío que aplica pero aún no tiene datos (BASES-HMI §6.5, `EstadoVacio`): borde punteado y gris, porque no es una
   anomalía; el título dice qué falta y el detalle dónde se resuelve. */
.estado-vacio {
  margin: var(--sp-2) 0;
  padding: 10px 12px;
  border: 1px dashed var(--line-soft);
  border-radius: 6px;
  color: var(--ink-2);
}
.estado-vacio-titulo {
  margin: 0;
  font-weight: 600;
  color: var(--ink-2);
}
.estado-vacio-detalle {
  margin: 4px 0 0;
  color: var(--ink-3);
}

/* Límite de error (v1.24, `LimiteDeError`): lo que se ve si una vista falla, en vez de la pantalla vacía. Panel del
   sistema con el borde de falla a la izquierda (es anormal: lleva su color) y una sola acción. */
.limite-error {
  max-width: 640px;
  margin: var(--sp-4) 0;
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--falla);
  border-radius: var(--radius-sm);
}
.limite-error[data-alcance='consola'] {
  margin: var(--sp-6) auto;
}
.limite-error-titulo {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--ink);
}
.limite-error-detalle {
  margin: var(--sp-1) 0 var(--sp-3);
  color: var(--ink-3);
}

/* Prioridad de alarma (BASES-HMI §6.3, `PrioridadEtiqueta`). Cada nivel cambia el RELLENO además del color, para que
   crítica y alta no se distingan sólo leyendo: crítica sólida · alta con borde · media con tinte · baja/info planas. */
.prioridad-etiqueta {
  display: inline-block;
  padding: 1px 7px;
  border: 1px solid transparent;
  border-radius: 9px;
  font-size: 11.5px;
  font-weight: 600;
  white-space: nowrap;
  color: var(--ink-2);
}
.prioridad-etiqueta[data-prioridad='critica'] {
  background: var(--falla);
  border-color: var(--falla);
  color: var(--field);
}
.prioridad-etiqueta[data-prioridad='alta'] {
  border-color: var(--falla);
  color: var(--falla);
  background: var(--field);
}
.prioridad-etiqueta[data-prioridad='media'] {
  border-color: var(--tinte-warn-border);
  background: var(--tinte-warn-bg);
  color: var(--tinte-warn-ink);
}
.prioridad-etiqueta[data-prioridad='baja'],
.prioridad-etiqueta[data-prioridad='info'] {
  border-color: var(--line-soft);
  color: var(--ink-3);
}
/* Apagada (un conteo en cero, v1.34): sin relleno ni color de prioridad, como cualquier cero. */
.prioridad-etiqueta[data-apagada='si'] {
  background: transparent;
  border-color: var(--line-soft);
  color: var(--ink-3);
}

/* Fila de indicadores de la página Salud (doc 08 §4). */
.salud-tiles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
  margin-bottom: var(--gap);
}

/* Badge En Vivo / Telemetría SignalR */
.conn-pill {
  margin-left: auto;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.2px;
  padding: 3px 10px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  line-height: 1;
  user-select: none;
  transition: all 0.2s ease;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}
.conn-pill .conn-dot-wrapper {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 8px;
  height: 8px;
}
.conn-pill .conn-dot {
  position: relative;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}
.conn-pill .conn-dot-ping {
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0;
}
.conn-pill .conn-text {
  font-variant-numeric: tabular-nums;
}

/* Tonos de estado para ConnPill */
.conn-pill.tone-live,
.conn-pill.tone-normal {
  color: var(--operativo);
  border-color: var(--operativo);
  background: var(--surface);
}
.conn-pill.tone-live .conn-dot-ping,
.conn-pill.tone-normal .conn-dot-ping {
  animation: live-ping 2s cubic-bezier(0, 0, 0.2, 1) infinite;
}

.conn-pill.tone-warn {
  color: var(--desconocido);
  border-color: var(--desconocido);
  background: var(--surface);
}
.conn-pill.tone-warn .conn-dot-ping {
  animation: live-ping 1.2s cubic-bezier(0, 0, 0.2, 1) infinite;
}

.conn-pill.tone-alarm {
  color: var(--falla);
  border-color: var(--falla);
  background: var(--surface);
}

@keyframes live-ping {
  0% {
    transform: scale(0.8);
    opacity: 0.8;
  }
  70%,
  100% {
    transform: scale(2.4);
    opacity: 0;
  }
}

.muted {
  color: var(--ink-3);
}
.err {
  color: var(--falla);
}

/* Login + cabecera de usuario. */
.login-wrap {
  display: grid;
  place-items: center;
  height: 100%;
  padding: 24px;
}
.login-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 24px;
  width: 320px;
  max-width: 100%;
  display: grid;
  gap: 12px;
}
.login-card label {
  display: grid;
  gap: 4px;
  font-size: 13px;
  color: var(--ink-3);
}
.login-card input {
  padding: 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 14px;
}
.login-card button {
  padding: 9px;
  background: var(--accent);
  color: var(--field);
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-weight: 600;
}
.login-card button:disabled {
  opacity: 0.6;
  cursor: default;
}
.link-btn {
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 3px 10px;
  cursor: pointer;
  color: var(--ink);
  font-size: 12px;
}
.link-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* Gestión de alarmas ISA-18.2. */
.kpi-bar {
  display: flex;
  gap: var(--gap);
  margin: 4px 0 16px;
}
.kpi {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  display: grid;
  min-width: 120px;
}
.kpi b {
  font-size: 22px;
  font-variant-numeric: tabular-nums;
}
.kpi span {
  font-size: 11px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.alarm-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.alarm-table th,
.alarm-table td {
  text-align: left;
  padding: 7px 10px;
  border-bottom: 1px solid var(--line);
}
.alarm-table th {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--ink-3);
}
.alarm-table tbody tr:hover {
  background: var(--surface);
}

/* Producción › Pozos (BASES-HMI §5.2): cifras alineadas a la derecha y lo normal en gris, para que lo que hay que
   atender se lea primero. */
.tabla-pozos .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.tabla-pozos tr.fila-normal td {
  color: var(--ink-3);
}
.tabla-pozos tfoot th {
  border-top: 2px solid var(--line);
  text-transform: none;
}

/* La celda Comentario: un botón que se lee como texto. */
.nota-celda {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.nota-celda:hover {
  text-decoration: underline;
}
/* El comentario entero, al abrirlo: respeta los saltos de línea y corta palabras largas sin ensanchar el diálogo. */
.nota-texto {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  line-height: 1.5;
}

.trends {
  margin-top: 16px;
}
.trends h3 {
  margin: 8px 0;
}

.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.legend-item i {
  width: 11px;
  height: 11px;
  border-radius: 2px;
  border: 1px solid var(--line);
}

/* Vitrina de módulo (ADR-0018): hero + tour + CTA (módulo no licenciado). */
.vitrina-hero {
  padding: 16px 0 8px;
}
.vitrina-hero h2 {
  margin: 6px 0 4px;
}
.vitrina-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--gap);
  margin: 12px 0;
}
.vitrina-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 12px;
}
.vitrina-cta {
  display: flex;
  gap: var(--gap);
  align-items: center;
  flex-wrap: wrap;
  margin-top: 12px;
}
.cta-btn {
  display: inline-block;
  padding: 8px 16px;
  background: var(--accent);
  color: var(--field);
  border-radius: var(--radius-sm);
  text-decoration: none;
  font-size: 14px;
}

/* Mapa multi-activo y pozos ISA-101 (doble codificación forma + color) */
.asset-glyph {
  font-size: 18px;
  line-height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* El tamaño sigue al zoom (`--tam-marcador`, lo pone `IntegratedMap` con `tamanoMarcador`): al alejar, más chicos. */
.pozo-marker-container,
.asset-marker-container {
  cursor: pointer;
  width: var(--tam-marcador) !important;
  height: var(--tam-marcador) !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  user-select: none;
  line-height: 1;
}
.pozo-marker-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--tam-marcador);
  height: var(--tam-marcador);
  background: transparent;
  border: none;
  box-shadow: none;
  transition: transform 0.15s ease;
  line-height: 1;
}
.pozo-marker-container:hover .pozo-marker-badge {
  transform: scale(1.25);
}
/* Marcador del pozo: forma y color del estado del activo, no del tipo de equipo (dueño 2026-10-28; `marcadorEstado.ts`). */
.marcador-pozo {
  display: inline-flex;
  align-items: center;
  width: var(--tam-marcador);
  height: var(--tam-marcador);
  cursor: pointer;
}
.marcador-pozo svg {
  width: 100%;
  height: 100%;
}
.marcador-pozo svg > * {
  stroke: var(--mapa-marcador-borde);
  stroke-width: 1.4px;
}
/* Lo anormal lleva sombra para que el ojo vaya ahí (HP-HMI), sin crecer. */
.marcador-pozo:not([data-estado='operativo']) {
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.55));
}
.asset-glyph {
  font-size: var(--tam-marcador);
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  filter: drop-shadow(0 1.5px 3px rgba(0, 0, 0, 0.85));
  transition: transform 0.15s ease;
}
.asset-marker-container:hover .asset-glyph {
  transform: scale(1.25);
}
.maplibregl-map {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.maplibregl-ctrl-group {
  background: var(--surface) !important;
  border: 1px solid var(--line) !important;
  border-radius: var(--radius-sm) !important;
  box-shadow: 0 2px 6px var(--line) !important;
}
.maplibregl-ctrl-group button {
  border-bottom: 1px solid var(--line-soft) !important;
}
.maplibregl-ctrl-group button .maplibregl-ctrl-icon {
  filter: var(--filtro-icono-ajeno);
}
/* El botón «ⓘ» de créditos: MapLibre lo pinta como un círculo blanco con la «i» en una imagen. Toma el panel del tema y
   la «i» se da vuelta en oscuro, como el zoom; los créditos desplegados, en la tinta del tema. */
.maplibregl-ctrl.maplibregl-ctrl-attrib {
  background-color: var(--surface);
  color: var(--ink-2);
}
.maplibregl-ctrl-attrib a {
  color: var(--ink-2);
}
.maplibregl-ctrl-attrib-button {
  filter: var(--filtro-icono-ajeno);
}

/* Tarjeta de un activo del mapa (dueño 2026-10-28; `TarjetaActivo.tsx`): UNA sola, la misma al pasar el mouse y fijada
   con un clic. Elemento propio sobre el mapa —no un popup de MapLibre— y siempre dentro de él: la coloca
   `ubicarTarjeta.ts` con `transform`, de ahí el `top/left` en cero. Mide como mucho el mapa menos su margen. */
.tarjeta-activo {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 5;
  width: min(184px, calc(100% - 16px));
  max-height: calc(100% - 16px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-2);
  font-size: var(--fs-sm);
  line-height: 1.35;
}
/* A la vista (mouse encima) no se toca: no tapa el puntero ni roba el clic. */
.tarjeta-activo[data-fijada='no'] {
  pointer-events: none;
}
/* El activo se salió del mapa al desplazarlo: la tarjeta espera a que vuelva. */
.tarjeta-activo[data-oculta='si'] {
  visibility: hidden;
}
.tarjeta-activo-cabecera {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line-soft);
}
.tarjeta-activo-titulo {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}
.tarjeta-activo-tipo {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.tarjeta-activo-nombre {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 700;
  overflow-wrap: anywhere;
}
.tarjeta-activo-cerrar.btn {
  height: 24px;
  padding: 0 var(--sp-1);
  color: var(--ink-3);
}
.tarjeta-activo-estado {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-2) var(--sp-3);
}
.tarjeta-activo-motivo,
.tarjeta-activo-alarmas-propias,
.tarjeta-activo-resto {
  margin: 0;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
.tarjeta-activo-alarmas-propias {
  font-weight: 600;
}
.tarjeta-activo-instalado {
  padding: var(--sp-2) var(--sp-3);
  border-top: 1px solid var(--line-soft);
}
.tarjeta-activo-subtitulo {
  margin: 0 0 var(--sp-1);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.tarjeta-activo-instalado ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.tarjeta-activo-instalado li {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.tarjeta-activo-miembro {
  font-weight: 600;
  overflow-wrap: anywhere;
}
/* Dónde está y su serie, bajo el tipo de equipo. */
.tarjeta-activo-serie {
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
.tarjeta-activo-alarma {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  color: var(--ink-2);
}
.tarjeta-activo-pie {
  display: flex;
  padding: var(--sp-2) var(--sp-3);
  border-top: 1px solid var(--line-soft);
}
.tarjeta-activo-pie .btn {
  flex: 1;
  text-decoration: none;
}
/* Ícono fusionado (dueño 2026-10-28; `agruparMarcadores.ts`): el símbolo del peor estado del grupo y cuántos activos
   junta, en una cifra chica arriba a la derecha. Los íconos de sus miembros se esconden mientras dure la fusión. */
.grupo-marker-container {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--tam-marcador);
  height: var(--tam-marcador);
  cursor: pointer;
}
.marcador-grupo-cuenta {
  position: absolute;
  top: -7px;
  left: calc(100% - 4px);
  min-width: 13px;
  padding: 0 3px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--surface);
  color: var(--ink);
  font-size: 9px;
  font-weight: 700;
  line-height: 11px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.grupo-marker-container:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 50%;
}
.pozo-marker-container[data-fusionado],
.asset-marker-container[data-fusionado] {
  display: none !important;
}
/* El activo con la tarjeta abierta lleva un anillo de acento: la tarjeta puede ir corrida para entrar en el mapa. */
.pozo-marker-container[data-seleccionado] .marcador-pozo,
.asset-marker-container[data-seleccionado] .asset-glyph {
  border-radius: 50%;
  box-shadow:
    0 0 0 2px var(--surface),
    0 0 0 4px var(--accent);
}
.pozo-marker-container:focus-visible,
.asset-marker-container:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 50%;
}

/* Bloques del pozo (2026-09-25): un bloque por equipo e instrumento, con su estado. */
.bloques-pozo {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--gap);
  margin: 8px 0 16px;
}
.bloque-pozo {
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  background: var(--surface);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.bloque-pozo.sel {
  outline: 2px solid var(--accent);
}
.bloque-pozo header {
  display: flex;
  flex-direction: column;
}
.bloque-pozo p {
  margin: 0;
}
.bloque-alarmas {
  margin: 0;
  padding-left: 16px;
  font-size: 12px;
}

/* Pantalla del activo (ADR-0055): la ficha de sólo lectura y los cambios de equipo bajo las curvas. */
.activo-ficha {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 6px var(--gap);
  margin: 8px 0 12px;
}
.activo-ficha dt {
  font-size: 12px;
  color: var(--ink-3);
}
.activo-ficha dd {
  margin: 0;
}
.activo-cambios {
  margin: 4px 0 12px;
  padding-left: 16px;
  font-size: 13px;
}

/* Cabecera y acciones compactas del mapa integrado */
.map-header-title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}
.map-header-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.map-activos-count {
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-3);
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  padding: 1.5px 6px;
  line-height: 1.2;
  white-space: nowrap;
}

/* Control segmentado de estilo de mapa (Normal, Satelital, Híbrido) */
.map-style-group {
  display: inline-flex;
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 1px;
  gap: 1px;
}
.btn-map-style {
  background: transparent;
  border: none;
  border-radius: 3px;
  padding: 3px 5px;
  color: var(--ink-3);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  line-height: 1;
  transition:
    background var(--t-fast),
    color var(--t-fast);
}
.btn-map-style:hover:not(.sel) {
  background: var(--hover);
  color: var(--ink);
}
.btn-map-style.sel {
  background: var(--sel);
  color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--sel-border);
}

/* Botones de acción del mapa (Fijar vista, Centrar) */
.btn-map-action {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 4px 6px;
  color: var(--ink-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  line-height: 1;
  transition:
    background var(--t-fast),
    color var(--t-fast),
    border-color var(--t-fast);
}
.btn-map-action:hover {
  background: var(--hover);
  color: var(--ink);
}
.btn-map-action.guardada {
  background: var(--zona-ok);
  color: var(--operativo);
  border-color: var(--operativo);
}
.btn-recenter,
.btn-vista {
  /* compatibilidad */
}

/* Leyenda flotante sobre el mapa (overlay HUD en lienzo) */
.map-legend-panel {
  position: absolute;
  bottom: 10px;
  left: 10px;
  z-index: 10;
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 6px 10px;
  font-size: var(--fs-xs);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
  pointer-events: auto;
  min-width: 215px;
  transition:
    opacity var(--t-fast),
    transform var(--t-fast);
}
.btn-leyenda-mapa-min {
  position: absolute;
  bottom: 10px;
  left: 10px;
  z-index: 10;
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 3px 8px;
  font-size: 11px;
  font-weight: 600;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  pointer-events: auto;
  transition:
    background var(--t-fast),
    color var(--t-fast),
    transform var(--t-fast);
}
.btn-leyenda-mapa-min:hover {
  background: var(--hover);
  color: var(--ink);
  transform: translateY(-1px);
}
.map-legend-header-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
  gap: 8px;
}
.map-legend-title {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ink-3);
}
.map-legend-header-actions {
  display: flex;
  align-items: center;
  gap: 6px;
}
.toggle-todos {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 10px;
  font-weight: 600;
  color: var(--ink-2);
  cursor: pointer;
  user-select: none;
}
.btn-legend-minimize {
  background: transparent;
  border: none;
  color: var(--ink-3);
  cursor: pointer;
  font-size: 11px;
  padding: 1px 4px;
  border-radius: 2px;
  line-height: 1;
}
.btn-legend-minimize:hover {
  background: var(--hover);
  color: var(--ink);
}
.map-legend-grid {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: var(--sp-2);
  font-size: 11px;
}
.legend-section-title {
  font-size: 9.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--ink-3);
  padding-bottom: 2px;
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: 3px;
}
.legend-item {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 2px 4px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  font-size: 11px;
  transition:
    opacity var(--t-fast),
    background var(--t-fast);
}
.legend-item.clickable {
  cursor: pointer;
  user-select: none;
}
.legend-item.clickable:hover {
  background: var(--hover);
}
.legend-item.desactivado {
  opacity: 0.35;
  text-decoration: line-through;
}
.legend-shape {
  font-size: 12px;
  font-weight: bold;
  width: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.legend-shape.shape-lote {
  color: var(--lote);
}

/* Nombre del lote sobre el mapa (capa de límites de PERUPETRO). */
.map-lote-etiqueta {
  color: var(--lote-etiqueta);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-shadow:
    0 0 3px rgba(0, 0, 0, 0.9),
    0 0 6px rgba(0, 0, 0, 0.6);
  pointer-events: auto;
  cursor: default;
  white-space: nowrap;
}

/* SQL Explorer RO (checklist ítem 14): editor + grilla de resultados. */
.sql-quick {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.sql-input {
  width: 100%;
  font-family: ui-monospace, monospace;
  font-size: 13px;
  padding: 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  margin-bottom: 8px;
}
.sql-result {
  overflow-x: auto;
  margin-top: 8px;
}
.sql-result table {
  font-size: 12px;
}

/* Acciones ISA-18.2 (reconocer/normalizar/silenciar) + formulario de shelve. */
.alarm-table .actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.shelve-form {
  display: flex;
  gap: var(--gap);
  align-items: center;
  flex-wrap: wrap;
  padding: 4px 0;
}
.shelve-form label {
  font-size: 13px;
  color: var(--ink-3);
}
.shelve-form input,
.shelve-form select {
  padding: 4px 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 13px;
}
.shelve-form input {
  min-width: 220px;
}

/* Alert Dashboard: tabs + banner P1 + filtros (checklist ítem 7) */
.alarm-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--line);
  margin: 12px 0;
  flex-wrap: wrap;
}
.alarm-tabs button,
.alarm-tabs a {
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 6px 12px;
  font: inherit;
  font-size: 13px;
  color: var(--ink-3);
  cursor: pointer;
}
.alarm-tabs a {
  text-decoration: none;
}
.alarm-tabs button.active,
.alarm-tabs a.active {
  color: var(--ink);
  border-bottom-color: var(--accent);
}
.banner-p1 {
  /* Sin fallback: `--falla` está declarado. Un respaldo que no puede fallar nunca es el que esconde que
     la variable no existe — es exactamente cómo `--accent` estuvo sin declarar sin que nadie lo notara.
     Sobre la falla, el campo de dato y no `#fff`: en oscuro la falla es un rojo claro (pendiente del paso 0). */
  background: var(--falla);
  color: var(--field);
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  margin: 8px 0;
  font-weight: 600;
  animation: p1pulse 1.2s ease-in-out infinite;
}
@keyframes p1pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.55;
  }
}
.kpi.clickable {
  cursor: pointer;
}
.kpi.sel {
  outline: 2px solid var(--accent);
}
.alarm-filters {
  display: flex;
  gap: var(--gap);
  align-items: center;
  flex-wrap: wrap;
  margin: 8px 0;
}
.alarm-filters input,
.alarm-filters select {
  padding: 4px 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 13px;
}

/* Alert Detail: timeline de estados + guía del operador (checklist ítem 8) */
.timeline {
  list-style: none;
  padding: 0;
  margin: 8px 0;
}
.timeline li {
  display: flex;
  gap: 10px;
  align-items: baseline;
  padding: 4px 0;
  color: var(--ink-3);
}
.timeline li.done {
  color: var(--ink);
}
.timeline .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 2px solid var(--line);
  flex: 0 0 auto;
}
.timeline li.done .dot {
  background: var(--accent);
  border-color: var(--accent);
}
.guide {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 12px 16px;
  margin: 8px 0;
}
.guide dt {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--ink-3);
  margin-top: 8px;
}
.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 8px 16px;
  margin: 8px 0;
}

/* Árbol de activos (rebanada 1c, doc 12-bis §1) */
.tree,
.tree ul {
  list-style: none;
  padding-left: 18px;
  margin: 0;
}
.tree > li {
  padding-left: 0;
}
.tree li {
  padding: 3px 0;
  border-left: 1px solid var(--line);
  padding-left: 10px;
}
.tree .node {
  display: flex;
  gap: 8px;
  align-items: baseline;
}
.tree .ruta {
  font-size: 11px;
  color: var(--ink-3);
}

/* Sección "Controlador Edge" (ADR-0028, D-v/D-vi; canal PROVISIONAL Q-16). */
.edge-controller {
  margin: 16px 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 12px;
}
.edge-controller .edge-d22 {
  font-size: 12px;
}
.edge-panel {
  margin: 10px 0;
  padding: 10px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.edge-panel h4 {
  margin: 0 0 8px;
}
.edge-section {
  margin: 8px 0;
}
.edge-kv {
  margin: 4px 0;
  padding-left: 18px;
  font-size: 13px;
}
.edge-kv li {
  margin: 2px 0;
}
.edge-raw {
  font-size: 11px;
  white-space: pre-wrap;
  word-break: break-all;
  margin: 6px 0 0;
}
.edge-propose fieldset {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  margin: 8px 0;
  padding: 8px 10px;
}
.edge-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-end;
}
.edge-field {
  display: flex;
  flex-direction: column;
  font-size: 12px;
  gap: 3px;
}
.edge-field input,
.edge-field select {
  min-width: 120px;
}
.edge-json {
  width: 100%;
  font-family: monospace;
  font-size: 12px;
  box-sizing: border-box;
}
.edge-propuestas {
  list-style: none;
  margin: 0;
  padding: 0;
}
.edge-propuesta {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  margin: 6px 0;
}
.edge-propuesta-head {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.edge-nota {
  font-size: 12px;
  margin: 4px 0 0;
}
.edge-bloqueadores {
  margin: 6px 0 0;
  padding-left: 18px;
  font-size: 12px;
}
/* Spinner de una propuesta en vuelo (estado 'enviada'). */
.spinner {
  display: inline-block;
  width: 12px;
  height: 12px;
  border: 2px solid var(--line);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* ── Bloque D: panel de flota, pantalla de estado del equipo y escenas de física ────────────────────
   ISA-101 (doc 12 §2): la escena es casi monocromática, el color se reserva a la anomalía y el estado
   nunca va solo por color — de ahí el glifo redundante junto a cada etiqueta. */

/* Los conteos del panel son botones (filtran), pero se leen como los KPI del resto de la aplicación. */
button.kpi {
  font: inherit;
  color: inherit;
  text-align: left;
}

.equipo-enlace {
  margin: 4px 0 12px;
}

.escena {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
  align-items: flex-start;
}
.escena-dibujo {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 8px;
  flex: 0 1 380px;
}
.escena-pie {
  flex: 1 1 260px;
}
.escena-estado {
  margin: 0 0 8px;
}
.escena-lecturas {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 8px;
}
.escena-lectura {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
}
.escena-lectura dt {
  font-size: 11px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.escena-lectura dd {
  margin: 2px 0 0;
  font-size: 20px;
  font-variant-numeric: tabular-nums;
}
/* Equipo sin comunicación: los valores son el último recibido y se ven apagados, no como una lectura actual. */
[data-sin-actualizar='si'] .escena-lectura dd {
  color: var(--ink-3);
}

/* Rótulos dentro del SVG de una escena. */
.escena-rotulo {
  font-size: 10px;
  fill: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.escena-valor {
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  fill: var(--ink);
}

/* Compresor CRE (v1.29, dueño 2026-11-04): el cilindro de doble acción dibujado en gris neutro ISA-101, como la unidad de
   bombeo (usa sus clases `rp-*` de acero, pieza y enlace). Lo de adentro de la caja va en línea oculta (trazos cortos) y
   sólo se ve su movimiento. El gas de cada tramo lo mueve el reloj de la escena (`stroke-dashoffset` desde el volumen que
   barre el pistón): la succión del casing pareja, cada válvula y la descarga al ritmo del pistón. Acá no se anima. */
.cre-interior {
  fill: var(--surface);
}
.cre-gas {
  fill: var(--ink-3);
}
.cre-marca {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1px;
  fill: var(--ink-3);
  /* La marca no es proceso: queda tenue, para no competir con el estado (como en la unidad de bombeo). */
  fill-opacity: 0.6;
}
.cre-oculto {
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 1;
  stroke-dasharray: 3 2;
}
.cre-movil {
  stroke: var(--ink-2);
  stroke-width: 2;
  stroke-linecap: round;
}
.cre-manivela {
  stroke-width: 4;
}
.cre-cruceta {
  fill: var(--ink-3);
  stroke: var(--ink-2);
  stroke-width: 1;
}
.cre-tubo {
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 4;
  stroke-linejoin: round;
}
.cre-flujo {
  fill: none;
  stroke: var(--surface);
  stroke-width: 1.5;
  stroke-dasharray: 3 4;
  opacity: 0;
}
.cre-flujo.fluye {
  opacity: 1;
}
.cre-cable {
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 1.2;
}
.cre-check-flecha {
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 1;
}
.cre-check-asiento {
  stroke: var(--ink-2);
  stroke-width: 1.5;
}
/* Abierta: la flecha se llena con tinta (la palabra está en el título de cada válvula). */
.cre-check.abierta .cre-check-flecha {
  fill: var(--ink);
  stroke: var(--ink);
}
.cre-check.abierta .cre-check-asiento {
  stroke: var(--line);
}

/* Equipo Recoil (v1.30, dueño 2026-11-04): la instalación de superficie y el corte del pozo en gris neutro ISA-101, como
   la unidad de bombeo y el CRE (usa sus clases `rp-*` de acero, pieza y enlace, y el caño `cre-tubo`). El tubo colector,
   el carretel y la polea los mueve el reloj de la escena con la profundidad medida; acá sólo avanzan el rotor de la Moyno
   (bombeando) y lo que corre por las líneas (el gas mientras el tubo está en el pozo, el petróleo al bombear). */
/* Borde del terreno: línea con rayitas inclinadas; el subsuelo no se rellena (dueño 2026-11-04). */
.rc-terreno {
  stroke: var(--ink-3);
  stroke-width: 1.5;
}
.rc-terreno-raya {
  stroke: var(--ink-3);
  stroke-width: 1;
}
.rc-interior {
  fill: var(--surface);
}
/* Regla de profundidad, pegada al casing. */
.rc-regla {
  stroke: var(--ink-3);
  stroke-width: 1;
}
.rc-punzado {
  stroke: var(--ink-3);
  stroke-width: 1.5;
}
.rc-fluido {
  fill: var(--ink-3);
  fill-opacity: 0.35;
}
.rc-nivel {
  stroke: var(--ink-2);
  stroke-width: 1.5;
}
.rc-petroleo {
  fill: var(--ink-2);
}
.rc-interno {
  stroke: var(--ink-3);
  stroke-width: 1;
  stroke-dasharray: 3 2;
}
.rc-marca {
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 1px;
  fill: var(--ink-3);
  /* La marca no es proceso: queda tenue, para no competir con el estado (como en la unidad de bombeo). */
  fill-opacity: 0.6;
}
/* Tubo guía del cable: el caño gris y, adentro, el cable que avanza con la profundidad (lo mueve el reloj de la escena). */
.rc-guia {
  stroke: var(--ink-3);
  stroke-width: 7;
  stroke-linecap: butt;
}
.rc-guia-cable {
  stroke: var(--surface-2);
  stroke-width: 2;
  stroke-dasharray: 6 4;
}
/* Manguera de succión de la bomba al cabezal. */
.rc-manguera {
  fill: none;
  stroke: var(--ink-2);
  stroke-width: 3.5;
  stroke-linecap: round;
}
/* Estator de la Moyno en corte: con petróleo en las cavidades mientras bombea. */
.rc-estator {
  fill: var(--surface);
  stroke: var(--ink-3);
  stroke-width: 0.8;
}
.rc-estator.con-petroleo {
  fill: var(--ink-3);
  fill-opacity: 0.45;
}
/* Rotor helicoidal: corre un paso (18 px = PASO_ROTOR) por vuelta, como se ve girar un rotor de cavidad progresiva. */
.rc-rotor {
  fill: none;
  stroke: var(--ink-2);
  stroke-width: 2.5;
  stroke-linecap: round;
}
.rc-rotor.gira {
  animation: rc-helice 0.5s linear infinite;
}
@keyframes rc-helice {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(18px);
  }
}
/* Motor de la bomba: gira rápido mientras bombea. */
.rc-motor {
  transform-box: fill-box;
  transform-origin: center;
}
.rc-motor.gira {
  animation: spin 0.4s linear infinite;
}
/* Caño de succión interior del tubo: el petróleo sube por él mientras bombea (trazo de período 4,5 = 9/2). */
.rc-interno.sube {
  stroke: var(--ink-2);
  stroke-width: 1.5;
  stroke-dasharray: 3 1.5;
  animation: rc-avanza 0.5s linear infinite reverse;
}
.rc-flujo {
  fill: none;
  stroke: var(--surface);
  stroke-width: 1.5;
  stroke-dasharray: 4 5;
  opacity: 0;
}
.rc-flujo.fluye {
  opacity: 1;
  animation: rc-avanza 0.7s linear infinite;
}
@keyframes rc-avanza {
  from {
    stroke-dashoffset: 9;
  }
  to {
    stroke-dashoffset: 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  .rc-rotor.gira,
  .rc-motor.gira,
  .rc-interno.sube,
  .rc-flujo.fluye {
    animation: none;
  }
}

/* Escena rodpump (dueño 2026-11-03): la unidad de bombeo dibujada en gris neutro ISA-101. Desde v1.21 los enlaces con
   señal van en gris como todo lo normal; el color aparece sólo al perderla, y siempre con su texto en `.rodpump-enlaces`.
   La cinemática la mueve el reloj de la estación; acá sólo gira el motor. La grilla de la estación está más abajo. */
.rp-lienzo {
  display: block;
}
.rp-acero {
  fill: var(--surface-2);
  stroke: var(--ink-3);
  stroke-width: 1;
}
.rp-estructura {
  fill: var(--surface-2);
  stroke: var(--ink-3);
  stroke-width: 2;
}
.rp-viga {
  fill: var(--ink-3);
  stroke: var(--ink-2);
  stroke-width: 1;
}
.rp-marca {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1px;
  fill: var(--surface);
  /* La marca no es proceso: queda tenue, para no competir con el estado (dueño 2026-11-03). */
  fill-opacity: 0.5;
}
.rp-pieza {
  fill: var(--ink-3);
  stroke: var(--ink-2);
  stroke-width: 1;
}
.rp-contrapeso {
  fill: var(--ink-2);
  stroke: var(--ink);
  stroke-width: 1;
}
.rp-eje {
  fill: var(--ink);
}
.rp-rayo {
  stroke: var(--surface);
  stroke-width: 2;
}
.rp-biela {
  stroke: var(--ink-2);
  stroke-width: 5;
  stroke-linecap: round;
}
.rp-correa {
  stroke: var(--ink-2);
  stroke-width: 1.5;
}
.rp-cable {
  stroke: var(--ink-2);
  stroke-width: 1.5;
}
.rp-barra {
  stroke: var(--ink);
  stroke-width: 2.5;
}
.rp-tablero {
  fill: var(--surface);
  stroke: var(--ink-3);
  stroke-width: 1.5;
}
.rp-cable-celda {
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 1.2;
  stroke-dasharray: 3 2;
}
/* Datos corriendo hacia el tablero (celda conectada): las rayas avanzan un período (5 px) por vuelta, siempre hacia el
   tablero. `hacia-fin` = en el sentido del trazo; `hacia-inicio` = en contra (el tramo colgante se traza desde el amarre). */
.rp-cable-celda.fluye.hacia-fin {
  animation: rp-datos-hacia-fin 0.5s linear infinite;
}
.rp-cable-celda.fluye.hacia-inicio {
  animation: rp-datos-hacia-inicio 0.5s linear infinite;
}
@keyframes rp-datos-hacia-fin {
  to {
    stroke-dashoffset: -5;
  }
}
@keyframes rp-datos-hacia-inicio {
  to {
    stroke-dashoffset: 5;
  }
}
@media (prefers-reduced-motion: reduce) {
  .rp-cable-celda.fluye {
    animation: none;
  }
}
.rp-celda {
  stroke: var(--ink);
  stroke-width: 1;
}
/* Enlaces (v1.21): con señal, gris de tinta como todo lo normal; sin señal, el gris tachado de «sin comunicación»; en
   espera o sin dato, gris claro. El color nunca va solo: el texto está al pie de la unidad y arriba del wifi. */
.rp-icono {
  fill: none;
  stroke-width: 2.2;
  stroke-linecap: round;
}
.rp-icono-punto {
  stroke: none;
}
.rp-enlace-conectado {
  stroke: var(--ink-3);
}
.rp-enlace-conectado .rp-icono-punto,
.rp-celda.rp-enlace-conectado {
  fill: var(--ink-3);
}
.rp-enlace-sin_comunicacion {
  stroke: var(--sincom);
}
.rp-enlace-sin_comunicacion .rp-icono-punto,
.rp-celda.rp-enlace-sin_comunicacion {
  fill: var(--sincom);
}
.rp-enlace-en_espera,
.rp-enlace-sin_dato {
  stroke: var(--line);
}
.rp-enlace-en_espera .rp-icono-punto,
.rp-enlace-sin_dato .rp-icono-punto,
.rp-celda.rp-enlace-en_espera,
.rp-celda.rp-enlace-sin_dato {
  fill: var(--line);
}
.rp-celda.rp-enlace-conectado,
.rp-celda.rp-enlace-sin_comunicacion,
.rp-celda.rp-enlace-en_espera,
.rp-celda.rp-enlace-sin_dato {
  stroke: var(--ink);
}
.rp-raya {
  stroke: var(--sincom);
  stroke-width: 2.5;
}
.rp-polea {
  transform-box: fill-box;
  transform-origin: center;
}
.rp-polea.gira {
  animation: spin 0.7s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .rp-polea.gira {
    animation: none;
  }
}
/* Estado de los enlaces al pie de la unidad, en una línea. Sólo la falla se marca (peso, no color). */
.rodpump-enlaces {
  margin: var(--sp-2) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-4);
  font-size: var(--fs-sm);
}
.rodpump-enlaces > div {
  display: flex;
  gap: var(--sp-1);
}
.rodpump-enlaces dt {
  color: var(--ink-3);
}
.rodpump-enlaces dt::after {
  content: ':';
}
.rodpump-enlaces dd {
  margin: 0;
  color: var(--ink-2);
}
.rodpump-enlaces dd[data-falla='si'] {
  color: var(--ink);
  font-weight: 600;
}
/* v1.32 (dueño 2026-11-06): el equipo detenido aunque su código diga otra cosa («Quieto — el equipo dice Bajando»). */
.rodpump-enlaces dd[data-aviso='si'] {
  color: var(--tinte-warn-ink);
  font-weight: 600;
}

/* ═══ Estación del pozo (v1.21, dueño 2026-11-03) ═══════════════════════════════════════════════════════════════════
   La pestaña *Ahora* de un pozo con escena de estación (rodpump) entra entera en la ventana, sin desplazarse. El marco
   mide lo que queda de ventana (`useAltoDisponible`) y la grilla se reparte ese alto; los dibujos llenan su celda sin
   deformarse. Se distribuye por el ANCHO DEL MARCO (consulta de contenedor), no por el de la ventana: abrir el menú
   lateral cambia la distribución como si la pantalla fuera más angosta.

   UN SOLO ESQUEMA para todo equipo (dueño 2026-11-04): a la izquierda la tarjeta del EQUIPO (el CRE; la unidad de
   bombeo con su carta debajo, en la misma tarjeta); a la derecha la COLUMNA LATERAL (`ColumnaLateral`): los valores 2 × 3
   y debajo las alarmas, cuyo panel tiene su lugar fijo y desplaza su lista adentro.

   · Escritorio y pared (≥ 900 px de marco): equipo │ columna lateral.
   · Tablet y celular (< 900 px): una columna — equipo, valores 3 × 2 compactos, alarmas con alto fijo. */
.estacion-marco {
  container: estacion / inline-size;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-height: 0;
}
.estacion-marco > p {
  margin: 0;
}
.estacion {
  flex: 1;
  min-height: 0;
  display: grid;
  gap: var(--gap);
  grid-template-columns: minmax(0, 1.3fr) minmax(320px, 1fr);
  grid-template-rows: minmax(0, 1fr);
  grid-template-areas: 'unidad lateral';
}
.estacion-lateral {
  grid-area: lateral;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  min-width: 0;
  min-height: 0;
}
/* Los valores de la estación miden lo mismo en todos los equipos (dueño 2026-11-05): siempre tres filas iguales (con
   cuatro o cinco valores la fila que falta queda libre) y cada indicador mide lo que un rótulo y una cifra, tenga o no
   límite: la barra del límite y su línea van A LA DERECHA de la cifra, no debajo. Así el panel de alarmas empieza a la
   misma altura en todos los pozos y la estación entra en el navegador con su barra de dirección. */
.estacion-indicadores {
  display: grid;
  gap: var(--sp-2);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: repeat(3, 1fr);
}
.estacion .indicador {
  grid-template-columns: max-content minmax(0, 1fr);
  grid-template-rows: auto auto;
  column-gap: var(--sp-3);
}
.estacion .indicador-rotulo {
  grid-column: 1 / -1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.estacion .indicador-valor {
  grid-row: 2;
  grid-column: 1;
}
.estacion .indicador .medidor {
  grid-row: 2;
  grid-column: 2;
  align-self: start;
  padding-top: 7px;
}
.estacion .indicador-contexto {
  grid-row: 2;
  grid-column: 2;
  align-self: end;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* «Valores del equipo» y «Alarmas del pozo» se reparten la columna en partes IGUALES (v1.32, dueño 2026-11-06: «reparte
   proporcional, igual en altura»), haya o no alarmas: la pantalla no se reacomoda cuando una salta. Los valores se estiran
   a llenar su mitad y SIEMPRE miden lo mismo que las alarmas (dueño: «alarmas tiene menos altura que valores»): cuando la
   mitad es chica (1536 × 730, 1366 × 640) las tarjetas se compactan —menos relleno, cifra más chica— en vez de crecer.
   Si las alarmas no entran, su lista se desplaza adentro y la pantalla queda quieta. */
.estacion-valores,
.estacion-alarmas {
  flex: 1 1 0;
  min-width: 0;
}
.estacion-valores .estacion-indicadores {
  flex: 1;
  min-height: 0;
  grid-template-rows: repeat(3, minmax(0, 1fr));
  container: valores / size;
}
@container valores (max-height: 200px) {
  .estacion .estacion-valores .indicador {
    gap: 0;
    padding: 4px var(--sp-2);
  }
  .estacion .estacion-valores .indicador-rotulo {
    font-size: 10px;
  }
  .estacion .estacion-valores .indicador-valor {
    font-size: 19px;
  }
}
.alarmas-pozo-vacio {
  margin: 0;
}
/* Lista detallada de alarmas (`AlarmasDelPozo` con `detalle`): todas, una debajo de otra, con desplazamiento propio. */
.alarmas-pozo[data-detalle='si'] {
  flex: 1;
  min-height: 0;
  flex-direction: column;
  align-items: stretch;
}
.alarmas-pozo[data-detalle='si'] ul {
  flex-direction: column;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.alarmas-pozo[data-detalle='si'] .alarmas-pozo-fila {
  flex: none;
}
.alarmas-pozo[data-detalle='si'] .alarmas-pozo-fila > a,
.alarmas-pozo[data-detalle='si'] .alarmas-pozo-fila > span {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
}
.alarmas-pozo[data-detalle='si'] .alarmas-pozo-donde {
  grid-column: 1 / -1;
}
.alarmas-pozo-valor {
  font-size: var(--fs-sm);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.alarmas-pozo-estado {
  font-size: var(--fs-sm);
  color: var(--ink-3);
  white-space: nowrap;
}
.alarmas-pozo-estado[data-estado='activa'] {
  color: var(--ink);
  font-weight: 600;
}
/* El panel del equipo es alto: el dibujo va al centro, no apoyado en un piso lejano. */
.estacion[data-sin-carta='si'] .estacion-lienzo {
  align-items: center;
}
.estacion[data-sin-carta='si'] .estacion-lienzo > svg {
  height: auto;
  /* Tope menor que el de la unidad de bombeo: el compresor tiene más detalle chico y, grande, domina la pantalla. */
  max-width: min(100%, 560px);
}
.estacion-unidad {
  grid-area: unidad;
}
/* El cuerpo de la tarjeta del equipo: una sola escena (dueño 2026-11-04, «la carta como parte de la animación»). La
   unidad y su carta lado a lado, sin caja, sin título y sin franja propia, CENTRADAS en el panel (en alto y en ancho).
   Debajo de la carta, sólo la leyenda y la hora del golpe. */
.estacion-equipo {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-4);
}
.estacion-equipo > .estacion-lienzo {
  flex: 0 1 58%;
  min-width: 0;
  align-self: stretch;
  align-items: center;
}
.estacion-equipo > .estacion-lienzo > svg {
  /* Alto según su ancho: el dibujo no se rellena de aire y queda centrado junto a la carta. */
  width: 100%;
  height: auto;
  max-width: 720px;
}
.estacion-carta {
  flex: 0 1 40%;
  /* El mismo alto que la unidad (su dibujo mide 376 × 290 en el 58 % del ancho): el pie de la carta queda a la altura
     del suelo y su tope a la del balancín, una sola escena (dueño 2026-11-04, «que se integren naturalmente»). */
  aspect-ratio: 0.9;
  max-height: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
/* En la estación la carta no tiene fondo ni borde propios: sólo la retícula tenue, sobre el fondo del panel. */
.estacion-carta .rp-carta-area {
  fill: none;
  stroke: none;
}
.estacion-subtitulo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1) var(--sp-4);
  /* Debajo de la carta y centrada (dueño 2026-11-04); el aviso de carta atrasada, si lo hay, al lado. */
  margin-top: var(--sp-1);
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
/* Los paneles de la estación se reparten el alto: el dibujo toma lo que sobra. */
.estacion .panel-hmi {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: var(--sp-2) var(--sp-3) var(--sp-3);
}
.estacion .panel-hmi-titulo {
  margin-bottom: var(--sp-2);
}
.estacion-lienzo {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.estacion-lienzo > svg {
  /* Tope de ancho: más grande, el dibujo agranda también su texto y deja de leerse como un esquema. */
  max-width: min(100%, 720px);
  max-height: 100%;
}
.estacion .indicador {
  min-width: 0;
  padding: var(--sp-2) var(--sp-3);
  align-content: start;
}
.estacion .indicador-rotulo {
  line-height: 1.25;
}
.estacion .indicador-valor {
  white-space: nowrap;
}
/* Un valor que es palabra (el diagnóstico) no lleva el tamaño de una cifra: no entraría «Golpe de fluido severo». */
.indicador-texto {
  font-size: var(--fs-xl);
}

@container estacion (min-width: 2200px) {
  .estacion {
    grid-template-columns: minmax(0, 2.08fr) minmax(320px, 0.6fr);
  }
  .estacion-indicadores {
    gap: var(--gap);
  }
  .estacion .indicador {
    padding: var(--sp-3) var(--sp-4);
  }
}
@container estacion (max-width: 899px) {
  .estacion {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
    grid-template-areas: 'unidad' 'lateral';
  }
  .estacion-indicadores {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-rows: repeat(2, 1fr);
  }
  /* Sin ancho para superponerla, la carta va debajo de la unidad, pegada, sin línea que la separe. */
  .estacion-equipo {
    flex-direction: column;
  }
  .estacion-equipo {
    align-items: stretch;
    gap: var(--sp-2);
  }
  .estacion-equipo > .estacion-lienzo {
    flex: 1 1 0;
    min-height: 0;
  }
  .estacion-equipo > .estacion-lienzo > svg {
    width: auto;
    height: 100%;
    max-width: 100%;
  }
  .estacion-carta {
    flex: 1 1 0;
    height: auto;
    min-height: 0;
  }
  /* En una columna las alarmas tienen un alto fijo (unas dos a la vista, para no achicar el equipo); el resto se
     desplaza dentro del panel. */
  .estacion-valores {
    flex: none;
  }
  .estacion-alarmas {
    flex: none;
    height: 11rem;
  }
}
/* Celular: los valores compactos (cifra 20 px) y sin la línea del límite, que se lee en la barra. */
@container estacion (max-width: 560px) {
  .estacion {
    gap: var(--sp-2);
  }
  .estacion .panel-hmi {
    padding: var(--sp-1) var(--sp-2) var(--sp-2);
  }
  .estacion .panel-hmi-titulo {
    margin-bottom: var(--sp-1);
  }
  .estacion-indicadores {
    gap: var(--sp-1);
  }
  .estacion-valores .panel-hmi-titulo {
    display: none;
  }
  .estacion .indicador {
    gap: 2px;
    padding: 6px var(--sp-2);
  }
  .estacion .indicador-rotulo {
    font-size: 10px;
    letter-spacing: 0.3px;
  }
  .estacion .indicador-valor {
    font-size: 17px;
    white-space: normal;
  }
  .estacion .indicador-texto {
    font-size: var(--fs-md);
  }
  .estacion .indicador-contexto:not([data-desvio]) {
    display: none;
  }
  .estacion .carta-leyenda {
    display: none;
  }
  .estacion .rodpump-enlaces {
    margin-top: var(--sp-1);
    font-size: 11px;
  }
}

/* Carta que se reproduce (v1.21): ejes con cifras redondas y unidades, retícula tenue, superficie en tinta. Se dibuja
   en px de su marco: el texto mide lo mismo en cualquier pantalla. */
.rp-carta-marco {
  position: relative;
  flex: 1;
  min-height: 0;
}
.rp-carta-marco > svg {
  position: absolute;
  inset: 0;
  display: block;
}
.rp-carta-area {
  fill: var(--field);
  stroke: var(--line);
}
.rp-carta-reticula {
  stroke: var(--line-soft);
  stroke-width: 1;
}
.rp-carta-eje,
.rp-carta-unidad {
  font-size: 11px;
  fill: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.rp-carta-unidad {
  font-weight: 600;
}
.rp-carta-sup {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.8;
  stroke-linejoin: round;
}
.rp-carta-relleno {
  fill: var(--ink);
  fill-opacity: 0.07;
  stroke: none;
}
.rp-carta-fondo {
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 1.4;
  stroke-dasharray: 4 3;
}
.rp-carta-estela {
  fill: none;
  stroke: var(--ink-2);
  stroke-width: 5;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-opacity: 0.3;
}
.rp-carta-punto {
  fill: var(--ink);
  stroke: var(--surface);
  stroke-width: 2;
}
/* La carta de FONDO de principal (estación, dueño 2026-11-04): llena, gruesa y con relleno; la de superficie queda
   cortada y tenue, y su bolita, más chica. Las dos se recorren a la vez. */
.rp-carta[data-principal='fondo'] .rp-carta-fondo {
  stroke: var(--ink);
  stroke-width: 2.4;
  stroke-dasharray: none;
  stroke-linejoin: round;
}
.rp-carta[data-principal='fondo'] .rp-carta-sup {
  stroke: var(--ink-3);
  stroke-width: 1.3;
  stroke-dasharray: 4 3;
}
.rp-carta[data-principal='fondo'] .rp-carta-relleno {
  fill-opacity: 0.1;
}
.rp-carta[data-principal='fondo'] .rp-carta-recorrido[data-curva='sup'] .rp-carta-punto {
  /* Un poco menos que la del fondo, pero se ve (dueño 2026-11-04: «resaltala un poco más»). */
  fill: var(--ink-2);
  r: 4.5px;
}
.rp-carta[data-principal='fondo'] .rp-carta-recorrido[data-curva='sup'] .rp-carta-estela {
  stroke-width: 4;
  stroke-opacity: 0.28;
}
/* ═══ Pestaña Cartas (v1.22, patrón de las pestañas del pozo §4.1; D-PP-2) ══════════════════════════════════════════════
   Un golpe a la vez, sin desplazar la página: el marco mide lo que queda de ventana (`useAltoDisponible` →
   `--alto-cartas`) y la grilla se lo reparte; los valores se desplazan dentro de su panel. Por el ancho del marco:
   · HD, FullHD y pared (≥ 900 px): carta de superficie │ carta de fondo │ valores; estado y diagnóstico debajo de las
     cartas, con los valores a todo el alto.
   · Tablet y celular (< 900 px): una columna; ahí sí se desplaza la página. */
.cartas-marco {
  container: cartas / inline-size;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-height: 0;
}
@media (min-width: 900px) {
  .cartas-marco {
    height: var(--alto-cartas); /* sin medir todavía: inválida, y el alto queda automático */
  }
}
.cartas-barra {
  align-items: center;
}
.cartas-golpe {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-2);
  font-variant-numeric: tabular-nums;
  margin-right: var(--sp-2);
}
/* «en vivo» o «fijo»: dice si el golpe sigue llegando. Fijo en acento: lo dejó así el usuario, no es una alarma. */
.cartas-modo {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0 var(--sp-2);
}
.cartas-modo[data-fijo='si'] {
  color: var(--accent);
  border-color: var(--accent);
}
/* Mientras llega el golpe elegido se sigue viendo el anterior; esto dice que viene otro (sin vaciar la pantalla). */
.cartas-buscando {
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.cartas {
  flex: 1;
  min-height: 0;
  display: grid;
  gap: var(--gap);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(300px, 0.85fr);
  grid-template-rows: minmax(0, 1fr) auto;
  grid-template-areas:
    'sup fondo valores'
    'tiempo tiempo valores';
}
.cartas-sup {
  grid-area: sup;
}
.cartas-fondo {
  grid-area: fondo;
}
.cartas-valores {
  grid-area: valores;
}
.cartas-tiempo {
  grid-area: tiempo;
  min-width: 0;
}
.cartas .panel-hmi {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: var(--sp-2) var(--sp-3) var(--sp-3);
}
.cartas .panel-hmi-titulo {
  margin-bottom: var(--sp-2);
}
/* Lo que matiza el rótulo del panel («· calculada por PumpOffS»): en tinta suave y sin mayúsculas. */
.panel-hmi-subtitulo {
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-3);
}
.cartas-valores .valores-golpe {
  flex: 1;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
}
/* La sarta puede ser más ancha que el panel: se desplaza a los lados en su marco, no el panel entero. */
.valores-tabla {
  overflow-x: auto;
}
@container cartas (min-width: 2200px) {
  .cartas {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(420px, 0.7fr);
  }
}
@container cartas (max-width: 899px) {
  .cartas {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: 280px 280px auto auto;
    grid-template-areas: 'sup' 'fondo' 'valores' 'tiempo';
  }
}

/* Valores de un golpe: nombre a la izquierda, cifra tabular a la derecha; sólo lo que se aparta lleva color. */
.valores-grupo {
  margin: var(--sp-3) 0 var(--sp-1);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--ink-3);
}
.valores-golpe > section:first-child .valores-grupo {
  margin-top: 0;
}
.valores-lista {
  margin: 0;
}
.valores-fila {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-2);
  padding: 3px 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: var(--fs-md);
}
.valores-fila dt {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-2);
}
.valores-fila dd {
  margin: 0;
  white-space: nowrap;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.valores-unidad,
.valores-nota {
  font-weight: 400;
  color: var(--ink-3);
}
.valores-nota.tone-warn {
  color: var(--tinte-warn-ink);
}
.valores-fila[data-alarma='si'] dd,
.valores-fila[data-tono='alarm'] dd {
  color: var(--falla);
}
.valores-fila[data-tono='warn'] dd {
  color: var(--tinte-warn-ink);
}
.valores-contexto {
  margin: 0 0 var(--sp-1);
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.valores-golpe .tabla-hmi {
  font-size: var(--fs-sm);
}
.valores-golpe .tabla-hmi th,
.valores-golpe .tabla-hmi td {
  height: auto;
  padding: 4px var(--sp-2);
}

/* Banda de tiempo (v1.22, `BandaDeTiempo`): lo normal en gris; color sólo en lo anormal (D-PP-3); «sin datos» rayado. */
.estado-tiempo {
  container: banda / inline-size; /* lo angosto se decide por el ancho de la banda, en cualquier pestaña */
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.estado-tiempo > .filtros-hmi {
  margin-bottom: var(--sp-1);
}
.banda-fila {
  position: relative;
  /* La banda es un control: un doble clic no selecciona texto (antes resaltaba media pantalla). */
  user-select: none;
  -webkit-user-select: none;
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-2);
}
.banda-rotulo {
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.banda {
  display: block;
  width: 100%;
  height: 28px;
  touch-action: none; /* arrastrar acerca: el gesto no desplaza la página */
  cursor: crosshair;
}
.banda-fondo {
  fill: var(--field);
  stroke: var(--line);
  vector-effect: non-scaling-stroke;
}
.banda-tramo[data-tono='normal'] {
  fill: var(--line);
}
.banda-tramo[data-tono='quieto'] {
  fill: var(--ink-3);
}
.banda-tramo[data-tono='aviso'] {
  fill: var(--desconocido);
}
.banda-tramo[data-tono='falla'] {
  fill: var(--falla);
}
.banda-tramo[data-tono='vacio'] {
  fill: none;
}
/* Golpe a golpe: cada golpe con su borde del color del fondo, para leerlos uno por uno (y uno sin diagnóstico, en hueco). */
.banda[data-separados='si'] .banda-tramo {
  stroke: var(--field);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.banda[data-separados='si'] .banda-tramo[data-tono='vacio'] {
  fill: var(--line-soft);
}
.banda-trama {
  stroke: var(--sincom);
  stroke-width: 2;
}
.banda-seleccion {
  stroke: var(--accent);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}
.banda-arrastre {
  fill: var(--accent);
  opacity: 0.2;
}
.banda-vacia {
  position: absolute;
  left: calc(84px + var(--sp-2) + var(--sp-2));
  font-size: var(--fs-sm);
  color: var(--ink-3);
  pointer-events: none;
}
.banda-leyenda {
  list-style: none;
  margin: var(--sp-1) 0 0;
  padding: 0 0 0 calc(84px + var(--sp-2));
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  font-size: 11px;
  color: var(--ink-3);
}
.banda-leyenda li {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
}
.banda-muestra {
  display: inline-block;
  width: 12px;
  height: 12px;
  border: 1px solid var(--line);
  border-radius: 2px;
  background: var(--field);
}
.banda-muestra[data-tono='normal'] {
  background: var(--line);
}
.banda-muestra[data-tono='quieto'] {
  background: var(--ink-3);
}
.banda-muestra[data-tono='aviso'] {
  background: var(--desconocido);
}
.banda-muestra[data-tono='falla'] {
  background: var(--falla);
}
.banda-muestra[data-tono='sincom'] {
  background: repeating-linear-gradient(45deg, var(--sincom) 0 2px, var(--field) 2px 5px);
}
/* Escala de tiempo bajo las bandas: marcas redondas según el rango; la medianoche, con el día y en tinta más fuerte. */
.banda-eje {
  position: relative;
  height: 18px;
  font-size: 11px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.banda-marca {
  position: absolute;
  top: 0;
  padding-top: 4px;
  transform: translateX(-50%);
  white-space: nowrap;
}
.banda-marca::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  height: 3px;
  border-left: 1px solid var(--line);
}
.banda-marca[data-dia='si'] {
  color: var(--ink-2);
  font-weight: 600;
}
@container banda (max-width: 560px) {
  .banda-fila {
    grid-template-columns: 64px minmax(0, 1fr);
  }
  .banda-leyenda {
    padding-left: 0;
  }
  /* En celular entran la mitad de las marcas: se rotula una sí y una no. */
  .banda-marca:nth-child(even) {
    visibility: hidden;
  }
}
/* Válvulas sobre la carta de fondo: anillo en tinta, como la curva (no son una alarma). */
.rp-carta-valvula {
  fill: var(--field);
  stroke: var(--ink-2);
  stroke-width: 1.5;
}
/* ═══ Pestaña Históricos (v1.25, patrón de las pestañas del pozo §4.1) ═══════════════════════════════════════════════════
   Sin desplazar la página (≥ 900 px): el marco mide lo que queda (`--alto-hist`) y la curva toma todo lo que sobra. La
   banda de estado sólo en pozos sin *Cartas*; los cambios de equipo sólo si hay, abajo y con tope de alto. */
.hist-marco {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-height: 0;
}
@media (min-width: 900px) {
  .hist-marco {
    height: var(--alto-hist); /* sin medir todavía: inválida, y el alto queda automático */
  }
}
.hist {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}
.hist .panel-hmi {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: var(--sp-2) var(--sp-3) var(--sp-3);
}
/* La curva termina en la fila de la hora del puntero: abajo, sólo un respiro (dueño 2026-11-06: «que quede ajustado»). */
.hist .panel-hmi.hist-curva {
  padding-bottom: var(--sp-1);
}
.hist .panel-hmi-titulo {
  margin-bottom: var(--sp-2);
}
.hist-curva {
  flex: 1;
}
.hist-cambios {
  max-height: 28%;
}
.hist-cambios .activo-cambios {
  overflow-y: auto;
  margin: 0;
}
@media (max-width: 899px) {
  .hist-curva {
    min-height: 320px;
  }
}

/* Curva histórica (v1.25, `CurvaHistorica`): la primera variable en tinta y llena, la segunda en acento y cortada (se
   distinguen también sin color); la banda mín/máx apenas visible; retícula tenue como la carta. Sin texto fijo
   ni sombra mín/máx (v1.33): la lectura vive en el cursor. */
.curva {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.trends .curva {
  height: 320px;
}
.curva-marco {
  position: relative;
  flex: 1;
  min-height: 160px;
}
.curva-marco > svg {
  position: absolute;
  inset: 0;
  display: block;
  touch-action: none; /* arrastrar acerca: el gesto no desplaza la página */
  cursor: crosshair;
  user-select: none;
  -webkit-user-select: none;
}
.curva-vacia {
  margin: 0;
  color: var(--ink-3);
}
.curva-area {
  fill: var(--field);
  stroke: var(--line);
}
.curva-reticula {
  stroke: var(--line-soft);
  stroke-width: 1;
}
.curva-eje {
  font-size: 11px;
  fill: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.curva-eje[data-dia='si'] {
  fill: var(--ink-2);
  font-weight: 600;
}
/* Cada eje en el color de su curva (v1.33): el izquierdo en tinta, el derecho en acento. */
.curva-eje[data-serie='a'],
.curva-unidad[data-serie='a'] {
  fill: var(--ink);
}
.curva-eje[data-serie='b'],
.curva-unidad[data-serie='b'] {
  fill: var(--accent);
}
.curva-unidad {
  font-size: 11px;
  font-weight: 600;
  fill: var(--ink-3);
}
.curva-linea {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.6;
  stroke-linejoin: round;
}
.curva-linea[data-serie='b'] {
  stroke: var(--accent);
}
.curva-cursor {
  stroke: var(--ink-3);
  stroke-dasharray: 3 3;
}
.curva-punto {
  fill: var(--ink);
  stroke: var(--surface);
  stroke-width: 2;
}
.curva-punto[data-serie='b'] {
  fill: var(--accent);
}
.curva-arrastre {
  fill: var(--accent);
  opacity: 0.15;
}
/* Lectura del cursor (dueño 2026-11-06: sin título ni leyenda): el valor junto a su punto, en el color de su serie y con
   un halo del fondo del área para leerse sobre la curva sin caja que la tape; la hora en su fila, bajo las marcas de
   tiempo, en una pastilla que sigue a la línea vertical. */
.curva-valor {
  font-size: 11px;
  font-weight: 600;
  fill: var(--ink);
  font-variant-numeric: tabular-nums;
  paint-order: stroke;
  stroke: var(--field);
  stroke-width: 3px;
  stroke-linejoin: round;
  pointer-events: none;
}
.curva-valor[data-serie='b'] {
  fill: var(--accent);
}
.curva-hora rect {
  fill: var(--surface);
  stroke: var(--line);
}
.curva-hora text {
  font-size: 11px;
  font-weight: 600;
  fill: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.curva-hora {
  pointer-events: none;
}
/* Relectura en vuelo (ScadaPumpOff): una barra fina arriba; la curva anterior sigue a la vista. */
.curva-cargando {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  overflow: hidden;
  pointer-events: none;
}
.curva-cargando::after {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 30%;
  background: var(--accent);
  animation: curva-cargando 1.1s ease-in-out infinite;
}
@keyframes curva-cargando {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(340%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .curva-cargando::after {
    animation: none;
    width: 100%;
    opacity: 0.5;
  }
}
/* Pestaña Variables (v1.28): cuántas se ven de cuántas, sobre la tabla. */
.variables-marco {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.variables-cuenta {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
/* Pestaña Eventos (v1.27): la barra con la ventana y, a la derecha, cuántos se ven de cuántos. */
.eventos-marco {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.eventos-cuenta {
  margin-left: auto;
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
/* Leyenda y hora del golpe, en el título del panel de la carta. */
.carta-leyenda {
  display: inline-flex;
  gap: var(--sp-3);
}
.carta-leyenda > span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.carta-leyenda > span::before {
  content: '';
  width: 16px;
  border-top: 2px solid var(--ink);
}
.carta-leyenda-fondo::before {
  border-top-style: dashed !important;
  border-top-color: var(--ink-3) !important;
}
/* Con el fondo de principal (estación), la leyenda se invierte igual que las curvas. */
.carta-leyenda[data-principal='fondo'] .carta-leyenda-fondo::before {
  border-top-style: solid !important;
  border-top-color: var(--ink) !important;
  border-top-width: 3px;
}
.carta-leyenda[data-principal='fondo'] .carta-leyenda-sup::before {
  border-top-style: dashed;
  border-top-color: var(--ink-3);
}
.carta-sello {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.carta-sello[data-viejo='si'] {
  color: var(--tinte-warn-ink);
  font-weight: 600;
}

/* Alarmas vivas del pozo (v1.21): la franja izquierda dice la prioridad, como «Requiere atención» de la portada. */
.alarmas-pozo {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-width: 0;
}
.alarmas-pozo ul {
  flex: 1;
  min-width: 0;
  display: flex;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}
.alarmas-pozo-fila {
  flex: 1;
  min-width: 0;
  background: var(--field);
  border: 1px solid var(--line-soft);
  border-left: 4px solid var(--desconocido);
  border-radius: var(--radius-sm);
}
.alarmas-pozo-fila[data-prioridad='critica'] {
  border-left-color: var(--falla);
}
.alarmas-pozo-fila > a,
.alarmas-pozo-fila > span {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px var(--sp-3);
  padding: 6px var(--sp-3);
  color: inherit;
  text-decoration: none;
}
.alarmas-pozo-fila > a:hover {
  background: var(--hover);
}
.alarmas-pozo-que {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}
.alarmas-pozo-donde {
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.alarmas-pozo-mas {
  white-space: nowrap;
  font-size: var(--fs-sm);
}

/* D6 — alcance por usuario: se lee junto a la fila del usuario, no en un modal. */
/* --- Ajustes (paso A8) --- */
/* Ajustes y Preferencias: una columna de campos del sistema por grupo. */
.ajustes-grupo {
  max-width: 760px;
}
.ajustes-lista {
  display: grid;
  gap: 14px;
}
.ajustes-aviso {
  max-width: 760px;
  border: 1px solid var(--tinte-warn-border);
  background: var(--tinte-warn-bg);
  color: var(--tinte-warn-ink);
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  font-size: 13px;
}

/* Indicador de estado (paso 2 del plan §8): forma + etiqueta + color, en ese orden de importancia.
   El COLOR va en el glifo y el texto queda en tinta primaria — principio 3 del §6.1, "el valor viste
   tinta, no estado": teñir la fila entera hace que la pantalla grite y le roba contraste a lo que sí
   importa. Cada estado apunta a su token de §6.2, `--sincom` incluido. */
.estado-glifo {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-1);
  white-space: nowrap;
}
.estado-glifo-marca {
  /* Ancho fijo: sin esto las etiquetas de una tabla no alinean, porque ● ▲ ◆ ◌ no miden lo mismo. */
  display: inline-block;
  width: 1em;
  text-align: center;
  font-size: 1.05em;
  line-height: 1;
}
.estado-glifo-marca[data-estado='operativo'] {
  color: var(--operativo);
}
/* El ● (Operativo y Sin datos) se dibuja más chico que ■ ▲ ◆ en la misma letra: se agrandan para igualarlos a la vista. Con `scale` y no con
   `font-size`, para no mover el ancho fijo que alinea las etiquetas (dueño 2026-10-27). */
.estado-glifo-marca[data-estado='operativo'],
.estado-glifo-marca[data-estado='sin_comunicacion'] {
  transform: scale(1.3);
}
.estado-glifo-marca[data-estado='parado'] {
  color: var(--parado);
}
.estado-glifo-marca[data-estado='con_alarma'] {
  color: var(--desconocido);
}
.estado-glifo-marca[data-estado='con_falla'] {
  color: var(--falla);
}
.estado-glifo-marca[data-estado='sin_comunicacion'] {
  color: var(--sincom);
}

/* Barra de proporción de la tira de flota (*Ahora*, plan §7).
   Los 2 px de separación entre segmentos no son decoración: sin ellos un tramo de un solo equipo se
   funde con su vecino y la barra dice "no hay ninguno" cuando lo que pasa es que "hay pocos". */

/* Lo que quedó fuera de la cola. Va atenuado porque es contexto, no trabajo pendiente. */
.postergados {
  list-style: none;
  padding: 0;
  margin: var(--sp-4) 0 0;
  color: var(--ink-3);
  font-size: var(--fs-md);
}
.postergados li {
  padding: var(--sp-1) 0;
}

/* Pantalla unificada Ahora (Ahora + Mapa + Cola) */

/* Panel Izquierdo: Mapa de Campo */
.integrated-map {
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
  min-height: 0;
}
.map-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 10px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line-soft);
  font-size: var(--fs-sm);
  flex-shrink: 0;
  gap: 8px;
  min-height: 32px;
  box-sizing: border-box;
}
.map-card-header h4 {
  margin: 0;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
}
.map-embed-wrapper {
  flex: 1;
  min-height: 0;
  height: 100%;
  width: 100%;
  position: relative;
  overflow: hidden;
}

/* Aviso en el lugar del mapa cuando el equipo no puede dibujarlo (sin WebGL2; ver mapaWebgl.ts). */
.map-aviso-sin-mapa {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  text-align: center;
  color: var(--ink-2);
  background: var(--surface);
  font-size: var(--fs-sm);
}

/* Panel Derecho: Cola de Atención ("Requiere atención") */

/* Tabla de eventos / novedades */

/* Reconocer, dentro de una fila que además navega (§7: la acción está EN la fila).
   La columna no se estira: es la de ancho fijo, para que "Dónde" se quede con el espacio sobrante. */
/* El foco se marca contra la fila, que al recibir hover se tiñe: sin `offset` negativo el anillo se
   confunde con el borde del botón y se pierde justo cuando se navega con teclado. */

/* Celdas de Qué, Dónde, Esperando */

/* Estado vacío */

/* Panel de postergados / diferidos al pie de la cola */

/* Adaptabilidad completa para celular y pantallas táctiles móviles */
@media (max-width: 768px) {
  .app {
    display: flex !important;
    flex-direction: column !important;
    min-height: var(--alto-pantalla) !important;
    height: auto !important;
    overflow-x: hidden !important;
    overflow-y: auto !important;
  }
  .conn-pill {
    margin-left: auto !important;
    padding: 2px 8px !important;
    border-radius: 10px !important;
    font-size: 11px !important;
    display: inline-flex !important;
    align-items: center !important;
    gap: 4px !important;
    white-space: nowrap !important;
  }
  .conn-pill .conn-text {
    display: inline !important;
  }
  .conn-pill .conn-dot {
    font-size: 9px !important;
    line-height: 1 !important;
  }
  .app-main {
    flex: 1 !important;
    height: auto !important;
    overflow: visible !important;
    padding: 8px 8px 30px !important;
  }
  .map-card-header {
    flex-wrap: nowrap;
    gap: 4px;
    padding: 4px 6px;
    min-height: 28px;
  }
  .map-header-title h4 {
    font-size: 11.5px;
  }
  .map-activos-count {
    font-size: 9.5px;
    padding: 1px 4px;
  }
  .map-header-actions {
    flex-wrap: nowrap;
    gap: 3px;
    justify-content: flex-end;
  }
  .btn-map-style,
  .btn-map-action {
    padding: 3px 4px;
  }
  .btn-accion-reconocer,
  .btn-accion-ver {
    padding: 3px 6px;
    font-size: 10.5px;
  }
}

/* Modo compacto del contenido (dueño 2026-10-20, ver `inicio/inicio.css`): de 901 a 1440 px el margen del área de trabajo
   se achica para que el contenido —en *Ahora*, el mapa— gane alto y ancho. */
@media (min-width: 901px) and (max-width: 1440px) {
  .app-main {
    padding: 6px 10px 8px;
  }
}

/* ═══ Sistema de componentes (docs/propuestas/SISTEMA-DE-COMPONENTES-HMI.md §4, dueño 2026-10-23) ═══════════════════ */

/* Sólo para el lector de pantalla. */
.solo-lector {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Encabezado de pantalla: migas + título, contexto, y a la derecha de cuándo es el dato y las acciones. */
.encabezado-pantalla {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-2) var(--sp-4);
  margin: 0 0 var(--sp-4);
}
.encabezado-titulos {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.encabezado-migas {
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.encabezado-migas a {
  color: var(--ink-3);
  text-decoration: none;
}
.encabezado-migas a:hover {
  color: var(--ink);
  text-decoration: underline;
}
.encabezado-pantalla h1 {
  margin: 0;
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.2px;
  color: var(--ink);
}
.encabezado-contexto {
  padding-bottom: 3px;
  color: var(--ink-3);
}
.encabezado-derecha {
  margin-left: auto;
  display: flex;
  flex-wrap: wrap; /* en celular, dos acciones no caben al lado de la antigüedad del dato */
  align-items: center;
  gap: var(--sp-3);
  padding-bottom: 2px;
}
.encabezado-dato {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-sm);
  color: var(--ink-3);
  white-space: nowrap;
}
.encabezado-dato-punto {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--operativo);
}
/* Dato viejo: el punto deja el verde por el hueco gris de «sin dato» y el texto lo dice. */
.encabezado-dato[data-viejo='si'] {
  color: var(--tinte-warn-ink);
}
.encabezado-dato[data-viejo='si'] .encabezado-dato-punto {
  background: transparent;
  border: 1.5px solid var(--sincom);
}

/* Botones por intención. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 32px;
  padding: 0 14px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font: inherit;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background var(--t-fast),
    border-color var(--t-fast);
}
.btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.btn:disabled {
  cursor: not-allowed;
  color: var(--sincom);
  background: var(--surface);
  border-color: var(--line-soft);
}
.btn-principal {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--field);
  font-weight: 600;
}
.btn-principal:hover:not(:disabled) {
  background: color-mix(in srgb, var(--accent) 88%, var(--ink));
}
.btn-secundario {
  background: var(--field);
  border-color: var(--line);
  color: var(--ink);
}
.btn-secundario:hover:not(:disabled) {
  background: var(--hover);
}
.btn-discreto {
  height: 28px;
  padding: 0 10px;
  background: transparent;
  color: var(--accent);
}
.btn-discreto:hover:not(:disabled) {
  background: var(--hover);
}
.btn-peligroso {
  background: var(--field);
  border-color: var(--falla);
  color: var(--falla);
  font-weight: 600;
}
.btn-peligroso:hover:not(:disabled) {
  background: var(--hover);
}

/* Cargando: esqueleto con la forma de una tabla. */
.esqueleto-tabla {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-md);
  background: var(--field);
  overflow: hidden;
}
.esqueleto-fila {
  display: grid;
  gap: var(--sp-4);
  align-items: center;
  height: 38px;
  padding: 0 var(--sp-3);
  border-top: 1px solid var(--line-soft);
}
.esqueleto-fila span {
  display: block;
  height: 10px;
  border-radius: 3px;
  background: var(--surface);
}
.esqueleto-encabezado {
  height: 34px;
  border-top: 0;
  background: var(--surface-2);
}
.esqueleto-encabezado span {
  width: 60%;
  height: 8px;
  background: var(--line-soft);
}

/* Tabla del sistema: encabezado sobre panel, filas de dato de 38 px, sin teñir filas. Se suma a `.alarm-table`. */
.tabla-hmi {
  /* Completa por sí sola: no depende de `.alarm-table` (una tabla sin otra clase, como las de la pantalla del activo,
     quedaba con los encabezados centrados del navegador). */
  width: 100%;
  font-size: 13px;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-md);
  background: var(--field);
  border-collapse: separate;
  border-spacing: 0;
  overflow: hidden;
}
.tabla-hmi thead th {
  text-align: left;
  font-size: 11px;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 9px 10px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line-soft);
  font-weight: 600;
  letter-spacing: 0.5px;
  vertical-align: bottom;
}
.tabla-hmi tbody td {
  text-align: left;
  height: 38px;
  padding: 4px 10px;
  border-bottom: 1px solid var(--line-soft);
}
.tabla-hmi tbody tr:last-child td {
  border-bottom: 0;
}
.tabla-hmi tbody tr:hover {
  background: var(--hover);
}
.tabla-hmi tfoot th {
  padding: 9px 10px;
  background: var(--surface-2);
  border-top: 1px solid var(--line);
  border-bottom: 0;
}

/* Barra de filtros (v1.33, dueño 2026-11-06): una fila con un solo alto de control (28 px) para píldoras y botones, y
   lo de tiempo (`.filtros-tiempo`) empujado a la derecha, para que la barra use su ancho. */
.filtros-hmi {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-2);
}
.filtros-hmi .btn {
  height: 28px;
}
.filtros-hmi .filtros-tiempo {
  margin-left: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-2);
}

/* Grupo de botones unidos (`GrupoBotones`): bordes compartidos, esquinas sólo en las puntas. */
.grupo-botones {
  display: inline-flex;
}
.grupo-botones > .btn {
  border-radius: 0;
}
.grupo-botones > .btn + .btn {
  margin-left: -1px;
}
.grupo-botones > .btn:first-child {
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
}
.grupo-botones > .btn:last-child {
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.grupo-botones > .btn[aria-pressed='true'],
.grupo-botones > .btn:focus-visible {
  position: relative; /* el borde del elegido queda encima del vecino */
}

/* En una barra angosta (celular) el grupo no se sale de la pantalla: se desplaza a los lados dentro de su ancho. */
.filtros-hmi .grupo-botones {
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}
.filtros-hmi .grupo-botones > .btn {
  flex: none;
}

/* La cuenta dentro de un botón conmutado («Alta 15»): cifra tabular, un paso más apagada que el rótulo. */
.grupo-botones > .btn .num {
  margin-left: var(--sp-1);
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
.grupo-botones > .btn[aria-pressed='true'] .num {
  color: inherit;
}

/* Alarmas: la barra de prioridad separada de la tabla como la de Eventos del pozo. */
.alarmas-pantalla > .filtros-hmi {
  margin-bottom: var(--sp-2);
}

/* Acciones por fila (sistema v1.37): la del operador como botón discreto y el resto en el menú «⋯» (`MenuFila`). */
.acciones-fila {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
}
.tabla-hmi td.acciones {
  text-align: right;
}
.menu-fila-boton {
  min-width: 28px;
  padding: 0 var(--sp-1);
  font-size: var(--fs-lg);
  line-height: 1;
}
.menu-fila {
  position: fixed;
  z-index: 40;
  display: flex;
  flex-direction: column;
  min-width: 160px;
  padding: var(--sp-1) 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-2);
  font-size: var(--fs-md);
}
.menu-fila-opcion {
  display: block;
  width: 100%;
  padding: 6px var(--sp-3);
  background: none;
  border: 0;
  color: var(--ink);
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.menu-fila-opcion:hover,
.menu-fila-opcion:focus-visible {
  background: var(--surface-2);
  outline: none;
}
.menu-fila-opcion:focus-visible {
  box-shadow: inset 2px 0 0 var(--accent);
}
.menu-fila-opcion[aria-disabled='true'] {
  color: var(--ink-3);
  cursor: not-allowed;
}
@media (pointer: coarse) {
  .menu-fila-boton {
    min-width: 44px;
    min-height: 44px;
  }
  .menu-fila-opcion {
    padding: 12px var(--sp-3);
  }
}

/* Filtros como píldoras «Campo: valor ▾». */
.filtros-hmi label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 4px 0 10px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--field);
  color: var(--ink-3);
  font-size: var(--fs-sm);
  /* v1.11: la píldora no pasa del ancho disponible; el rótulo no se parte y el valor largo se recorta. */
  max-width: 100%;
  white-space: nowrap;
}
/* La píldora de una variable de la curva lleva la muestra de su trazo (v1.33): sin leyenda, dice qué línea es. Ancho
   fijo (dueño 2026-11-06): la barra no salta al cambiar de variable; un nombre largo se recorta con «…». */
.filtros-hmi label[data-serie] {
  width: 300px;
}
.filtros-hmi label[data-serie] select {
  flex: 1;
}
.filtros-hmi label[data-serie]::before {
  content: '';
  flex: none;
  width: 16px;
  border-top: 2px solid var(--ink);
}
.filtros-hmi label[data-serie='b']::before {
  border-top-color: var(--accent);
}
/* El foco se marca en la píldora entera, no con el recuadro del select nativo adentro. */
.filtros-hmi label:focus-within {
  box-shadow: var(--focus-ring);
}
.filtros-hmi select:focus-visible {
  outline: none;
}
.filtros-hmi select {
  min-width: 0;
  max-width: 100%;
  text-overflow: ellipsis;
  height: 24px;
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-weight: 600;
}
.filtros-hmi .filtros-nota {
  margin-left: auto;
  font-size: var(--fs-sm);
  color: var(--ink-3);
}

/* Búsqueda dentro de una barra de filtros: la misma píldora de 28 px, sin rótulo (lo dice el texto de ayuda). */
.filtros-hmi input[type='search'] {
  height: 28px;
  min-width: 240px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--field);
  color: var(--ink);
  font: inherit;
  font-size: var(--fs-sm);
}
.filtros-hmi input[type='search']:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Pestañas: subrayado de acento y peso en la elegida, `--ink-3` en las demás (sistema §4). */
.pestanas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  margin: var(--sp-3) 0;
  border-bottom: 1px solid var(--line);
}
.pestana {
  padding: 7px 12px;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  background: transparent;
  color: var(--ink-3);
  font: inherit;
  font-size: var(--fs-md);
  text-decoration: none;
  cursor: pointer;
}
.pestana:hover {
  color: var(--ink);
  text-decoration: none;
}
.pestana:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.pestana.elegida {
  color: var(--ink);
  font-weight: 600;
  border-bottom-color: var(--accent);
}

/* Panel (v1.21): la caja de la portada *Ahora* hecha componente (`Panel`), compartida con la estación del pozo. Rótulo
   11/600 en mayúsculas arriba a la izquierda y una nota corta a la derecha. `.inicio-panel` es el mismo panel con el
   nombre que ya tenía en la portada. */
.panel-hmi,
.inicio-panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: var(--sp-3) var(--sp-4) var(--sp-4);
  min-width: 0;
  box-shadow: var(--shadow-1);
}
/* Los indicadores son lo último del panel: el margen de abajo ya lo pone el panel. */
.panel-hmi > .indicadores:last-child {
  margin-bottom: 0;
}
.panel-hmi-titulo,
.inicio-panel-titulo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}
.panel-hmi-titulo h3,
.inicio-panel-titulo h3 {
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.6px;
}
.panel-hmi-nota,
.inicio-panel-nota {
  font-size: var(--fs-sm);
  color: var(--ink-3);
  text-align: right;
}
.panel-hmi-nota {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
  gap: var(--sp-1) var(--sp-4);
  min-width: 0;
}

/* Medidor analógico del indicador (v1.21, HP-HMI): pista gris, la zona de alarma un paso más oscura, la marca del límite
   y la aguja en tinta. Sólo la aguja toma el color del desvío; la línea de contexto lo dice en palabras. */
.medidor {
  display: block;
  padding: 4px 0 2px;
}
.medidor-pista {
  position: relative;
  display: block;
  height: 6px;
  background: var(--field);
  border: 1px solid var(--line);
  border-radius: 3px;
}
.medidor-zona {
  position: absolute;
  top: 0;
  bottom: 0;
  background: var(--line);
}
.medidor-marca {
  position: absolute;
  top: -4px;
  bottom: -4px;
  width: 2px;
  margin-left: -1px;
  background: var(--ink-3);
}
.medidor-aguja {
  position: absolute;
  top: -5px;
  bottom: -5px;
  width: 4px;
  margin-left: -2px;
  border-radius: 1px;
  background: var(--ink);
  box-shadow: 0 0 0 1.5px var(--surface-2);
}
.medidor[data-desvio='aviso'] .medidor-aguja {
  background: var(--desconocido);
}
.medidor[data-desvio='alarma'] .medidor-aguja {
  background: var(--falla);
}

/* Selector de pozo (v1.21): el nombre del pozo en el título es el selector; ‹ › recorren. */
.selector-pozo {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-2);
}
.selector-pozo-boton.btn {
  height: auto;
  padding: 0 var(--sp-1);
  gap: var(--sp-1);
  font: inherit;
  color: var(--ink);
}
.selector-pozo-boton.btn:hover {
  background: var(--hover);
  color: var(--ink);
  text-decoration: none;
}
.selector-pozo-boton svg {
  color: var(--ink-3);
}
.selector-pozo-paso {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: var(--fs-sm);
  font-weight: 400;
  letter-spacing: 0;
  color: var(--ink-3);
}
.selector-pozo-paso .btn {
  height: 28px;
  min-width: 28px;
  padding: 0 2px;
  color: var(--ink-2);
}
/* Las flechas van ANTES del nombre y el contador tiene ancho fijo según los dígitos del total («9 de 12» mide lo mismo
   que «10 de 12»): las flechas quedan en el mismo lugar en todos los pozos (dueño 2026-11-05). */
.selector-pozo-paso {
  margin-left: calc(-1 * var(--sp-1));
}
.selector-pozo-posicion {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-align: center;
  min-width: 7ch;
}
.selector-pozo-posicion[data-digitos='2'] {
  min-width: 9ch;
}
.selector-pozo-posicion[data-digitos='3'] {
  min-width: 11ch;
}
.selector-pozo-posicion[data-digitos='4'] {
  min-width: 13ch;
}
.selector-pozo-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 30;
  width: 400px;
  max-height: min(540px, calc(var(--alto-pantalla) - 180px));
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-2);
  font-size: var(--fs-md);
  font-weight: 400;
  letter-spacing: 0;
}
.selector-pozo-busca {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line);
  color: var(--ink-3);
}
.selector-pozo-busca input {
  flex: 1;
  min-width: 0;
  height: 32px;
}
.selector-pozo-cerrar {
  display: none;
}
.selector-pozo-lista,
.selector-pozo-lista ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.selector-pozo-lista {
  overflow: auto;
  padding: var(--sp-1) 0 var(--sp-2);
}
.selector-pozo-grupo {
  display: block;
  padding: var(--sp-2) var(--sp-3) var(--sp-1);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--ink-3);
}
.selector-pozo-subgrupo {
  padding: var(--sp-1) var(--sp-3) 2px var(--sp-5);
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.selector-pozo-opcion {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 32px;
  padding: 0 var(--sp-3) 0 28px;
  cursor: pointer;
  color: var(--ink);
}
.selector-pozo-opcion:hover,
.selector-pozo-opcion[data-activa='si'] {
  background: var(--hover);
}
.selector-pozo-opcion[aria-selected='true'] {
  background: var(--sel);
  box-shadow: inset 2px 0 0 var(--accent);
  font-weight: 600;
}
.selector-pozo-sin-estado {
  width: 10px;
}
.selector-pozo-donde {
  margin-left: auto;
  font-size: var(--fs-sm);
  color: var(--ink-3);
  white-space: nowrap;
}
.selector-pozo-vacio {
  padding: var(--sp-3);
  color: var(--ink-3);
}
@media (max-width: 720px) {
  .selector-pozo-panel {
    position: fixed;
    inset: 0;
    width: auto;
    max-height: none;
    border-radius: 0;
    z-index: 60;
  }
  .selector-pozo-cerrar {
    display: inline-flex;
  }
  .selector-pozo-opcion {
    min-height: 44px;
  }
  /* Las pestañas en una sola fila que se desplaza a los lados: dos filas de pestañas se comían el alto del celular. */
  .pestanas {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .pestana {
    white-space: nowrap;
  }
}

/* Indicador (KPI): rótulo 11/600, valor 26/600 con unidad, una línea de contexto; el color sólo en el contexto y sólo
   con desvío (sistema §4). */
.indicadores {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
  margin: 0 0 var(--sp-4);
}
.indicador {
  display: grid;
  gap: 4px;
  min-width: 132px;
  padding: 12px 14px;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-md);
  /* Como la maqueta aprobada (tablero «Propuesta»): el indicador va sobre el panel, no sobre el campo de dato. */
  background: var(--surface-2);
  color: var(--ink);
  font: inherit;
  text-align: left;
}
.indicador-rotulo {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--ink-3);
}
.indicador-valor {
  font-size: 26px;
  font-weight: 600;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.indicador-unidad {
  font-size: var(--fs-md);
  font-weight: 400;
  color: var(--ink-3);
}
.indicador-contexto {
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.indicador-contexto[data-desvio='aviso'] {
  /* La tinta del tinte y no `--desconocido`: el ámbar puro no llega a 4,5:1 como texto chico sobre el campo. */
  color: var(--tinte-warn-ink);
  font-weight: 600;
}
.indicador-contexto[data-desvio='alarma'] {
  color: var(--falla);
  font-weight: 600;
}
/* «Todo sin reconocer» (v1.35): franja de 3 px arriba, del color del estado que cuenta la caja. Es un pseudo-elemento
   (fuera de la grilla) para convivir con el borde azul del filtro elegido y el anillo de foco sin cambiar la medida. */
.indicador[data-pendiente] {
  position: relative;
  overflow: hidden;
}
.indicador[data-pendiente]::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: var(--sincom);
}
.indicador[data-pendiente='aviso']::before {
  background: var(--desconocido);
}
.indicador[data-pendiente='alarma']::before {
  background: var(--falla);
}
.indicador-filtro {
  cursor: pointer;
  transition: border-color var(--t-fast);
}
.indicador-filtro:hover {
  border-color: var(--sel-border);
}
.indicador-filtro:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.indicador-filtro[aria-pressed='true'] {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* Cifras de la tabla del sistema: a la derecha y tabulares (lista de control §5, punto 5). */
.tabla-hmi .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* En celular la app no deja desbordar la página (`.app`, overflow-x oculto): la tabla del sistema se desplaza dentro de
   su propio marco, o sus últimas columnas —donde están las acciones de la fila— quedaban cortadas e inalcanzables. */
@media (max-width: 768px) {
  .tabla-hmi {
    display: block;
    max-width: 100%;
    overflow-x: auto;
  }
}

/* Tabla del sistema con orden y filtro en los títulos (`TablaHmi`, v1.15). Como una hoja de cálculo: el marco se
   desplaza, la página no; título y pie fijos (`sticky` en las CELDAS, que es lo que Safari pega), la columna `fija`
   pegada a la izquierda y ninguna celda partida en dos líneas. El borde y el radio pasan de la tabla al marco: una
   tabla con `overflow: hidden` sería el ancestro al que se pegan los títulos y no se pegarían al marco. */
.tabla-hmi-envoltura {
  position: relative;
}
.tabla-hmi-marco {
  /* La letra se mide contra el ancho del marco (un elemento no puede medirse a sí mismo). */
  container-type: inline-size;
  overflow: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-md);
  background: var(--field);
}
.tabla-hmi-marco:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.tabla-hmi.tabla-hmi-dinamica {
  display: table;
  width: max-content;
  min-width: 100%;
  max-width: none;
  overflow: visible;
  border: 0;
  border-radius: 0;
  /* 12 px en un marco de 800 px, 14 px desde 1600 px; 13 px donde no hay unidades de contenedor. */
  font-size: 13px;
  font-size: clamp(12px, calc(10px + 0.25cqi), 14px);
}
.tabla-hmi-dinamica :is(th, td) {
  white-space: nowrap;
}
.tabla-hmi-dinamica thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  /* 11 px junto a celdas de 13 px: sigue a la letra de la tabla. */
  font-size: 0.85em;
}
.tabla-hmi-dinamica tbody td {
  height: 2.9em;
}
.tabla-hmi-dinamica tfoot th {
  position: sticky;
  bottom: 0;
  z-index: 2;
  text-align: left;
}
.tabla-hmi-dinamica tfoot th.num {
  text-align: right;
}
.tabla-hmi-dinamica .celda-fija {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--field);
  box-shadow: inset -1px 0 0 var(--line-soft);
}
.tabla-hmi-dinamica thead th.celda-fija,
.tabla-hmi-dinamica tfoot th.celda-fija {
  z-index: 3;
  background: var(--surface-2);
}
.tabla-hmi-dinamica tbody tr:hover td.celda-fija {
  background: var(--hover);
}
.tabla-hmi-dinamica thead th[data-activa='si'] {
  color: var(--accent);
  box-shadow: inset 0 -2px 0 var(--accent);
}
.tabla-hmi-dinamica .tabla-hmi-sin-filas {
  color: var(--ink-3);
  text-align: left;
}
/* Cifra que existe pero no está actualizada (v1.16): apagada y con su rótulo en tono de aviso, como la escena del
   equipo sin comunicación (v1.14). El rótulo la hace legible sin depender del color. */
.tabla-hmi-dinamica .valor-viejo {
  color: var(--ink-3);
}
/* El comentario no ensancha la tabla sin fin: se corta con «…» y se lee entero al abrirlo (toque o clic). */
.tabla-hmi-dinamica .celda-nota .nota-celda {
  display: block;
  max-width: 26em;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* El título de columna es un botón que se lee como el título: abre el orden y el filtro. */
.titulo-columna {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: -4px -6px;
  padding: 4px 6px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}
.titulo-columna:hover {
  background: var(--hover);
}
.titulo-columna:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.titulo-columna-marcas {
  display: inline-flex;
  gap: 2px;
  opacity: 0.8;
}
/* Todos los títulos a la izquierda con su flecha a la derecha, también el de una columna de cifras (v1.33, dueño
   2026-11-06: «están disparejos»); las cifras siguen a la derecha. */
.tabla-hmi thead th.num {
  text-align: left;
}
/* Columna de ancho `'contenido'`: lo justo para lo que tiene, sin partir. */
.tabla-hmi .celda-justa {
  white-space: nowrap;
}

/* El panel de la columna: diálogo no modal bajo su título. */
.menu-columna {
  position: absolute;
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  width: 300px;
  max-height: min(480px, calc(var(--alto-pantalla) - 120px));
  overflow-y: auto;
  padding: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-2);
  color: var(--ink);
  font-size: var(--fs-md);
}
.menu-columna-cabeza {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-weight: 600;
}
.menu-columna-cerrar {
  display: inline-flex;
  padding: 4px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink-3);
  cursor: pointer;
}
.menu-columna-cerrar:hover {
  background: var(--hover);
}
.menu-columna-seccion {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding-top: var(--sp-2);
  border-top: 1px solid var(--line-soft);
}
.menu-columna-seccion h3 {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ink-3);
}
/* Orden: dos botones conmutados (v1.4), uno debajo del otro: «Más reciente primero» no cabe a lo ancho. */
.menu-columna-orden {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.menu-columna-orden .btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  justify-content: flex-start;
}
.menu-columna-lista {
  display: flex;
  flex-direction: column;
  max-height: 240px;
  overflow-y: auto;
}
/* Una opción de la lista: casilla, cuántas filas la tienen (a la derecha, como el pie de una tabla) y «Sólo». */
.menu-columna-opcion {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: var(--sp-2);
  border-radius: var(--radius-sm);
}
.menu-columna-opcion:hover {
  background: var(--hover);
}
.menu-columna-opcion[data-vacia='si'] .campo-casilla span {
  color: var(--ink-3);
}
.menu-columna-cuantas {
  color: var(--ink-3);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}
.menu-columna-solo,
.menu-columna-accion {
  min-height: 24px;
  padding: 0 var(--sp-1);
  font-size: var(--fs-sm);
}
.menu-columna-accion {
  justify-self: start;
}
/* «Sólo» aparece al pasar por la opción o al llegarle con el teclado; con el dedo (abajo) está siempre. */
.menu-columna-solo {
  visibility: hidden;
}
.menu-columna-opcion:is(:hover, :focus-within) .menu-columna-solo {
  visibility: visible;
}
/* Los campos del panel miden y se ven como el campo de formulario del sistema (§4): 34 px, `--field`, foco de acento. */
.menu-columna-buscar,
.menu-columna-campos input {
  width: 100%;
  min-height: 34px;
  padding: 0 var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--field);
  color: var(--ink);
  font: inherit;
}
.menu-columna-buscar:focus-visible,
.menu-columna-campos input:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}
.menu-columna-rango {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.menu-columna-atajos {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
}
.menu-columna-campos {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-2);
}
.menu-columna-campos > label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-2);
}
.menu-columna-ayuda {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.menu-columna-pie {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding-top: var(--sp-2);
  border-top: 1px solid var(--line-soft);
}
.menu-columna-cuenta {
  margin-right: auto;
  font-size: var(--fs-sm);
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* Dedo (celular, tablet, pantalla táctil de sala): objetivos de 44 px. */
@media (any-pointer: coarse) {
  .menu-columna .campo-casilla label,
  .menu-columna .btn,
  .menu-columna-buscar,
  .menu-columna-campos input {
    min-height: 44px;
  }
  .menu-columna-solo {
    visibility: visible;
  }
  .menu-columna-lista {
    max-height: none;
  }
}

/* Celular: el panel sale como hoja desde abajo, a lo ancho y al alcance del pulgar. */
@media (max-width: 720px) {
  .menu-columna {
    position: fixed;
    inset: auto 0 0 0 !important;
    width: auto;
    max-height: calc(var(--alto-pantalla) * 0.7);
    border-radius: var(--radius-md) var(--radius-md) 0 0;
    padding-bottom: calc(var(--sp-3) + env(safe-area-inset-bottom));
  }
}

/* Indicador en cero: valor, rótulo y glifo atenuados, sin perder la forma del glifo. El glifo va en gris CLARO (el del
   borde, cerca del fondo del recuadro) y no en `--ink-3`: ese gris oscuro se confundía con `--sincom`, el de «Sin
   datos», en la barra de flota (dueño 2026-10-27). */
.indicador[data-cero='si'] .indicador-valor,
.indicador[data-cero='si'] .indicador-rotulo {
  color: var(--ink-3);
}
.indicador[data-cero='si'] .estado-glifo-marca {
  color: var(--line);
}
.indicador .estado-glifo {
  text-transform: none;
  letter-spacing: 0;
}

/* Curva de proceso (sistema v1.12, reemplaza a la curva chica): escala de proceso desde un piso, referencias punteadas en
   gris, nada en color de estado. Toma el alto que le da su panel (`.curva-proceso-lienzo` se mide). */
.curva-proceso {
  margin: var(--sp-2) 0 0;
  flex: 1;
  min-height: 120px;
  display: flex;
  flex-direction: column;
}
.curva-proceso-lienzo {
  flex: 1;
  min-height: 0;
}
.curva-proceso svg {
  display: block;
  overflow: visible;
}
.curva-proceso-eje {
  font-size: 10px;
  fill: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
/* La lectura bajo el mouse: texto de dato con un halo del color del panel, para que se lea sobre las curvas. */
.curva-proceso-lectura-texto {
  font-size: 11px;
  font-weight: 600;
  fill: var(--ink);
  font-variant-numeric: tabular-nums;
  paint-order: stroke;
  stroke: var(--surface);
  stroke-width: 3px;
}
.curva-proceso-leyenda {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  font-size: 11px;
  color: var(--ink-3);
}
/* El dato al final de la leyenda, en la misma fila y a la derecha; en cifra de dato, no de rótulo. */
.curva-proceso-pie {
  margin-left: auto;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.curva-proceso-pie b {
  color: var(--ink);
}
.curva-proceso-muestra {
  display: inline-block;
  width: 14px;
  vertical-align: middle;
  border-top: 2px solid var(--ink-2);
}
/* Las muestras imitan el trazo: ayer guiones largos y finos en gris claro; proyección puntos redondos gruesos. */
.curva-proceso-muestra[data-trazo='referencia'] {
  border-top: 0;
  height: 1.5px;
  background: repeating-linear-gradient(90deg, var(--ink-3) 0 7px, transparent 7px 11px);
}
.curva-proceso-muestra[data-trazo='proyeccion'] {
  border-top: 0;
  height: 3px;
  background: radial-gradient(circle, var(--ink-2) 1.25px, transparent 1.5px) 0 50% / 5px 3px
    repeat-x;
}
.curva-proceso-muestra[data-trazo='limite'] {
  border-top: 1px dashed var(--ink-3);
}

/* Barras comparadas por categoría (sistema v1.38, `BarrasComparadas`): el período anterior en gris (la referencia) y el
   actual en el azul del tema; las cifras giradas sobre su barra; el gráfico llena el alto de su panel y, si las categorías
   no entran, se desplaza a los lados dentro de su marco. Nada en color de estado: una comparación no es una alarma. */
.barras-comparadas {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin-top: var(--sp-1);
}
.barras-comparadas-leyenda {
  display: flex;
  gap: var(--sp-3);
  font-size: 11px;
  color: var(--ink-3);
}
.barras-comparadas-muestra {
  display: inline-block;
  width: 10px;
  height: 8px;
  border-radius: 2px;
  vertical-align: middle;
}
.barras-comparadas-marco {
  flex: 1;
  min-height: 0;
  overflow-x: auto;
  overflow-y: hidden;
}
.barras-comparadas-marco > svg {
  display: block;
}
.barras-comparadas-muestra[data-serie='anterior'],
.barras-comparadas-barra[data-serie='anterior'] {
  background: var(--ink-3);
  fill: var(--ink-3);
}
.barras-comparadas-muestra[data-serie='actual'],
.barras-comparadas-barra[data-serie='actual'] {
  background: var(--accent);
  fill: var(--accent);
}
.barras-comparadas-base {
  stroke: var(--line);
}
.barras-comparadas-zona {
  fill: transparent;
}
.barras-comparadas-cifra,
.barras-comparadas-rotulo {
  font-size: 10px;
  font-variant-numeric: tabular-nums;
}
.barras-comparadas-cifra {
  fill: var(--ink);
}
.barras-comparadas-cifra[data-serie='anterior'] {
  fill: var(--ink-3);
}
.barras-comparadas-rotulo {
  fill: var(--ink-2);
}
.barras-comparadas-vacio {
  margin: var(--sp-2) 0 0;
}

/* Líneas por categoría con dos ejes (v1.40): el izquierdo en tinta, el derecho en acento, como `CurvaHistorica`. */
.lineas-categoria,
.barras-signo {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin-top: var(--sp-1);
}
.lineas-categoria-leyenda {
  display: flex;
  gap: var(--sp-3);
  font-size: 11px;
  color: var(--ink-3);
}
.lineas-categoria-muestra {
  display: inline-block;
  width: 14px;
  height: 2px;
  vertical-align: middle;
}
.lineas-categoria-marco,
.barras-signo-marco {
  flex: 1;
  min-height: 0;
  overflow-x: auto;
  overflow-y: hidden;
}
.lineas-categoria-marco > svg,
.barras-signo-marco > svg {
  display: block;
}
.lineas-categoria-muestra[data-eje='izquierdo'] {
  background: var(--ink);
}
.lineas-categoria-muestra[data-eje='derecho'] {
  background: var(--accent);
}
.lineas-categoria-linea {
  fill: none;
  stroke-width: 2;
}
.lineas-categoria-linea[data-eje='izquierdo'],
.lineas-categoria-punto[data-eje='izquierdo'] {
  stroke: var(--ink);
}
.lineas-categoria-linea[data-eje='derecho'],
.lineas-categoria-punto[data-eje='derecho'] {
  stroke: var(--accent);
}
.lineas-categoria-punto[data-eje='izquierdo'] {
  fill: var(--ink);
}
.lineas-categoria-punto[data-eje='derecho'] {
  fill: var(--accent);
}
.lineas-categoria-base,
.barras-signo-cero {
  stroke: var(--line);
}
.lineas-categoria-zona,
.barras-signo-zona {
  fill: transparent;
}
.lineas-categoria-cifra,
.lineas-categoria-rotulo,
.barras-signo-cifra,
.barras-signo-rotulo {
  font-size: 10px;
  font-variant-numeric: tabular-nums;
}
.lineas-categoria-cifra[data-eje='izquierdo'],
.barras-signo-cifra {
  fill: var(--ink);
}
.lineas-categoria-cifra[data-eje='derecho'] {
  fill: var(--accent);
}
.lineas-categoria-rotulo,
.barras-signo-rotulo {
  fill: var(--ink-2);
}
.lineas-categoria-vacio,
.barras-signo-vacio {
  margin: var(--sp-2) 0 0;
}

/* Barras con signo (v1.40): verde si sube, rojo si baja; los únicos de su tipo en el sistema. */
.barras-signo-barra[data-signo='sube'] {
  fill: var(--variacion-sube);
}
.barras-signo-barra[data-signo='baja'] {
  fill: var(--variacion-baja);
}

/* Deslizador de rango (v1.40): dos `input type=range` superpuestos sobre una pista; el tramo elegido en el acento. Sólo
   los punteros reciben el puntero del ratón, así cada uno se arrastra aunque estén encimados. */
.deslizador-rango {
  position: relative;
  height: 34px;
  margin-top: var(--sp-1);
}
.deslizador-rango-pista {
  position: absolute;
  left: 8px;
  right: 8px;
  top: 9px;
  height: 4px;
  border-radius: 2px;
  background: var(--line);
}
.deslizador-rango-elegido {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--desde);
  right: calc(100% - var(--hasta));
  background: var(--accent);
  border-radius: 2px;
}
.deslizador-rango input[type='range'] {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 22px;
  margin: 0;
  background: none;
  pointer-events: none;
  appearance: none;
  -webkit-appearance: none;
}
.deslizador-rango input[type='range']::-webkit-slider-thumb {
  pointer-events: auto;
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--accent);
  cursor: ew-resize;
}
.deslizador-rango input[type='range']::-moz-range-thumb {
  pointer-events: auto;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--accent);
  cursor: ew-resize;
}
.deslizador-rango input[type='range']:focus-visible::-webkit-slider-thumb {
  box-shadow: var(--focus-ring);
}
.deslizador-rango-fechas {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* Botón conmutado (`aria-pressed`): el elegido de un grupo, como la barra de dispositivos del pozo. Fondo de selección y
   borde de selección, sin color de estado. */
.btn-secundario[aria-pressed='true'] {
  background: var(--sel);
  border-color: var(--sel-border);
  font-weight: 600;
}
.selector-dispositivo {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: var(--sp-3) 0 0;
}

/* El activo elegido dentro de *Análisis*: subtítulo, estado y el enlace a su pantalla completa. */
.activo-sujeto {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-3);
  margin: 0 0 var(--sp-2);
}
.activo-sujeto h2 {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 600;
}

/* ─── Diálogo y campo de formulario (sistema §4, dueño 2026-10-23) ──────────────────────────────────────────────────
   Una sola ventana para los formularios y las confirmaciones. Dos anchos —angosto para las altas simples, ancho para
   lo que lleva secciones o tablas—; en celular ocupa la pantalla; en las de sala de control crece para mostrar más
   sin desplazar (la letra no cambia: es la de toda la consola). Encabezado y pie quedan fijos; el cuerpo se desplaza. */
.dialogo-fondo {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: calc(var(--alto-pantalla) * 0.06) var(--sp-4) var(--sp-4);
  background: var(--overlay);
}
.dialogo {
  --dialogo-ancho: 480px;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: var(--dialogo-ancho);
  max-height: calc(var(--alto-pantalla) * 0.88);
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-2);
  color: var(--ink);
}
.dialogo[data-ancho='ancho'] {
  --dialogo-ancho: 760px;
}
.dialogo-encabezado {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line-soft);
}
.dialogo-titulo {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: 1.3;
}
.dialogo-contexto {
  margin: 2px 0 0;
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.dialogo-cerrar {
  flex: none;
  width: 28px;
  padding: 0;
  color: var(--ink-3);
}
.dialogo-cuerpo {
  flex: 1;
  min-height: 0; /* sin esto el hijo flex no se desplaza y el pie queda fuera de la pantalla */
  overflow-y: auto;
  padding: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.dialogo-cuerpo > :is(p, ul) {
  margin: 0;
}
.dialogo-pie {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--line-soft);
  background: var(--surface-2);
  border-radius: 0 0 var(--radius-md) var(--radius-md);
}

/* Una acción del pie que va aparte, a la izquierda (Borrar): lejos de la principal. */
.dialogo-pie-aparte {
  margin-right: auto;
}

/* Sección del cuerpo: subtítulo como el encabezado de una tabla. */
.dialogo-seccion {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.dialogo-seccion + .dialogo-seccion {
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line-soft);
}
.dialogo-seccion-titulo {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ink-3);
}
/* Campos lado a lado: tantas columnas como entren de 220 px; en celular, una. */
.dialogo-rejilla {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--sp-3);
}
/* Una nota del cuerpo: gris, corta. */
.dialogo-nota {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
/* Pares rótulo → valor de sólo lectura (la cadena de comunicación de un equipo). */
.dialogo-datos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--sp-2);
  margin: 0;
}
.dialogo-datos > div {
  padding: var(--sp-2) var(--sp-3);
  background: var(--field);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
}
.dialogo-datos dt {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ink-3);
}
.dialogo-datos dd {
  margin: 2px 0 0;
  font-variant-numeric: tabular-nums;
}
/* La vía de entrada de un equipo dentro de su configuración: la vigente, el cambio y el historial, uno debajo del otro. */
.via-entrada {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.via-desde {
  display: block;
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
/* Lo que choca y conviene leer dos veces, antes de confirmar. */
.dialogo-aviso {
  margin: 0;
  padding: var(--sp-2) var(--sp-3);
  background: var(--tinte-warn-bg);
  border: 1px solid var(--tinte-warn-border);
  border-radius: var(--radius-sm);
  color: var(--tinte-warn-ink);
}
/* Una fila de controles: el selector y su botón «Agregar». */
.dialogo-fila {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-2);
}
.dialogo-fila > .campo-formulario {
  flex: 1;
  min-width: 220px;
}
/* Una tabla dentro del diálogo se desplaza en su marco y deja el encabezado a la vista. */
.dialogo-tabla {
  max-height: 300px;
  overflow: auto;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-md);
}
.dialogo-tabla .tabla-hmi {
  border: 0;
  border-radius: 0;
  overflow: visible;
}
.dialogo-tabla .tabla-hmi thead th {
  position: sticky;
  top: 0;
  z-index: 1;
}
.tabla-hmi td :is(input:not([type='checkbox']), select) {
  height: 26px;
  width: 100%;
  min-width: 56px;
  padding: 0 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font: inherit;
  font-variant-numeric: tabular-nums;
}
.tabla-hmi td label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-sm);
}
/* Tabla editable (v1.36, dueño 2026-11-06): la fila con algo escrito y sin guardar lleva un filete de acento a la
   izquierda; la celda inválida, borde de falla y su frase debajo. Las mismas reglas en claro y en oscuro (tokens). */
.tabla-hmi tr.fila-cambiada > td:first-child {
  box-shadow: inset 3px 0 0 var(--accent);
}
.tabla-hmi td :is(input:not([type='checkbox']), select)[aria-invalid='true'] {
  border-color: var(--falla);
}
.tabla-hmi td :is(input:not([type='checkbox']), select):disabled {
  color: var(--ink-3);
  background-color: var(--surface-2);
}
.celda-error {
  margin: 2px 0 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--falla);
  white-space: normal;
}
/* La barra de cambios (`BarraDeCambios`): fija al pie del área de trabajo mientras haya algo sin guardar. */
.barra-cambios {
  position: sticky;
  bottom: 0;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-2);
}
.barra-cambios-resumen {
  margin: 0;
  font-weight: 600;
  color: var(--ink);
}
.barra-cambios-error {
  margin: 0;
  font-weight: 600;
  color: var(--falla);
}
.barra-cambios-acciones {
  display: flex;
  gap: var(--sp-2);
  margin-left: auto;
}

/* Subtítulo de una sección de la pantalla («Últimos cambios»): el mismo del diálogo y del encabezado de tabla. */
.seccion-pantalla {
  margin: var(--sp-5) 0 var(--sp-2);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ink-3);
}
/* Las acciones de una pestaña, arriba de su tabla: el principal primero y una nota a la derecha. */
.barra-acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: var(--sp-3) 0;
}
.barra-acciones .filtros-nota {
  margin-left: auto;
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
/* Dentro de una fila: lo que matiza el dato («dada de baja») y el aviso de configuración debajo del valor. */
.tabla-hmi .nota-fila {
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.tabla-hmi .aviso-fila {
  margin: 2px 0 0;
  font-size: var(--fs-sm);
}

/* Campo de formulario: rótulo 12/600 arriba, control de 34 px, ayuda gris, error en falla. */
.campo-formulario {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.campo-formulario-rotulo {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-2);
}
.campo-formulario-requerido {
  color: var(--ink-3);
}
.campo-formulario > :is(input, select, textarea) {
  width: 100%;
  min-height: 34px;
  padding: 0 var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font: inherit;
}
.campo-formulario > textarea {
  padding: var(--sp-2);
  min-height: 72px;
}
.campo-formulario > :is(input, select, textarea):focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}
.campo-formulario > :is(input, select, textarea):disabled {
  color: var(--ink-3);
  background-color: var(--surface-2);
}
.campo-formulario[data-error='si'] > :is(input, select, textarea) {
  border-color: var(--falla);
}
.campo-formulario-ayuda {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.campo-formulario-error {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--falla);
}
.campo-casilla label {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 28px;
  cursor: pointer;
}
.campo-casilla .campo-formulario-ayuda {
  margin-left: 22px;
}
.error-formulario {
  margin: 0;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--falla);
  border-radius: var(--radius-sm);
  background: var(--field);
  color: var(--falla);
  font-weight: 600;
}

/* Celular: el diálogo es la pantalla entera y los botones del pie se reparten el ancho, al alcance del pulgar. */
@media (max-width: 720px) {
  .dialogo-fondo {
    padding: 0;
  }
  .dialogo,
  .dialogo[data-ancho='ancho'] {
    max-width: none;
    height: 100%;
    max-height: none;
    border: 0;
    border-radius: 0;
  }
  .dialogo-pie {
    border-radius: 0;
  }
  .dialogo-pie > .btn {
    flex: 1;
  }
}

/* Pantallas de sala de control: los dos anchos crecen y el cuerpo usa más alto; la letra sigue siendo la de la consola. */
@media (min-width: 1920px) {
  .dialogo {
    --dialogo-ancho: 560px;
    max-height: calc(var(--alto-pantalla) * 0.9);
  }
  .dialogo[data-ancho='ancho'] {
    --dialogo-ancho: 1040px;
  }
  .dialogo-tabla {
    max-height: 420px;
  }
}
@media (min-width: 2560px) {
  .dialogo[data-ancho='ancho'] {
    --dialogo-ancho: 1280px;
  }
  .dialogo-tabla {
    max-height: 560px;
  }
}
