/* =============================================================================
 * production.css — Estilos de la pantalla de producción
 * F2R Engineering
 *
 * Layout: visor 3D a la izquierda + sidebar de control a la derecha.
 * Usa exclusivamente tokens de variables.css.
 * ============================================================================= */

/* ── Layout principal ─────────────────────────────────────────────────────── */
.prod-layout {
  display: flex;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.prod-viewer {
  flex: 1;
  position: relative;
  background: var(--surface-base);
  overflow: hidden;
  /* el #maquina interno usa los mismos estilos que en manual */
}

.prod-sidebar {
  /* Anchura: el operador la ajusta con el asa de redimensionado (la guarda
   * production-sidebar.js en localStorage y la inyecta como --prod-sidebar-width
   * sobre :root). El default 420px reproduce el diseño original y se escala
   * con --font-scale (a "Extra grande" llegaría a 630 px). Clamp en JS entre
   * 340..560 px para que no se rompa el layout interno ni se coma el visor. */
  width:     calc(var(--prod-sidebar-width, 420px) * var(--font-scale));
  min-width: calc(340px * var(--font-scale));
  max-width: calc(560px * var(--font-scale));
  background: var(--surface-raised);
  border-left: 1px solid var(--border-base);
  display: flex;
  flex-direction: column;
  /* overflow: visible para que el asa y el botón de dock (posicionados con
     left negativo) NO queden clippeados. El scroll lo gestiona el wrapper
     interno .prod-sidebar-body. */
  overflow: visible;
  position: relative;
  /* La transición sólo cubre transiciones plegar/desplegar — durante el drag
     production-sidebar.js añade `.is-resizing` para suprimirla y evitar el
     "rubber band" mientras se arrastra. */
  transition: width var(--transition-base);
}

.prod-sidebar.is-resizing { transition: none; }

/* Wrapper interno: aquí vive el padding, el gap, y el scroll vertical. */
.prod-sidebar-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  padding: var(--space-3);
  gap: var(--space-3);
}

/* ── Asa de redimensionado (centro del borde izquierdo del sidebar) ────────
   Sólo visible cuando el sidebar está desplegado. Se oculta automáticamente
   con `.is-docked` y en la versión móvil (≤900px, layout vertical). */
.prod-sidebar-resize {
  position: absolute;
  left: -7px;
  top: 50%;
  transform: translateY(-50%);
  width: 14px;
  height: 60px;
  padding: 0;
  background: var(--surface-overlay);
  border: 1px solid var(--border-base);
  border-radius: var(--radius-md);
  color: var(--text-muted);
  cursor: ew-resize;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 6;
  opacity: 0.5;
  transition: opacity var(--transition-fast), background var(--transition-fast), border-color var(--transition-fast);
}
.prod-sidebar-resize:hover,
.prod-sidebar-resize:focus-visible {
  opacity: 1;
  background: var(--accent);
  border-color: var(--accent-active);
  color: var(--text-inverse);
  outline: none;
}
.prod-sidebar-resize-grip {
  display: block;
  width: 2px;
  height: 26px;
  background: currentColor;
  box-shadow: 4px 0 0 currentColor, -4px 0 0 currentColor;
  border-radius: 1px;
}

/* ── Botón de plegar/desplegar ──────────────────────────────────────────── */
.prod-sidebar-dock {
  position: absolute;
  left: -14px;
  /* 60px aprox = top de los botones del visor (12px) + alto (36px) +
     margen (12px). Así el dock queda justo debajo del cluster cámara +
     engranaje del viewer-settings, sin solaparse con ellos. */
  top: 60px;
  width: 28px;
  height: 28px;
  padding: 0;
  background: var(--surface-raised);
  border: 1px solid var(--border-base);
  border-radius: 50%;
  color: var(--text-secondary);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 7;
  box-shadow: var(--shadow-sm);
  /* Sólo animamos color/borde/fondo. Posición e icono cambian en seco al
     plegar/desplegar para no animar 4 propiedades a la vez. */
  transition: background var(--transition-fast),
              border-color var(--transition-fast),
              color var(--transition-fast);
}
.prod-sidebar-dock:hover,
.prod-sidebar-dock:focus-visible {
  background: var(--accent);
  border-color: var(--accent-active);
  color: var(--text-inverse);
  outline: none;
}
.prod-sidebar-dock-icon { transition: transform var(--transition-base); }
/* En estado desplegado el chevron apunta hacia el borde derecho (>),
   sugiriendo "plegar hacia ahí". Al plegar invertimos el icono. */
.prod-sidebar.is-docked .prod-sidebar-dock-icon { transform: rotate(180deg); }

/* ── Estado plegado: sidebar reducido a una franja clicable ─────────────── */
.prod-sidebar.is-docked {
  width: 28px !important;
  min-width: 28px !important;
  max-width: 28px !important;
  overflow: hidden;
  cursor: pointer;
}
.prod-sidebar.is-docked > .prod-sidebar-body { display: none !important; }
.prod-sidebar.is-docked > .prod-sidebar-resize { display: none !important; }
.prod-sidebar.is-docked .prod-sidebar-dock {
  /* Centramos el botón sobre toda la franja para que sea fácil de pulsar
     en pantallas táctiles. left/top/transform tienen que recalcularse. */
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 24px;
  height: 48px;
  border-radius: var(--radius-md);
  box-shadow: none;
  background: transparent;
  border: none;
  color: var(--text-secondary);
}
.prod-sidebar.is-docked:hover .prod-sidebar-dock,
.prod-sidebar.is-docked:focus-within .prod-sidebar-dock {
  color: var(--accent);
}
.prod-sidebar.is-docked .prod-sidebar-dock-icon {
  transform: rotate(180deg);
  width: 18px;
  height: 18px;
}
.prod-sidebar.is-docked:hover { background: var(--surface-elevated); }

@media (max-width: 900px) {
  .prod-layout      { flex-direction: column; }
  .prod-viewer      { flex: 1 1 50vh; min-height: 280px; }
  .prod-sidebar     {
    width: 100% !important;
    max-width: none !important;
    min-width: 0 !important;
    border-left: none;
    border-top: 1px solid var(--border-base);
  }
  /* En layout vertical el asa de redimensionado y el plegado pierden sentido
     (la sidebar se apila bajo el visor). Los ocultamos para no estorbar. */
  .prod-sidebar-resize,
  .prod-sidebar-dock { display: none !important; }
  /* Si quedó en estado plegado en escritorio y la ventana se reduce a móvil,
     forzamos desplegado para que el operador no quede sin sidebar. */
  .prod-sidebar.is-docked {
    width: 100% !important;
    min-width: 0 !important;
    max-width: none !important;
    overflow: visible;
    cursor: auto;
  }
  .prod-sidebar.is-docked > .prod-sidebar-body { display: flex !important; }
}

/* ── Banner overlay del visor ─────────────────────────────────────────────── */
/* Aviso "Selecciona una estación…" sobre el visor 3D. Auto-dismiss a los 5 s
   (la lógica del fade-out vive en production-page.js para poder cancelar el
   timer). Diseño compartido por tokens: en modo oscuro queda transparente
   sobre el fondo del visor; en light-mode tiene su override más abajo. */
.prod-overlay-info {
  position: absolute;
  top: var(--space-5);
  left: 50%;
  transform: translateX(-50%);
  background: var(--surface-raised);
  color: var(--text-primary);
  padding: var(--space-2) var(--space-5);
  border: 1px solid var(--border-base);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-md);
  backdrop-filter: blur(8px);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  letter-spacing: 0.2px;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  pointer-events: none;
  z-index: 10;
  opacity: 1;
  transition: opacity 0.4s ease, transform 0.4s ease;
  animation: prod-overlay-pop-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
.prod-overlay-info [data-icon] { color: var(--accent); }

/* Estado "fading": se aplica desde JS al cumplirse los 5 s. Cuando termina
   el fade, JS pone `hidden` para sacarlo del flujo. */
.prod-overlay-info.is-dismissing {
  opacity: 0;
  transform: translate(-50%, -8px);
}

.prod-overlay-info[hidden] { display: none; }

@keyframes prod-overlay-pop-in {
  from { opacity: 0; transform: translate(-50%, -8px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* Light-mode: el fondo `--surface-raised` puede confundirse con el panel
   del visor; le damos un ligero tinte de acento para que destaque sin
   romper la paleta. */
body.light-mode .prod-overlay-info {
  background: var(--surface-raised);
  border-color: var(--accent-soft, var(--border-base));
  box-shadow: 0 4px 16px rgba(15, 23, 42, 0.08);
}

/* ── Section header ──────────────────────────────────────────────────────── */
.prod-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
/* El atributo `hidden` debe ganar sobre `display: flex`. Sin esta regla,
   el detalle de estación queda visible aunque se le ponga hidden=true en JS,
   porque CSS gana. Usamos !important para mantenerlo blindado. */
.prod-section[hidden] {
  display: none !important;
}

.prod-section-header {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 0 var(--space-1);
}
.prod-section-header h2 {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  letter-spacing: 1px;
  color: var(--text-primary);
  text-transform: uppercase;
  flex: 1;
}
.prod-station-count {
  background: var(--accent);
  color: var(--text-inverse);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  min-width: 22px;
  text-align: center;
}

/* ── Lista de estaciones (vista general) ──────────────────────────────── */
.prod-stations {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.prod-station-card {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--surface-overlay);
  border: 1px solid var(--border-base);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: var(--transition-base);
  text-align: left;
  font-family: inherit;
  color: var(--text-primary);
  width: 100%;
}
.prod-station-card:hover {
  background: var(--surface-elevated);
  border-color: var(--accent);
  transform: translateX(2px);
}
.prod-station-card.is-fault {
  border-color: var(--color-danger);
  background: linear-gradient(90deg, rgba(216,59,78,0.18), var(--surface-overlay) 60%);
}
.prod-station-card.is-active {
  border-color: var(--accent);
  background: var(--surface-elevated);
}

/* Punto de estado (verde/rojo/etc.) */
.prod-statedot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--color-success);
  box-shadow: 0 0 8px var(--color-success-soft);
  transition: var(--transition-base);
}
.prod-statedot.is-fault   { background: var(--color-danger);  box-shadow: 0 0 12px var(--color-danger-soft); }
.prod-statedot.is-warning { background: var(--color-warning); box-shadow: 0 0 8px  var(--color-warning-soft); }
.prod-statedot.is-undef   { background: var(--text-muted);    box-shadow: none; }

/* Punto grande (en la cabecera del detalle) */
.prod-station-statedot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--color-success);
  box-shadow: 0 0 10px var(--color-success-soft);
  flex-shrink: 0;
}
.prod-station-statedot.is-fault   { background: var(--color-danger);  box-shadow: 0 0 14px var(--color-danger-soft); }
.prod-station-statedot.is-warning { background: var(--color-warning); box-shadow: 0 0 10px var(--color-warning-soft); }
.prod-station-statedot.is-undef   { background: var(--text-muted);    box-shadow: none; }

.prod-station-card-info {
  flex: 1;
  min-width: 0;
}
.prod-station-card-name {
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  color: var(--text-primary);
}
.prod-station-card-meta {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  margin-top: 2px;
}

.prod-station-card-arrow {
  color: var(--text-muted);
  display: flex;
  flex-shrink: 0;
}

/* ── Vista detalle ────────────────────────────────────────────────────── */
.prod-station-header {
  background: var(--surface-overlay);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-base);
}
.prod-back-btn {
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--text-primary);
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: var(--transition-fast);
  flex-shrink: 0;
}
.prod-back-btn:hover {
  background: var(--surface-elevated);
  border-color: var(--accent);
}
.prod-back-btn[hidden] { display: none; }

.prod-station-title {
  flex: 1;
  min-width: 0;
}
.prod-station-name {
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  color: var(--text-primary);
}
.prod-station-mode {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  margin-top: 2px;
  text-transform: uppercase;
  letter-spacing: 1px;
}

/* ── Panel título extra ───────────────────────────────────────────────── */
.panel-title-hint {
  float: right;
  font-size: var(--fs-xs);
  font-weight: var(--fw-normal);
  color: var(--text-muted);
  text-transform: none;
  letter-spacing: 0;
}

/* ── Control de modo ──────────────────────────────────────────────────── */
.prod-mode-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
}
.prod-mode-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-3) var(--space-2);
  background: var(--surface-overlay);
  border: 2px solid var(--border-base);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  cursor: pointer;
  transition: var(--transition-base);
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  letter-spacing: 1px;
  text-transform: uppercase;
}
.prod-mode-btn span[data-icon] {
  font-size: calc(24px * var(--font-scale));
  display: flex;
}
.prod-mode-btn:hover:not(.is-active):not(:disabled) {
  background: var(--surface-elevated);
  border-color: var(--accent);
}
.prod-mode-btn:active:not(:disabled) {
  transform: scale(0.97);
}
.prod-mode-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.prod-mode-btn.is-active {
  background: var(--accent);
  color: var(--text-inverse);
  border-color: var(--accent-active);
  box-shadow: var(--shadow-glow-accent);
}
.prod-mode-btn.is-active.mode-manual      { background: var(--color-warning);     border-color: var(--color-warning-strong);  color: var(--text-inverse); }
.prod-mode-btn.is-active.mode-auto        { background: var(--color-success);     border-color: var(--color-success-strong);  color: var(--text-inverse); }
.prod-mode-btn.is-active.mode-audit       { background: var(--color-info);        border-color: var(--color-info-strong);     color: var(--text-inverse); }
.prod-mode-btn.is-active.mode-maintenance { background: var(--color-secondary);   border-color: var(--color-secondary-hover); color: var(--text-inverse); }

/* ── Panel OEE ────────────────────────────────────────────────────────── */
.prod-oee-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
}
.prod-oee-donut {
  position: relative;
  width: 140px;
  height: 140px;
  /* Es un <button> — reseteamos los defaults del navegador.
     Hover/focus añaden un anillo accent para que el operador sepa que
     es clicable (abre el overlay de Estadísticas → pestaña OEE). */
  background: transparent;
  border: none;
  padding: 0;
  border-radius: 50%;
  cursor: pointer;
  transition: transform var(--transition-base), box-shadow var(--transition-base);
}
.prod-oee-donut:hover {
  transform: scale(1.03);
  box-shadow: 0 0 0 2px var(--accent-soft);
}
.prod-oee-donut:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}
.prod-oee-donut:active { transform: scale(0.98); }
.prod-oee-donut svg {
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}
.prod-oee-donut-track,
.prod-oee-donut-fill {
  fill: none;
  stroke-width: 12;
  cx: 70; cy: 70; r: 56;
}
.prod-oee-donut-track { stroke: var(--surface-overlay); }
.prod-oee-donut-fill  {
  stroke: var(--accent);
  stroke-linecap: round;
  transition: stroke-dashoffset 0.6s ease, stroke 0.3s ease;
}
.prod-oee-donut-fill.is-low      { stroke: var(--color-danger); }
.prod-oee-donut-fill.is-medium   { stroke: var(--color-warning); }
.prod-oee-donut-fill.is-high     { stroke: var(--color-success); }

.prod-oee-donut-label {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
}
.prod-oee-donut-pct {
  font-size: var(--fs-xxl);
  font-weight: var(--fw-black);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.prod-oee-donut-caption {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 2px;
}

.prod-oee-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
  width: 100%;
}
.prod-oee-stat {
  text-align: center;
  padding: var(--space-2);
  background: var(--surface-overlay);
  border-radius: var(--radius-sm);
}
.prod-oee-stat-label {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 1px;
}
.prod-oee-stat-value {
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}

.prod-oee-placeholder {
  text-align: center;
  padding: var(--space-4);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  background: var(--surface-overlay);
  border-radius: var(--radius-sm);
  border: 1px dashed var(--border-base);
}
.prod-oee-placeholder code {
  background: var(--surface-elevated);
  padding: 2px 6px;
  border-radius: 3px;
  font-family: var(--font-tech);
  font-size: var(--fs-xs);
  color: var(--accent);
}

/* ── Lista de devices ─────────────────────────────────────────────────── */
.prod-devices-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  max-height: 320px;
  overflow-y: auto;
}
.prod-device-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--surface-overlay);
  border: 1px solid var(--border-base);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: var(--transition-fast);
  text-align: left;
  font-family: inherit;
  color: var(--text-primary);
}
.prod-device-row:hover {
  background: var(--surface-elevated);
  border-color: var(--accent);
}
.prod-device-row.is-fault {
  border-left: 3px solid var(--color-danger);
}
.prod-device-row-info {
  flex: 1;
  min-width: 0;
  overflow: hidden;
}
.prod-device-row-name {
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.prod-device-row-status {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.prod-device-row-arrow {
  color: var(--text-muted);
  display: flex;
  flex-shrink: 0;
}

/* ── Hotspots 3D específicos de production ────────────────────────────── */
/* Reusan estilos básicos de manual.css (.nodo-dot) — añadimos variantes */
.prod-hotspot {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--text-primary);
  cursor: pointer;
  transition: var(--transition-base);
  /* Halo neón configurable. `box-shadow` se RECORTA con clip-path (las formas
   * triángulo/hexágono/estrella del hotspot dejaban de brillar), así que
   * usamos `filter: drop-shadow()` que SÍ sigue el silueta clipeada. Cada
   * variante (fault/warning/hover/done) sólo cambia color y blur vía custom
   * properties, y la única declaración `filter` se reconstruye sola. */
  --hs-glow-color: var(--accent-soft, rgba(0, 153, 153, 0.5));
  --hs-glow-blur:  calc(10px * var(--hotspot-glow-strength, 1));
  --hs-extra-filter: brightness(1);   /* identidad: para que el espacio en
                                         var() sea siempre tokens válidos */
  filter: drop-shadow(0 0 var(--hs-glow-blur) var(--hs-glow-color)) var(--hs-extra-filter);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: calc(11px * var(--font-scale));
  font-weight: var(--fw-bold);
  color: var(--text-inverse);
}
.prod-hotspot:hover {
  transform: scale(1.2);
  --hs-glow-color: var(--accent);
  --hs-glow-blur:  calc(14px * var(--hotspot-glow-strength, 1));
}
/* Focus: el anillo azul que pintaba el navegador no respetaba el clip-path
 * NI el color del estado. Lo apagamos y reusamos el sistema de
 * --hs-glow-color (que es el color del estado en cada momento) — un halo
 * más intenso del MISMO color que el hotspot. Sirve igual para station,
 * device, action y sus variantes fault/warning/done.
 *
 * Usamos `:focus` (no `:focus-visible`) a propósito: en clicks de ratón/
 * táctil :focus-visible no dispara, y el operador quería que al SELECCIONAR
 * (= clicar) el hotspot brille en su color de estado. */
.prod-hotspot:focus {
  outline: none;
  --hs-glow-blur: calc(20px * var(--hotspot-glow-strength, 1));
}
.prod-hotspot.is-fault {
  background: var(--color-danger);
  --hs-glow-color: var(--color-danger);
  --hs-glow-blur:  calc(12px * var(--hotspot-glow-strength, 1));
}
/* La pulsación es opt-in vía Sistema → Visor 3D (Prefs.pulseFaults).
   Sin la clase body.pulse-faults el hotspot queda rojo fijo. */
body.pulse-faults .prod-hotspot.is-fault {
  animation: prod-fault-pulse 1.4s ease-in-out infinite;
}
.prod-hotspot.is-warning {
  background: var(--color-warning);
  color: var(--text-inverse);
  --hs-glow-color: var(--color-warning);
  --hs-glow-blur:  calc(11px * var(--hotspot-glow-strength, 1));
}

/* ── ESTACIÓN ────────────────────────────────────────────────────────────
   Hotspot grande circular con un anillo concéntrico pulsante.
   Lleva el número de estación dentro (1, 2, 3, …). Color accent (turquesa).
   El anillo `::before` está fuera del círculo y pulsa para llamar la
   atención de que es un punto de NAVEGACIÓN (entras en la estación).        */
.prod-hotspot.is-station {
  width: 36px;
  height: 36px;
  font-size: calc(14px * var(--font-scale));
  border-width: 3px;
  position: relative;
  /* OJO: NO declarar `background` aquí. La heredamos de .prod-hotspot
   * (var(--accent)) y las clases de estado .is-fault / .is-warning la
   * sobreescriben. Si re-añadimos `background` con la misma especificidad
   * pero después en el código, las estaciones dejan de cambiar de color
   * al entrar en falla (bug observado tras la customización de formas). */
}
/* Forma de la estación — por defecto círculo (border-radius:50%). Se cambia
 * con body[data-hotspot-station-shape="<X>"] y clip-path en el botón.
 * NOTA: para shapes que no son círculo eliminamos el border-radius y los
 * outlines del anillo pulsante (sólo tiene sentido en círculo). */
body[data-hotspot-station-shape="square"]   .prod-hotspot.is-station { border-radius: 4px; }
body[data-hotspot-station-shape="diamond"]  .prod-hotspot.is-station { border-radius: 4px; transform: rotate(45deg); }
body[data-hotspot-station-shape="diamond"]  .prod-hotspot.is-station > * { transform: rotate(-45deg); }
body[data-hotspot-station-shape="triangle"] .prod-hotspot.is-station { clip-path: polygon(50% 0%, 100% 100%, 0% 100%); border: 0; }
body[data-hotspot-station-shape="hexagon"]  .prod-hotspot.is-station { clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); border-radius: 0; }
body[data-hotspot-station-shape="star"]     .prod-hotspot.is-station { clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); border: 0; }

.prod-hotspot.is-station::before {
  content: '';
  position: absolute;
  inset: -8px;
  border-radius: 50%;
  border: 2px solid var(--accent);
  opacity: 0.6;
  animation: prod-station-ring 2s ease-in-out infinite;
  pointer-events: none;
}
/* El anillo pulsante sólo se ve bien en círculo. Para otras formas, ocultar. */
body[data-hotspot-station-shape="square"]   .prod-hotspot.is-station::before,
body[data-hotspot-station-shape="diamond"]  .prod-hotspot.is-station::before,
body[data-hotspot-station-shape="triangle"] .prod-hotspot.is-station::before,
body[data-hotspot-station-shape="hexagon"]  .prod-hotspot.is-station::before,
body[data-hotspot-station-shape="star"]     .prod-hotspot.is-station::before { display: none; }
.prod-hotspot.is-station:hover::before {
  opacity: 1;
}

@keyframes prod-station-ring {
  0%, 100% { transform: scale(1);   opacity: 0.55; }
  50%      { transform: scale(1.2); opacity: 0.10; }
}

/* ── DEVICE ──────────────────────────────────────────────────────────────
   Hotspot más pequeño con forma de ROMBO (cuadrado rotado 45°). Color
   distinto (azul info) para que de un vistazo se sepa que es un device
   y no una estación. Sin texto dentro: solo la forma habla.                  */
.prod-hotspot.is-device {
  /* La forma de ROMBO vive en ::before (pseudo-element con clip-path).
   * El propio button NO tiene clip-path para que su hijo
   * .prod-hotspot-flag (etiqueta CAD-callout) NO quede recortado al
   * salir del rombo — bug observado en docs/Captura.JPG. */
  width: 24px;
  height: 24px;
  background: transparent;
  border: 0;
  box-shadow: none;
  position: relative;
  overflow: visible;
}
.prod-hotspot.is-device {
  /* El halo va en el padre vía filter (drop-shadow sigue el clip-path). */
  --hs-glow-color: rgba(52, 152, 219, 0.55);
  --hs-glow-blur:  calc(10px * var(--hotspot-glow-strength, 1));
}
.prod-hotspot.is-device::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--color-info, #3498db);
  /* Forma diamante por defecto; body[data-hotspot-device-shape] redefine. */
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
  z-index: -1;
}
body[data-hotspot-device-shape="circle"]   .prod-hotspot.is-device::before { clip-path: circle(50%); }
body[data-hotspot-device-shape="square"]   .prod-hotspot.is-device::before { clip-path: none; border-radius: 4px; }
body[data-hotspot-device-shape="triangle"] .prod-hotspot.is-device::before { clip-path: polygon(50% 0%, 100% 100%, 0% 100%); }
body[data-hotspot-device-shape="hexagon"]  .prod-hotspot.is-device::before { clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); }
body[data-hotspot-device-shape="star"]     .prod-hotspot.is-device::before { clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); }
.prod-hotspot.is-device:hover { transform: scale(1.18); }
.prod-hotspot.is-device.is-fault {
  --hs-glow-color: var(--color-danger);
  --hs-glow-blur:  calc(13px * var(--hotspot-glow-strength, 1));
}
.prod-hotspot.is-device.is-fault::before {
  background: var(--color-danger);
}

/* Hotspot oculto: no se renderiza visualmente y no recibe clicks.
   Se usa para alternar entre vista de estaciones (default) y vista de
   devices de la estación seleccionada. */
.prod-hotspot.is-hidden {
  opacity: 0;
  pointer-events: none;
  transform: scale(0.5);
}
.prod-hotspot.is-device.is-hidden {
  transform: scale(0.5);
}
/* Anima la aparición/desaparición */
.prod-hotspot {
  transition: opacity 0.25s ease, transform 0.25s ease, box-shadow 0.25s ease, background-color 0.25s ease;
}

/* ── Leyenda de hotspots ────────────────────────────────────────────────
 * Aparece SOLO cuando hay estación seleccionada y está en modo manual.
 * Es un overlay esquina superior-derecha del visor, con dos filas
 * clicables (Dispositivos / Acciones). Cada click toggla un atributo
 * en el body (data-hide-devices, data-hide-actions) que esconde los
 * hotspots correspondientes via reglas más abajo. */
.prod-legend {
  /* Justo encima de la sequence bar, esquina inferior-izquierda. La
   * seq bar mide ~90-110 px (depende de --font-scale), dejamos 12 px
   * de hueco entre ambas para que respire visualmente. */
  position: absolute;
  bottom: calc(var(--space-4) + 110px);
  left: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2) var(--space-2);
  /* Bajada de opacidad a 0.55 — antes 0.88 ocultaba la maquinaria detrás.
   * Aumentamos el blur para que el contenido siga siendo legible sobre
   * cualquier fondo. */
  background: rgba(20, 24, 30, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: var(--radius-md);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  z-index: 14;
  color: #fff;
  font-size: var(--fs-xs);
  user-select: none;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
.prod-legend[hidden] { display: none; }
body.light-mode .prod-legend {
  background: rgba(255, 255, 255, 0.65);
  border-color: rgba(15, 23, 42, 0.15);
  color: var(--neutral-800, #1e293b);
}
.prod-legend-title {
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  opacity: 0.6;
  padding: 0 var(--space-1) 2px;
}
.prod-legend-row[hidden] { display: none; }
.prod-legend-row {
  display: grid;
  grid-template-columns: 24px 1fr 16px;
  align-items: center;
  gap: var(--space-2);
  padding: 6px var(--space-2);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  color: inherit;
  cursor: pointer;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  transition: background var(--transition-fast);
}
.prod-legend-row:hover {
  background: rgba(255, 255, 255, 0.08);
}
body.light-mode .prod-legend-row:hover {
  background: rgba(15, 23, 42, 0.06);
}
/* Markers genéricos en la leyenda — un cuadrado base que cada variante
 * deforma con clip-path (rombo, hexágono...) para imitar la forma real
 * del hotspot que representa en el visor 3D. */
.prod-legend-marker {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  background: #fb923c;
  border: 2px solid #fff;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.4);
}
/* Dispositivo: rombo cyan, sin icono interior — matchea exactamente el
 * .prod-hotspot.is-device del visor (clip-path en pseudo-element). */
.prod-legend-marker-device {
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
  background: #06b6d4;
  border: 0;
  box-shadow: 0 0 6px rgba(6, 182, 212, 0.55);
}
/* Acción: hexágono naranja con ▶ blanco — matchea el hotspot real. */
.prod-legend-marker-action {
  clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
  background: #ff7a00;
  border-color: #fff;
  color: #fff;
}
.prod-legend-marker-action svg {
  margin-left: 1px;   /* compensa el centro óptico del triángulo */
}
/* Etiqueta: mini callout (chip + leader line + dot), réplica del flag
 * real del visor. El marker hace de "contenedor" para los 3 elementos. */
.prod-legend-marker-label {
  background: transparent;
  border: 0;
  box-shadow: none;
  position: relative;
  width: 18px;
  height: 18px;
  /* Más alto que el resto para que entren chip+línea+punto sin amontonarse */
  margin-top: -2px;
  margin-bottom: -2px;
}
.prod-legend-callout-chip {
  position: absolute;
  top: -2px;
  left: 50%;
  transform: translateX(-50%);
  padding: 0 4px;
  background: rgba(15, 20, 28, 0.95);
  color: #fff;
  font-size: 8px;
  font-weight: var(--fw-bold);
  border-radius: 2px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  line-height: 1.2;
  white-space: nowrap;
}
.prod-legend-callout-line {
  position: absolute;
  top: 10px;
  left: 50%;
  width: 1px;
  height: 7px;
  margin-left: -0.5px;
  background: rgba(255, 255, 255, 0.55);
}
.prod-legend-callout-dot {
  position: absolute;
  top: 16px;
  left: 50%;
  width: 4px;
  height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.85);
}
body.light-mode .prod-legend-callout-chip {
  background: rgba(255, 255, 255, 0.96);
  color: var(--neutral-800, #1e293b);
  border-color: rgba(15, 23, 42, 0.2);
}
body.light-mode .prod-legend-callout-line { background: rgba(15, 23, 42, 0.55); }
body.light-mode .prod-legend-callout-dot  { background: rgba(15, 23, 42, 0.85); }
.prod-legend-eye-off { display: none; }
/* Cuando el toggle está OFF, el row muestra el ojo tachado y queda atenuado. */
.prod-legend-row[data-state="off"] .prod-legend-eye { display: none; }
.prod-legend-row[data-state="off"] .prod-legend-eye-off { display: inline-block; }
.prod-legend-row[data-state="off"] { opacity: 0.45; }

/* Atributos en body para esconder cada tipo de hotspot. Usamos display:none
 * para liberar pointer-events y evitar interacción accidental. */
body[data-hide-devices="1"] .prod-hotspot.is-device { display: none; }
body[data-hide-actions="1"] .prod-hotspot.is-action { display: none; }
/* `data-hide-labels` esconde SOLO los flags (no los hotspots). Los rombos
 * y hexágonos siguen visibles, sólo desaparece la etiqueta de texto. */
body[data-hide-labels="1"]  .prod-hotspot-flag    { display: none; }

/* ── Hotspots de ACCIÓN ──────────────────────────────────────────────────
 * Distintos de los de device: hexágono más grande, naranja brillante con
 * icono play interior y flag de texto "ACCIÓN <Name>" encima. Solo
 * visibles cuando station está en modo MANUAL. `is-done` (Stat=true) los
 * pinta en verde con !important para que ningún hover/transition pueda
 * sobreescribir el indicador de "completado". */
.prod-hotspot.is-action {
  /* La forma de HEXÁGONO vive en ::before — el button NO tiene
   * clip-path para que .prod-hotspot-flag (etiqueta callout) NO quede
   * recortada al salir del hexágono. Tamaño FIJO igual al de device
   * (24px) — antes era 30px × font-scale y al alejar la cámara los
   * action hotspots se veían desproporcionados respecto a los devices. */
  width:  24px;
  height: 24px;
  background: transparent;
  border: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: visible;
  color: #fff;
}
.prod-hotspot.is-action {
  /* Halo en el padre vía drop-shadow para que respete el clip-path
   * (hexágono/diamante/triángulo/estrella) — el box-shadow anterior se
   * recortaba con la forma y los halos desaparecían en cuanto la forma
   * no era cuadrado. */
  --hs-glow-color: rgba(255, 122, 0, 0.55);
  --hs-glow-blur:  calc(10px * var(--hotspot-glow-strength, 1));
}
.prod-hotspot.is-action::before {
  content: "";
  position: absolute;
  inset: 0;
  background: #ff7a00;
  border: 3px solid #fff;
  box-sizing: border-box;
  /* Hexágono por defecto; body[data-hotspot-action-shape] redefine. */
  clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
  z-index: -1;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
body[data-hotspot-action-shape="circle"]   .prod-hotspot.is-action::before { clip-path: circle(50%); }
body[data-hotspot-action-shape="square"]   .prod-hotspot.is-action::before { clip-path: none; border-radius: 4px; }
body[data-hotspot-action-shape="diamond"]  .prod-hotspot.is-action::before { clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); }
body[data-hotspot-action-shape="triangle"] .prod-hotspot.is-action::before { clip-path: polygon(50% 0%, 100% 100%, 0% 100%); }
body[data-hotspot-action-shape="star"]     .prod-hotspot.is-action::before { clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); }
.prod-hotspot.is-action:hover {
  transform: scale(1.12);
  --hs-glow-color: rgba(255, 122, 0, 0.75);
  --hs-glow-blur:  calc(13px * var(--hotspot-glow-strength, 1));
}
/* `pressing` añade brightness al filter SIN romper el drop-shadow — usa la
 * variable --hs-extra-filter que `.prod-hotspot` base concatena al final. */
.prod-hotspot.is-action.pressing {
  --hs-extra-filter: brightness(1.35);
  transform: scale(0.95);
}
/* Verde rotundo cuando Stat=true. El halo también respeta --hotspot-glow-strength. */
.prod-hotspot.is-action.is-done {
  --hs-glow-color: rgba(34, 197, 94, 0.95);
  --hs-glow-blur:  calc(13px * var(--hotspot-glow-strength, 1));
}
.prod-hotspot.is-action.is-done::before {
  background: #16a34a;
  border-color: #d1fae5;
}
.prod-hotspot.is-action.is-hidden {
  opacity: 0;
  pointer-events: none;
  transform: scale(0.5);
}
/* Icono play (▶) dentro del hexágono — refuerza que es un trigger. */
.prod-hotspot-action-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  margin-left: 2px;   /* compensa el centro óptico del triángulo */
}

/* Flag con el nombre del elemento (acción o device), colocado OFFSET hacia
 * arriba con una "leader line" (estilo callout CAD) que conecta visualmente
 * el chip con el hotspot. Operador identifica el elemento desde lejos sin
 * tener que hacer hover.
 *
 * El offset es bastante grande (-58px) para que la línea sea visible
 * incluso con hotspots muy juntos. Si la legend toggle "Etiquetas" está
 * OFF, body[data-hide-labels="1"] esconde TODO el flag (línea incluida). */
.prod-hotspot-flag {
  position: absolute;
  bottom: calc(100% + 22px);   /* 22 px de hueco para la leader line */
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  background: rgba(15, 20, 28, 0.95);
  color: #fff;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(255, 255, 255, 0.22);
  white-space: nowrap;
  pointer-events: none;
  overflow: visible;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.55);
}
/* Leader line vertical: desde bottom-center del chip hacia abajo, hasta el
 * hotspot. Es un pseudo-element en absolute con altura fija que coincide
 * con el bottom-offset (22px). */
.prod-hotspot-flag::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  width: 1.5px;
  height: 16px;                      /* alcanza el borde del hotspot */
  margin-left: -0.75px;
  background: rgba(255, 255, 255, 0.55);
  pointer-events: none;
}
/* Pequeño punto al final de la línea (donde toca el hotspot), refuerza la
 * sensación de callout CAD. */
.prod-hotspot-flag::before {
  content: "";
  position: absolute;
  top: calc(100% + 14px);
  left: 50%;
  width: 5px;
  height: 5px;
  margin-left: -2.5px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.85);
  pointer-events: none;
}
.prod-hotspot-flag-tag {
  background: #ff7a00;
  color: #fff;
  padding: 5px 8px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
}
.prod-hotspot-flag-name {
  padding: 5px 12px;
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
}
body.light-mode .prod-hotspot-flag {
  background: rgba(255, 255, 255, 0.96);
  color: var(--neutral-800, #1e293b);
  border-color: rgba(15, 23, 42, 0.18);
}
/* Cuando la acción está done, el pill TAG también vira a verde para
 * coherencia visual con el hexágono. */
.prod-hotspot.is-action.is-done .prod-hotspot-flag-tag {
  background: #16a34a;
}

/* Variante del flag para hotspots de DEVICE: pill cyan (color del rombo)
 * en lugar de naranja. Operador distingue de un vistazo "Action" naranja
 * vs "Robot/Servo/..." cyan. */
.prod-hotspot-flag-device .prod-hotspot-flag-tag {
  background: #06b6d4;
}
/* Cuando el device está en fault, el pill TAG también vira a rojo. */
.prod-hotspot.is-device.is-fault .prod-hotspot-flag-tag {
  background: var(--color-danger);
}

/* Variante del flag para hotspots de STATION: el pill TAG ("ST<n>")
 * refleja el estado de la estación — verde OK, amarillo warning, rojo
 * fault, gris undef. Sin el estado mapeado, los labels TODOS aparecían
 * con el mismo color (heredando el default naranja de .prod-hotspot-flag-tag).
 *
 * Aplican mismas clases que pinta computeStationStateClass: is-ok,
 * is-warning, is-fault, is-undef. Si no hay clase de estado, default
 * al accent del sistema (mismo color que el hotspot redondo en idle). */
.prod-hotspot-flag-station .prod-hotspot-flag-tag {
  background: var(--accent);
}
.prod-hotspot.is-station.is-ok      .prod-hotspot-flag-tag { background: var(--color-success); }
/* `--color-warning` (#f1c40f) era demasiado claro: el texto blanco encima
 * apenas se leía. Bajamos a un amber más oscuro mantenendo el tono cálido
 * de \"warning\" (#d97706 = amber-600), que pasa contraste WCAG AA con #fff. */
.prod-hotspot.is-station.is-warning .prod-hotspot-flag-tag { background: #d97706; }
.prod-hotspot.is-station.is-fault   .prod-hotspot-flag-tag { background: var(--color-danger); }
.prod-hotspot.is-station.is-undef   .prod-hotspot-flag-tag { background: var(--text-muted); }

@keyframes prod-fault-pulse {
  /* Animamos `filter` en vez de `box-shadow` por la misma razón que el resto
   * del módulo: el box-shadow se recorta con clip-path (devices/actions con
   * forma no-cuadrada perdían el pulso). drop-shadow sigue el silueta. */
  0%, 100% { filter: drop-shadow(0 0 calc(12px * var(--hotspot-glow-strength, 1)) var(--color-danger)); transform: scale(1);    }
  50%      { filter: drop-shadow(0 0 calc(20px * var(--hotspot-glow-strength, 1)) var(--color-danger)); transform: scale(1.1);  }
}
/* En la versión de device el pulso ya no necesita rotación (clip-path lo
 * hace gráficamente sin transform). Usa el mismo keyframe que el genérico. */
.prod-hotspot.is-device.is-fault {
  animation: prod-fault-pulse 1.4s ease-in-out infinite;
}

/* ── Modo claro ──────────────────────────────────────────────────────── */
body.light-mode .prod-sidebar {
  background: #fff;
  border-left-color: var(--neutral-200);
}
body.light-mode .prod-station-card,
body.light-mode .prod-device-row,
body.light-mode .prod-station-header,
body.light-mode .prod-oee-stat {
  background: var(--neutral-50);
  border-color: var(--neutral-200);
  color: var(--neutral-900);
}
body.light-mode .prod-station-card-name,
body.light-mode .prod-station-name,
body.light-mode .prod-device-row-name,
body.light-mode .prod-oee-donut-pct,
body.light-mode .prod-oee-stat-value {
  color: var(--neutral-900);
}
body.light-mode .prod-station-card-meta,
body.light-mode .prod-station-mode,
body.light-mode .prod-device-row-status {
  color: var(--neutral-500);
}
body.light-mode .prod-mode-btn {
  background: var(--neutral-50);
  border-color: var(--neutral-200);
  color: var(--neutral-900);
}
body.light-mode .prod-oee-donut-track {
  stroke: var(--neutral-100);
}

/* ── FACEPLATE MODERNO DE DEVICE EN PRODUCCIÓN ─────────────────────────── */
/* Reemplazo del popup genérico de showDialog por un faceplate compacto y
   coherente para todos los tipos de device. Layout en 4 zonas:
   1) Header con icono+eyebrow+name+pill de estado+cerrar
   2) Cards de datos numéricos (FaultCode, Programa, etc.)
   3) Grid de indicadores boolean
   4) Footer con CERRAR + IR A CONTROL MANUAL (condicionado)                */

/* ── Anchor común para los DOS faceplates en producción ──────────────
   Tanto el faceplate informativo (.prod-faceplate) como el popup de
   control manual (#cylinderModal en production.html) viven dentro del
   contenedor del visor y se anclan en la MISMA esquina superior-derecha
   del visor. Los station-banners ocupan la esquina superior-izquierda,
   por lo que no hay solapamiento.

   IMPORTANTE: para #cylinderModal sólo tocamos posición y z-index. NO
   forzamos overflow/max-height: la animación interna de
   .popup-faceplate (transform translateY+scale) y su layout dependen
   de que el contenedor le deje fluir. */
/* z-index 1500 deja ambos popups POR ENCIMA del header global
   (.hmi-header-wrapper tiene z-index: 1000). Es necesario aunque
   ambos popups vivan dentro del visor: el header crea su propio
   stacking context y, si un popup llega a tocar visualmente el área
   del header (popup alto en pantallas cortas, sombras…), el header
   ganaría. Mantenerlos por encima resuelve cualquier solape. */
/* AMBOS popups posicionados con `position: fixed` + valores anclados al
   viewport. Esto bypassa cualquier ambigüedad sobre el bloque
   contenedor (model-viewer, viewer-container, body, etc.) y garantiza
   que el popup se sitúe siempre en el mismo punto.

   Layout:
     · top: 110px → bajo el header (~96-110px alto típico).
     · right: 460px → deja sitio a la sidebar (420px) + margen.
     · bottom: 24px → la altura se ajusta automáticamente al espacio
       disponible (top + bottom anclados → height = viewport - top - bottom).
     · max-height/overflow → si el contenido es más alto, scroll interno.
     · z-index 2500 → por encima del header (z=1000).
*/
/* Posicionamiento compartido: ambos popups anclados arriba-derecha del
   viewport, sin `bottom`. La altura es AUTO para que el popup se
   ajuste al contenido (panel de control compacto → no hay scroll).
   `max-height` cap más `overflow-y: auto` sólo activan scroll cuando
   el contenido supera el alto disponible (típicamente al abrir el
   panel de parámetros del device, que es más alto). */
/* ── POPUPS ACOPLADOS A LA SIDEBAR ─────────────────────────────────────
   Los popups ahora son hijos del wrapper interno `.prod-sidebar-body`
   (antes lo eran directos del aside; el wrapper apareció para que el
   asa/dock posicionados con left negativo no fueran clippeados por el
   overflow del aside). Cuando se activan (prod-faceplate.is-open o
   cylinderModal.active) toman el ancho/alto disponibles y el JS añade
   .has-docked-popup al sidebar para esconder el listado/detalle de
   estaciones. Con esto evitamos el flotante encima del visor 3D que
   con fuentes grandes no cabía en pantallas pequeñas.

   La animación de aparición de .prod-faceplate (translateY+scale)
   sigue intacta — solo cambiamos posicionamiento. */
body.prod-page .prod-sidebar-body > .prod-faceplate,
body.prod-page .prod-sidebar-body > #cylinderModal.hmi-float-window {
  position: static !important;
  top:    auto !important;
  right:  auto !important;
  left:   auto !important;
  bottom: auto !important;
  width:  100% !important;
  max-width:  100% !important;
  max-height: 100% !important;
  /* El wrapper interno gestiona el scroll con overflow-y: auto. Aquí
     dejamos visible para que el contenido del popup se sume al flujo
     vertical del sidebar y nunca aparezcan DOS scrollbars anidadas. */
  overflow: visible !important;
  z-index: auto !important;
}
body.prod-page .prod-sidebar-body > #cylinderModal.hmi-float-window {
  transform: none !important;
}

/* Cuando hay un popup acoplado, escondemos el listado y el detalle de
   estaciones para que el popup ocupe TODA la sidebar (full width + height
   visibles, sin scroll innecesario por contenido duplicado). */
.prod-sidebar.has-docked-popup .prod-sidebar-body > .prod-section { display: none !important; }

/* Quitamos el gap/padding extra del wrapper mientras hay popup acoplado:
   queremos que el popup ocupe el área completa, no quede una banda de
   color del sidebar alrededor. El popup ya trae su propio padding. */
.prod-sidebar.has-docked-popup .prod-sidebar-body {
  padding: 0;
  gap: 0;
}

body.prod-page #cylinderModal.hmi-float-window > .faceplate,
body.prod-page #cylinderModal.hmi-float-window > .popup-faceplate {
  margin: 0;
}

/* ────────────────────────────────────────────────────────────────────────
 * BARRA INFERIOR DE CONTROL DE SECUENCIAS (Graph)
 *
 * Overlay anclado al borde inferior del visor 3D. NO se solapa con la
 * sidebar derecha. Cuatro grupos (Globales, HOME, AUTO, CUSTOM) en una
 * pill con glass-morphism. Cada grupo tiene icono, label coloreado y
 * controles. AUTO se OCULTA fuera de modo auto. CUSTOM aparece sólo si
 * la estación declara custom_buttons; los botones viven en un popover
 * que se abre al click del chevron — igual patrón que HOME / AUTO.
 * ──────────────────────────────────────────────────────────────────────── */

.prod-seq-bar {
  position: absolute;
  left:   var(--space-4);
  right:  var(--space-4);
  bottom: var(--space-4);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: calc(var(--space-2) + 2px) var(--space-3);
  background: linear-gradient(
    180deg,
    rgba(32, 38, 46, 0.85),
    rgba(20, 24, 30, 0.88)
  );
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-xl);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  z-index: 12;
  pointer-events: auto;
  box-shadow:
    0 12px 32px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.prod-seq-bar[hidden] { display: none; }

/* Cualquier `prod-seq-group` con `display: flex` tiene mayor especificidad
 * que el `[hidden]` del user-agent stylesheet, así que sin esta regla el
 * atributo `hidden` no funciona y los grupos quedan siempre visibles
 * (bug: AUTO se veía en MANUAL, CUSTOM se veía sin botones, etc.). */
.prod-seq-group[hidden] { display: none; }

body.light-mode .prod-seq-bar {
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.92),
    rgba(241, 245, 249, 0.92)
  );
  border-color: rgba(15, 23, 42, 0.10);
  box-shadow:
    0 12px 32px rgba(15, 23, 42, 0.18),
    inset 0 1px 0 rgba(255, 255, 255, 0.7);
}

/* Cada grupo es una "isla" con padding. Position relative porque ancla el
 * popover absolute. Separador soft entre grupos via gradient. */
.prod-seq-group {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
  gap: var(--space-2);
  padding: 0 var(--space-3);
}
.prod-seq-group + .prod-seq-group::before {
  content: "";
  position: absolute;
  left: 0;
  top: 22%;
  bottom: 22%;
  width: 1px;
  background: linear-gradient(
    to bottom,
    transparent,
    rgba(255, 255, 255, 0.12) 30%,
    rgba(255, 255, 255, 0.12) 70%,
    transparent
  );
}
body.light-mode .prod-seq-group + .prod-seq-group::before {
  background: linear-gradient(
    to bottom,
    transparent,
    rgba(15, 23, 42, 0.12) 30%,
    rgba(15, 23, 42, 0.12) 70%,
    transparent
  );
}

/* Cabecera del grupo: icono + label + chevron opcional. Label coloreado
 * por tipo de grupo para identificación visual rápida. */
.prod-seq-group-title {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--fs-xs);
  font-weight: var(--fw-black);
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--text-muted);
}
.prod-seq-group-icon {
  display: inline-flex;
  width:  calc(14px * var(--font-scale));
  height: calc(14px * var(--font-scale));
  color: inherit;
}
.prod-seq-group-icon svg { width: 100%; height: 100%; }

.prod-seq-group-globals .prod-seq-group-title { color: var(--text-secondary); }
.prod-seq-group-home    .prod-seq-group-title { color: var(--color-info); }
.prod-seq-group-auto    .prod-seq-group-title { color: var(--color-success); }
.prod-seq-group-custom  .prod-seq-group-title { color: var(--color-warning); }

.prod-seq-controls {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* LED indicator (Sequence_Active, Stat_All, InCycle). Estilo "indicador
 * empotrado": shadow inset para off, radial gradient + glow para on. */
.prod-seq-led {
  width:  calc(14px * var(--font-scale));
  height: calc(14px * var(--font-scale));
  border-radius: 50%;
  background: var(--surface-elevated);
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, 0.55),
    inset 0 -1px 1px rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(0, 0, 0, 0.4);
  transition: background var(--transition-base), box-shadow var(--transition-base);
  flex-shrink: 0;
}
.prod-seq-led[data-state="on"] {
  background: radial-gradient(circle at 30% 30%, #6bf3a0, #1f9e54);
  border-color: rgba(72, 201, 176, 0.6);
  box-shadow:
    0 0 14px rgba(72, 201, 176, 0.65),
    inset 0 1px 2px rgba(255, 255, 255, 0.35);
}

/* "paso N" — pill compacto con tabular-nums para que el dígito no salte. */
.prod-seq-step-display {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-1);
  font-family: var(--font-tech);
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.04);
}
body.light-mode .prod-seq-step-display { background: rgba(15, 23, 42, 0.05); }
.prod-seq-step-label {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  color: var(--text-muted);
  letter-spacing: 0.5px;
}
.prod-seq-step-value {
  font-size: var(--fs-base);
  font-weight: var(--fw-bold);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

/* STEP MODE — toggle visual; cuando is-active modo paso-a-paso está ON.
 * Glow amarillo para distinguirlo del resto. */
.prod-seq-step-btn.is-active {
  background: var(--color-warning-soft);
  border-color: var(--color-warning);
  color: var(--color-warning);
  box-shadow: 0 0 12px var(--color-warning-soft);
}

/* ABORT ALL hold-to-set: feedback visual del press. */
.prod-seq-abort.pressing {
  filter: brightness(1.6) saturate(120%);
  transform: scale(0.97);
}

/* Toggle del grupo con chevron — el title MISMO es el botón. */
.prod-seq-group-toggle {
  background: transparent;
  border: none;
  padding: 2px 0;
  cursor: pointer;
  user-select: none;
  touch-action: none;
  transition: opacity var(--transition-base);
}
.prod-seq-group-toggle:hover { opacity: 0.85; }
.prod-seq-chevron {
  display: inline-flex;
  transition: transform var(--transition-base);
  margin-left: 2px;
  width:  calc(12px * var(--font-scale));
  height: calc(12px * var(--font-scale));
}
.prod-seq-group-toggle.is-open .prod-seq-chevron {
  transform: rotate(180deg);
}

/* Popover (HOME / AUTO / CUSTOM). Float UP del grupo, glass-morphism
 * profundo, animación fade-up al abrir. */
.prod-seq-popover {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 0;
  min-width: calc(280px * var(--font-scale));
  max-width: calc(440px * var(--font-scale));
  background: linear-gradient(
    180deg,
    rgba(40, 46, 54, 0.96),
    rgba(28, 32, 38, 0.96)
  );
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: var(--radius-lg);
  box-shadow:
    0 16px 40px rgba(0, 0, 0, 0.55),
    inset 0 1px 0 rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(12px) saturate(140%);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  padding: var(--space-3);
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  animation: prodSeqPopFadeIn 0.18s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes prodSeqPopFadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.prod-seq-popover[hidden] { display: none; }
body.light-mode .prod-seq-popover {
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.98),
    rgba(241, 245, 249, 0.98)
  );
  border-color: rgba(15, 23, 42, 0.10);
  box-shadow:
    0 16px 40px rgba(15, 23, 42, 0.22),
    inset 0 1px 0 rgba(255, 255, 255, 0.6);
}

.prod-seq-popover-empty {
  padding: var(--space-3);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-style: italic;
}

/* CUSTOM popover: ancla a la derecha del grupo (que es el más a la derecha
 * del bar). Si anclase a la izquierda (default `.prod-seq-popover`), su
 * contenido se desbordaría por la derecha del bar y quedaría tapado por la
 * sidebar de control. */
.prod-seq-popover-custom {
  left: auto;
  right: 0;
}
/* CUSTOM popover: grid auto-fit de botones (no filas como subseqs). */
.prod-seq-popover-custom .prod-seq-popover-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(calc(160px * var(--font-scale)), 1fr));
  gap: var(--space-2);
}
.prod-seq-custom-btn {
  padding: calc(var(--space-2) + 1px) var(--space-3);
  font-size: var(--fs-sm);
  letter-spacing: 0.5px;
  transition:
    background var(--transition-fast),
    border-color var(--transition-fast),
    color var(--transition-fast),
    box-shadow var(--transition-fast),
    transform 0.08s ease;
}
.prod-seq-custom-btn:active { transform: scale(0.97); }
.prod-seq-custom-btn.is-toggle.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text-inverse);
  box-shadow: 0 0 14px var(--accent-soft);
}
.prod-seq-custom-btn.is-hold.is-active,
.prod-seq-custom-btn.is-hold.pressing {
  background: var(--color-warning);
  border-color: var(--color-warning-strong);
  color: var(--text-inverse);
  box-shadow: 0 0 14px var(--color-warning-soft);
}

/* Una fila por subsecuencia dentro del popover HOME / AUTO. */
.prod-seq-subrow {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.04);
  transition: background var(--transition-base);
}
.prod-seq-subrow:hover { background: rgba(255, 255, 255, 0.08); }
body.light-mode .prod-seq-subrow       { background: rgba(15, 23, 42, 0.04); }
body.light-mode .prod-seq-subrow:hover { background: rgba(15, 23, 42, 0.08); }
.prod-seq-subrow-name {
  font-family: var(--font-tech);
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  letter-spacing: 0.5px;
}
.prod-seq-subrow-action {
  padding: var(--space-1) var(--space-3);
  font-size: var(--fs-xs);
}

/* Estado cerrado/abierto del faceplate de producción. */
.prod-faceplate {
  opacity: 0;
  pointer-events: none;
  transform: translateY(-8px) scale(0.97);
  transition: opacity 0.22s ease, transform 0.22s ease;
}
.prod-faceplate.is-open {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0) scale(1);
}

.prod-fp-card-root {
  background: var(--surface-raised);
  border: 1px solid var(--border, #444);
  border-radius: var(--radius-xl);
  padding: var(--space-5);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.45);
}

/* Header */
.prod-fp-header {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  margin-bottom: var(--space-4);
}
.prod-fp-icon {
  width: 44px;
  height: 44px;
  border-radius: var(--radius-lg);
  background: var(--color-info-soft);
  color: var(--color-info);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.prod-fp-icon span[data-icon] svg { width: 24px; height: 24px; }
.prod-fp-title { flex: 1; min-width: 0; }
.prod-fp-eyebrow {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 1px;
  font-weight: var(--fw-medium);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prod-fp-name {
  font-size: var(--fs-lg);
  color: var(--text-primary);
  font-weight: var(--fw-medium);
  margin-top: 2px;
  /* Permitimos hasta 2 líneas para no truncar nombres largos del PLC.
     Si excede, ahí sí ellipsis vertical. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
  line-height: 1.25;
}
.prod-fp-status-pill {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: var(--radius-md);
  font-size: calc(12px * var(--font-scale));
  font-weight: var(--fw-medium);
  white-space: nowrap;
  flex-shrink: 0;
  border: 1px solid;
}
.prod-fp-status-pill.is-ok {
  background: var(--color-success-soft);
  color: var(--color-success);
  border-color: var(--color-success-soft);
}
.prod-fp-status-pill.is-fault {
  background: var(--color-danger-soft);
  color: var(--color-danger);
  border-color: var(--color-danger-soft);
}
.prod-fp-status-pill.is-undef {
  background: rgba(149, 165, 166, 0.12);
  color: var(--text-muted);
  border-color: rgba(149, 165, 166, 0.25);
}
.prod-fp-status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 8px currentColor;
}
.prod-fp-status-pill.is-undef .prod-fp-status-dot { box-shadow: none; }

.prod-fp-close {
  background: transparent;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  padding: 8px;
  border-radius: var(--radius-md);
  transition: background 0.15s, color 0.15s;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.prod-fp-close:hover {
  background: var(--surface-overlay);
  color: var(--text-primary);
}
.prod-fp-close span[data-icon] svg { width: 20px; height: 20px; }

/* Banda de Status — sección destacada entre header y cards. Muestra el
   código numérico (grande) y el texto traducido. Color según el estado
   (ok/fault/undef) para que se vea de un vistazo. */
.prod-fp-status-band {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-lg);
  border: 1px solid;
  margin-bottom: var(--space-4);
}
.prod-fp-status-band.is-ok {
  background: var(--color-success-soft);
  border-color: rgba(72, 201, 176, 0.3);
}
.prod-fp-status-band.is-fault {
  background: var(--color-danger-soft);
  border-color: rgba(216, 59, 78, 0.4);
}
.prod-fp-status-band.is-undef {
  background: var(--surface-overlay);
  border-color: rgba(255, 255, 255, 0.06);
}
.prod-fp-status-band-lbl {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 1px;
  font-weight: var(--fw-medium);
  color: var(--text-muted);
  flex-shrink: 0;
  min-width: 50px;
}
.prod-fp-status-band-body {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  flex: 1;
  min-width: 0;
}
.prod-fp-status-band-code {
  font-family: var(--font-tech, "Courier New", monospace);
  font-size: calc(28px * var(--font-scale));
  font-weight: var(--fw-bold);
  line-height: 1;
  flex-shrink: 0;
}
.prod-fp-status-band.is-ok    .prod-fp-status-band-code { color: var(--color-success); }
.prod-fp-status-band.is-fault .prod-fp-status-band-code { color: var(--color-danger); }
.prod-fp-status-band.is-undef .prod-fp-status-band-code { color: var(--text-muted); }
.prod-fp-status-band-text {
  font-size: calc(15px * var(--font-scale));
  font-weight: var(--fw-medium);
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Cards de datos numéricos */
.prod-fp-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
/* Servo: layout fijo Posición (2x) / Velocidad / Par — equivalente al
   KPI grid del popup manual del servo, para mantener el ojo del operador
   en el mismo sitio al pasar manual ↔ producción. */
.prod-fp-cards.is-servo-layout {
  grid-template-columns: 2fr 1fr 1fr;
}
.prod-fp-card {
  background: var(--surface-overlay);
  padding: var(--space-3) var(--space-3);
  border-radius: var(--radius-lg);
  min-height: 64px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.prod-fp-card.is-accent {
  border-left: 3px solid var(--color-warning-strong);
  padding-left: calc(var(--space-3) - 3px);
}
.prod-fp-card-lbl {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.8px;
  font-weight: var(--fw-medium);
}
.prod-fp-card-val {
  font-size: calc(16px * var(--font-scale));
  color: var(--text-primary);
  font-weight: var(--fw-medium);
  margin-top: 4px;
  word-break: break-word;
}
.prod-fp-card-val.is-mono {
  font-family: var(--font-tech, "Courier New", monospace);
  font-size: calc(20px * var(--font-scale));
}

/* Sección de indicadores boolean */
.prod-fp-section-lbl {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 1px;
  font-weight: var(--fw-medium);
  margin: var(--space-3) 0 var(--space-2);
}
/* Grid fijo 2-col: los pares lógicos (BWD/FWD, Home/Work, Cond Bwd/Fwd)
   NUNCA se rompen a filas separadas. La lógica de collectBoolIndicators()
   agrupa los pares para que caigan en la misma fila. */
.prod-fp-bools {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
}
.prod-fp-bool.is-full { grid-column: 1 / -1; }
.prod-fp-bool {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--radius-lg);
  border: 1px solid;
  background: var(--surface-overlay);
}
.prod-fp-bool.is-on {
  background: var(--color-success-soft);
  border-color: rgba(72, 201, 176, 0.3);
}
.prod-fp-bool.is-off {
  background: var(--surface-overlay);
  border-color: rgba(255, 255, 255, 0.06);
}
/* Indicador de fallo (Fault/Alarm/Error): off = tinte de alerta latente,
   on = fallo activo en rojo. Paridad visual con .state-badge.is-fault-prone /
   .is-active-danger del popup manual. */
.prod-fp-bool.is-fault.is-off {
  border-color: color-mix(in srgb, var(--color-danger) 30%, var(--border-base));
}
.prod-fp-bool.is-fault.is-on {
  background: var(--color-danger-soft);
  border-color: var(--color-danger);
}
.prod-fp-bool.is-fault.is-on .prod-fp-bool-led {
  background: var(--color-danger);
  box-shadow: 0 0 6px var(--color-danger);
}
.prod-fp-bool.is-fault.is-on .prod-fp-bool-val { color: var(--color-danger); }
.prod-fp-bool-led {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.prod-fp-bool.is-on .prod-fp-bool-led {
  background: var(--color-success);
  box-shadow: 0 0 6px var(--color-success);
}
.prod-fp-bool.is-off .prod-fp-bool-led {
  background: #4b5563;
}
.prod-fp-bool-body { flex: 1; min-width: 0; }
.prod-fp-bool-lbl {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prod-fp-bool-val {
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
}
.prod-fp-bool.is-on .prod-fp-bool-val { color: var(--color-success); }
.prod-fp-bool.is-off .prod-fp-bool-val { color: var(--text-muted); }

.prod-fp-empty {
  grid-column: 1 / -1;
  text-align: center;
  padding: var(--space-3);
  color: var(--text-muted);
  font-style: italic;
  font-size: var(--fs-base);
}

/* Footer con botones */
.prod-fp-footer {
  display: flex;
  gap: 10px;
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.prod-fp-btn {
  padding: 10px 16px;
  border-radius: var(--radius-lg);
  cursor: pointer;
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  letter-spacing: 0.5px;
  transition: all 0.15s ease;
  border: 1px solid;
}
.prod-fp-btn span[data-icon] svg { width: 16px; height: 16px; }
.prod-fp-btn.is-secondary {
  background: transparent;
  border-color: var(--border, #444);
  color: var(--text-secondary);
  flex: 1;
}
.prod-fp-btn.is-secondary:hover {
  background: var(--surface-overlay);
  color: var(--text-primary);
}
.prod-fp-btn.is-primary {
  background: var(--accent, #009999);
  border-color: var(--accent, #009999);
  color: var(--text-inverse, #fff);
  flex: 2;
}
.prod-fp-btn.is-primary:hover:not(.is-disabled) {
  filter: brightness(1.15);
}
.prod-fp-btn.is-primary.is-disabled,
.prod-fp-btn.is-primary[disabled] {
  background: var(--surface-overlay);
  border-color: var(--border, #444);
  color: var(--text-muted);
  cursor: not-allowed;
  opacity: 0.7;
}

/* Modo claro */
body.light-mode .prod-fp-card-root {
  background: #ffffff;
  border-color: #e2e8f0;
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.15);
}
body.light-mode .prod-fp-header,
body.light-mode .prod-fp-footer {
  border-color: #e2e8f0;
}
body.light-mode .prod-fp-card,
body.light-mode .prod-fp-bool.is-off,
body.light-mode .prod-fp-status-band.is-undef {
  background: #f8fafc;
  border-color: #e2e8f0;
}
body.light-mode .prod-fp-bool-led { background: #cbd5e1; }
body.light-mode .prod-fp-btn.is-secondary {
  border-color: #cbd5e1;
}
body.light-mode .prod-fp-btn.is-secondary:hover {
  background: #f1f5f9;
}

/* (Eliminado) — La regla previa centraba .hmi-float-window con
   transform: translate(-50%, -50%) y top/left 50%. Se ha quitado
   porque ahora el popup vive anclado top:110/right:460 (ver bloque
   "AMBOS popups posicionados con position: fixed" arriba) y el
   transform residual tiraba de él hacia arriba-izquierda. */

/* Cuando CUALQUIER popup de device está abierto en producción ocultamos
   los hotspots para que (1) no se vean detrás del popup ni distraigan,
   y (2) el operador NO pueda saltar a otro device sin cerrar el popup
   actual — el slot del PLC se multiplexa por IN.ID, así que un cambio
   silencioso a otro device desincronizaría los OUT.* del popup vivo.
   Antes los dejábamos a opacity 0.15 pero el glow rojo de los pulsos
   de fault (box-shadow animado) seguía perfectamente visible y daba
   aspecto de bug; con `display: none` desaparecen del todo. Se
   restauran al cerrar el popup (las clases se quitan en
   device-manager.closePopup y production-page.closeFaceplate). */
body.prod-page.is-manual-faceplate-open .prod-hotspot,
body.prod-page.is-prod-faceplate-open .prod-hotspot {
  display: none;
}

/* Botón "VOLVER" en el header del faceplate de control manual: solo
   tiene sentido cuando se accede desde producción (para volver al popup
   moderno). Fuera de production.html lo ocultamos. */
.faceplate-action-back-to-prod { display: none; }
body.prod-page .faceplate-action-back-to-prod { display: inline-flex; }

/* ========================================== */
/* HOTSPOT/CARD/DOT — VARIANTES POR ESTADO    */
/* ========================================== */
/* Coherente con header-aggregator: fault > warning > ok > undef.
   Estado derivado de Fault.OK + StatWord en producción-page.computeStationStateClass. */

/* Hotspot is-ok (verde) — estación en AUTO sin fallo. */
.prod-hotspot.is-station.is-ok {
  background: var(--color-success);
  box-shadow: 0 0 12px var(--color-success-soft);
}
/* Hotspot is-undef (gris) — estación sin modo asignado / sin datos. */
.prod-hotspot.is-station.is-undef {
  background: var(--text-muted);
  box-shadow: none;
  opacity: 0.7;
}
/* Hotspot is-warning grande de estación: hereda el amarillo definido
   más arriba pero anulamos el pulso de fault si lo había. */
.prod-hotspot.is-station.is-warning { animation: none; }

/* Anillo concéntrico del hotspot de estación: lo coloreamos según el
   estado para reforzar la lectura sin tener que mirar el centro. */
.prod-hotspot.is-station.is-fault::before    { border-color: var(--color-danger); }
.prod-hotspot.is-station.is-warning::before  { border-color: var(--color-warning); }
.prod-hotspot.is-station.is-ok::before       { border-color: var(--color-success); }
.prod-hotspot.is-station.is-undef::before    { border-color: var(--text-muted); animation: none; }

/* Card del listado lateral: borde / fondo según estado. is-active
   (selección visual) tiene precedencia sobre cualquier color de estado. */
.prod-station-card.is-warning {
  border-color: var(--color-warning);
  background: var(--color-warning-soft, rgba(241, 196, 15, 0.08));
}
/* Auto / operativo: verde. Antes is-ok no llevaba clase en la card → las
   estaciones en automático no se resaltaban. Ahora sí, como manual y fault. */
.prod-station-card.is-ok {
  border-color: var(--color-success);
  background: var(--color-success-soft, rgba(34, 197, 94, 0.10));
}
.prod-station-card.is-undef {
  opacity: 0.85;
}

/* Light-mode: los soft-bg traslúcidos sobre superficie clara quedan casi
   invisibles (por eso en claro sólo se veía el manual). Usamos tintes claros
   sólidos para que el resalte se vea en TODOS los estados — auto, manual y
   fault — igual que en modo oscuro. */
body.light-mode .prod-station-card.is-warning {
  border-color: var(--color-warning);
  background: #fef9c3;
}
body.light-mode .prod-station-card.is-ok {
  border-color: var(--color-success);
  background: #dcfce7;
}
body.light-mode .prod-station-card.is-fault {
  border-color: var(--color-danger);
  background: #fee2e2;
}

/* ========================================== */
/* Botón "GESTIONAR RECETAS" — dos estados:    */
/*   is-loaded : pill destacada con modelo+N°  */
/*   is-empty  : texto plano "EN PRODUCCIÓN —  */
/*               GESTIÓN DE RECETAS"            */
/* ========================================== */
.prod-recipes-btn-label {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  text-align: left;
  flex: 1;
}

/* Pill destacada con el modelo en producción (is-loaded). */
.prod-recipes-pill {
  display: none;            /* oculto por defecto, lo activa is-loaded */
  flex-direction: column;
  gap: 2px;
  padding: 6px 12px;
  border-radius: var(--radius-md, 8px);
  background: var(--accent-soft, rgba(95,180,214,0.12));
  border: 1px solid var(--accent, #5fb4d6);
}
.prod-recipes-btn.is-loaded .prod-recipes-pill { display: flex; }
.prod-recipes-pill-eyebrow {
  font-size: 0.65em;
  font-weight: var(--fw-bold, 700);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent, #5fb4d6);
  opacity: 0.85;
}
.prod-recipes-pill-val {
  font-family: var(--font-tech);
  font-size: 1.05em;
  font-weight: var(--fw-bold, 700);
  color: var(--text-primary, #e8edf2);
  line-height: 1.15;
  word-break: break-word;
}

/* Texto plano cuando no hay modelo (is-empty). */
.prod-recipes-empty-text {
  display: none;            /* oculto por defecto, lo activa is-empty */
  font-size: 0.85em;
  letter-spacing: 0.05em;
  color: var(--text-muted, #93a1b1);
  font-style: italic;
}
.prod-recipes-btn.is-empty .prod-recipes-empty-text { display: inline-block; }

/* CTA inferior: visible siempre, color accent, hover invierte. */
.prod-recipes-btn-cta {
  font-size: 0.75em;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent, #5fb4d6);
  font-weight: var(--fw-bold, 700);
}
.prod-recipes-btn.is-empty .prod-recipes-btn-cta { display: none; }   /* el texto plano ya lo dice */

.prod-recipes-btn:hover .prod-recipes-pill {
  background: var(--accent, #5fb4d6);
}
.prod-recipes-btn:hover .prod-recipes-pill-eyebrow,
.prod-recipes-btn:hover .prod-recipes-pill-val,
.prod-recipes-btn:hover .prod-recipes-btn-cta,
.prod-recipes-btn:hover .prod-recipes-empty-text { color: var(--text-inverse, #fff); }

body.light-mode .prod-recipes-pill {
  background: #e0f2fe;
  border-color: var(--accent, #0284c7);
}
body.light-mode .prod-recipes-pill-eyebrow { color: var(--accent, #0284c7); }
body.light-mode .prod-recipes-pill-val     { color: var(--neutral-800, #1e293b); }
body.light-mode .prod-recipes-empty-text   { color: var(--neutral-500, #64748b); }
body.light-mode .prod-recipes-btn-cta      { color: var(--accent, #0284c7); }
