:root {
  /* ==================== Sistema visual corporativo (ronda "CAMBIO VISUAL GLOBAL — PALETA SAP
     CLÁSICO"): tokens canónicos con los valores HEX exactos pedidos. Sustituye la paleta clara/plana
     de la ronda anterior (demasiado blanca) por niveles de azul + gris claro + blanco de trabajo. ==================== */
  --sap-blue: #0B5CAD;          /* Azul SAP principal */
  --sap-blue-dark: #0A3D78;     /* Azul oscuro */
  --sap-blue-nav: #155AA8;      /* Azul navegación */
  --sap-blue-active: #0875D1;   /* Azul seleccionado (módulo activo, elementos destacados) */
  --sap-blue-light: #DCEAF7;    /* Azul claro (hover, tintes suaves) */
  --sap-blue-lighter: #EAF3FA;  /* Azul muy claro (paneles de filtros, fondos discretos) */
  /* Ronda "REDISEÑO VISUAL INTEGRAL — ETAPA 1": estos 3 tokens controlaban casi todo el aspecto SAP
     (franjas celestes de encabezado, fondo azulado, bordes duros azul-grisáceos). Al reemplazarlos
     acá en :root, TODA la app hereda automáticamente el aspecto claro/blanco tipo LubriAnalytics --
     .filtros, .resumen .card, table th, .panel h4, .dash-seccion h2, .modal, etc. -- sin tener que
     tocar esas reglas una por una. Los tokens --sap-blue-* NO cambian (siguen siendo el azul
     corporativo de marca: sidebar, botones primarios, texto de títulos, estados "activo"). */
  --panel-header-bg: #FFFFFF;   /* Encabezado de panel/sección/tabla -- ya no una franja celeste */
  --panel-header-text: #17365D;
  --background: #F6F7F9;        /* Fondo general -- gris/blanco muy claro, no azulado */
  --surface: #FFFFFF;           /* Superficie principal (contenido) */
  --surface-alt: #F7F8FA;       /* Superficie secundaria */
  --table-row-alt: #FAFBFC;     /* Fila par de tabla -- gris casi imperceptible, no celeste */
  --table-hover: #EEF2F6;
  --table-selected: #DCEAF7;
  --border: #E7E9ED;            /* Bordes gris muy finos, no azul-grisáceos */
  --text-primary: #1F2D3D;
  --text-secondary: #52677B;
  --success: #107E3E;      /* NORMAL / CERRADO-RECUPERADO */
  --information: #36A9E1;  /* TOLERABLE */
  --warning: #CA8A04;      /* PRECAUCIÓN (ronda "COLORES DE CONDICIÓN": amarillo, antes naranja) */
  --critical: #BB0000;     /* CRÍTICO */
  --neutral: #6A6D70;      /* NO EJECUTADO */
  --pending: #5B738C;      /* PENDIENTE / placeholder */
  --danger: var(--critical);
  --track-bg: #E3EAF0;

  /* Alias retrocompatibles: TODA la aplicación (app.js/index.html) ya referencia estos nombres
     (--bg/--panel/--panel2/--text/--muted/--accent/--ok/--tolerable/--review/--error/--placeholder)
     cientos de veces. Remapearlos aquí a los tokens canónicos de arriba retiñe toda la aplicación sin
     tener que renombrar una sola referencia -- cero riesgo de romper una clase que el JS espera. */
  --bg: var(--background);
  --panel: var(--surface);
  --panel2: var(--surface-alt);
  --text: var(--text-primary);
  --muted: var(--text-secondary);
  --accent: var(--sap-blue);
  --ok: var(--success);
  --tolerable: var(--information);
  --review: var(--warning);
  --error: var(--critical);
  --placeholder: var(--pending);

  /* Paleta por TÉCNICA DE INSPECCIÓN (Programa Semanal) -- secundaria frente al azul SAP corporativo
     (sección 14 del pedido), deliberadamente distinta de los colores de ESTADO para que técnica y
     estado nunca se confundan. */
  --tec-vibracion: #0B5CAD; --tec-termografia: #C1610B; --tec-aceite: #107E3E;
  --tec-ut: #8B3FE0; --tec-visual: #9A7D0A; --tec-otra: #6A6D70;
}
* { box-sizing: border-box; }
body { margin: 0; font-family: "72", Arial, "Helvetica Neue", sans-serif; background: var(--background); color: var(--text-primary); -webkit-font-smoothing: antialiased; }

/* ==================== Layout general: menú lateral AUTO-OCULTABLE (ronda "MEJORA VISUAL —
   REGISTRO DE CONDICIÓN + MENÚ LATERAL AUTO-OCULTABLE") ====================
   Header + nav comparten la columna izquierda, el contenido ocupa el resto -- puramente
   presentacional (CSS Grid + :has()), cambiarTab() sigue alternando display:none/block sobre los
   mismos IDs de siempre, sin tocar una sola línea de esa función. Tres estados controlados por
   document.body.dataset.sidebar (persistido en localStorage, sección 2 del pedido):
     - "auto" (por defecto): franja azul angosta de descanso; al pasar el mouse por encima del
       header/nav (incluida la franja angosta pegada al borde izquierdo) se expande; al salir, se
       contrae de nuevo. Sección 15: es un comportamiento GLOBAL, no siete implementaciones.
     - "fijado": permanece siempre expandido (210px), ignora el mouse.
     - "contraido": permanece siempre contraído, ignora el hover (el usuario lo pidió explícitamente
       con el botón ☰; nunca se oculta del todo -- sigue siendo una franja clickeable, sección 2:
       "No ocultar permanentemente la navegación").
   Con viewport angosto (<1024px) se revierte a navegación horizontal superior, igual que antes. */
:root { --sidebar-w: 220px; --sidebar-w-colapsado: 14px; }
/* Ronda "REDISEÑO VISUAL INTEGRAL — ETAPA 1": tercera fila para el pie de sidebar (usuario/rol/
   cerrar sesión, antes viviendo arriba del todo en <header>) -- .tab-panel sigue en "1 / -1" así que
   le da igual cuántas filas tenga la columna 1, ocupa el alto completo de cualquier forma. */
body { display: grid; grid-template-columns: var(--sidebar-w-colapsado) 1fr; grid-template-rows: auto 1fr auto; min-height: 100vh; transition: grid-template-columns .22s ease; }
body[data-sidebar="fijado"] { grid-template-columns: var(--sidebar-w) 1fr; }
/* RONDA "CORRECCIÓN FINAL — HOVER DE ESCRITORIO EN CELULAR": esta regla es el auto-expandir-al-pasar-
   el-mouse del sidebar de ESCRITORIO (ver el comentario de arriba, "franja azul angosta... al pasar
   el mouse... se expande"), pero estaba declarada SIN ningún media query. Su especificidad compuesta
   (dos :not() + :has()) le gana en cascada a CUALQUIER regla de body{grid-template-columns} de
   tablet/celular sin importar el orden en el archivo -- así que un solo :hover real sobre header/.tabs
   (un clic de mouse real deja el cursor "descansando" ahí, incluso en un navegador de escritorio
   redimensionado a un ancho angosto) rompía el layout de celular/tablet, dejando tarjetas de
   Registro de Condición/Seguimiento con un ancho angosto anómalo -- defecto real, confirmado con
   medición de anchos, no cosmético. Corrección de causa (no del síntoma): esta franja hover-expand es
   conceptualmente exclusiva de escritorio (tablet usa un rail con clic explícito, celular un drawer,
   ninguno de los dos usa hover) -- se restringe con (min-width:1200px), el propio umbral de escritorio
   de esta app, más (hover:hover) y (pointer:fine) para que además nunca dispare con un toque en una
   pantalla táctil. Fuera de ese media query la regla no puede aplicar a ningún ancho, sin importar el
   estado de :hover. */
@media (min-width: 1200px) and (hover: hover) and (pointer: fine) {
  body:not([data-sidebar="fijado"]):not([data-sidebar="contraido"]):has(header:hover),
  body:not([data-sidebar="fijado"]):not([data-sidebar="contraido"]):has(.tabs:hover) { grid-template-columns: var(--sidebar-w) 1fr; }
}

header {
  grid-column: 1; grid-row: 1; overflow: hidden;
  background: var(--sap-blue-dark);
  padding: 20px 18px 16px;
  display: flex; flex-direction: column; gap: 3px;
}
header h1 { font-size: 15px; margin: 0; font-weight: 700; letter-spacing: .01em; color: #fff; line-height: 1.3; white-space: nowrap; }
.header-subtitulo { margin: 0; font-size: 10.5px; font-weight: 500; color: rgba(255,255,255,.6); white-space: nowrap; }
header .db-path { font-size: 9.5px; color: rgba(255,255,255,.4); background: none; border: none; padding: 6px 0 0; white-space: nowrap; }

/* Aviso de versión desactualizada (pestaña abierta desde antes del último despliegue): sección
   propia fuera del grid header/tabs/tab-panel para que nunca la tape ni la desplace ningún módulo. */
.version-banner {
  position: fixed; top: 0; left: 0; right: 0; z-index: 500;
  background: var(--warning, #b8860b); color: #fff; font-size: 12.5px; font-weight: 600;
  padding: 8px 16px; text-align: center;
}
.version-banner button {
  margin-left: 10px; background: rgba(255,255,255,.2); border: 1px solid rgba(255,255,255,.6); color: #fff;
  font-size: 12px; font-weight: 700; padding: 3px 10px; border-radius: 6px; cursor: pointer;
}
.version-banner button:hover { background: rgba(255,255,255,.35); }

/* Ronda "FASE WEB 1", sección 1: hasta que body lleva la clase .autenticado, SOLO se ve el login --
   se oculta cada hijo directo de body salvo el overlay, sin tocar el grid del layout autenticado
   (header/.tabs/.tab-panel siguen siendo hijos directos de body, nunca envueltos en un div extra). */
body:not(.autenticado) > *:not(#loginOverlay) { display: none; }
body.autenticado #loginOverlay { display: none; }

.login-overlay {
  position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center;
  background: var(--sap-blue-dark); overflow: hidden;
}
/* Fondo fotográfico real (planta industrial) tratado en capas independientes -- cada capa controla
   un efecto (oscurecer, subir cian, viñeta) para poder ajustarlas por separado sin recomprimir la foto. */
.login-fondo {
  position: absolute; inset: 0;
  background-image: url("img/login-fondo.jpg");
  background-size: cover; background-position: center 40%;
  filter: brightness(.82) saturate(.94) contrast(1.05);
}
.login-capa-color {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(6,16,28,.42) 0%, rgba(6,16,28,.5) 50%, rgba(4,10,18,.84) 100%);
  mix-blend-mode: multiply;
}
.login-capa-cian {
  position: absolute; inset: 0;
  background: linear-gradient(160deg, rgba(54,169,225,.16), rgba(10,30,54,0) 46%);
  mix-blend-mode: screen; opacity: .5;
}
.login-capa-vineta {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse 780px 640px at 50% 60%, rgba(4,10,18,.74) 0%, rgba(4,10,18,.42) 45%, rgba(4,10,18,0) 72%);
}
.login-escena { position: absolute; inset: 0; width: 100%; height: 100%; }

.login-caja {
  position: relative; z-index: 5;
  background: var(--surface); border-radius: 4px; padding: 34px 38px 30px; width: 332px; max-width: calc(100vw - 40px);
  box-shadow: 0 24px 64px rgba(0,0,0,.55), 0 2px 0 rgba(54,169,225,.25); display: flex; flex-direction: column; gap: 14px;
}
.login-marca { display: flex; flex-direction: column; align-items: center; gap: 2px; margin-bottom: 2px; }
.login-icono {
  width: 34px; height: 34px; border-radius: 50%; margin-bottom: 6px;
  background: radial-gradient(circle at 35% 30%, var(--information), var(--sap-blue-dark) 72%);
  box-shadow: 0 0 0 3px rgba(54,169,225,.15);
}
.login-caja h1 { font-size: 16.5px; margin: 0; color: var(--sap-blue-dark); text-align: center; letter-spacing: .04em; font-weight: 700; }
.login-subtitulo { margin: 0; font-size: 12px; color: var(--text-secondary); text-align: center; letter-spacing: .01em; }
.login-caja label { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--text-secondary); font-weight: 600; margin-top: 6px; }
.login-caja input {
  background: var(--surface-alt); border: 1px solid var(--border); color: var(--text-primary);
  padding: 9px 10px; border-radius: 6px; font-size: 14px; font-family: inherit;
}
.login-caja input:focus { outline: none; border-color: var(--sap-blue); box-shadow: 0 0 0 2px var(--sap-blue-light); }
.login-caja button.primario { margin-top: 8px; padding: 10px; font-size: 13px; }

/* Ronda "REDISEÑO VISUAL INTEGRAL — ETAPA 1": sidebar agrupada (Operación/Análisis/Gestión/
   Administración) con íconos + pie de usuario/rol/cerrar sesión. Un solo azul oscuro plano para todo
   el panel (antes header y nav tenían dos azules ligeramente distintos) -- más parecido al panel
   lateral sólido de LubriAnalytics que a la barra de navegación SAP. */
.tabs {
  grid-column: 1; grid-row: 2; background: var(--sap-blue-dark);
  display: flex; flex-direction: column; gap: 2px; padding: 10px 8px; overflow-y: auto; overflow-x: hidden;
}
.nav-grupo { display: flex; flex-direction: column; gap: 1px; margin-bottom: 10px; }
.nav-grupo-titulo {
  font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: rgba(255,255,255,.4); padding: 6px 12px 4px; white-space: nowrap;
}
.tab-btn {
  background: none; border: none; color: rgba(255,255,255,.78); padding: 9px 12px; cursor: pointer;
  font-size: 13px; font-weight: 600; text-align: left; border-radius: 6px; border-left: 3px solid transparent;
  transition: background .15s, color .15s; white-space: nowrap; width: 100%; flex: none;
  display: flex; align-items: center; gap: 10px;
}
.tab-btn:hover { background: rgba(255,255,255,.08); color: #fff; }
.tab-btn.active { background: rgba(255,255,255,.14); color: #fff; border-left-color: var(--information); }
/* Íconos: familia única de línea, pequeños y secundarios al texto (nunca más protagónicos que la
   etiqueta) -- heredan color vía currentColor, así el estado hover/activo los tiñe automáticamente. */
.nav-icon { width: 16px; height: 16px; flex: none; stroke: currentColor; stroke-width: 1.6; fill: none; stroke-linecap: round; stroke-linejoin: round; opacity: .85; }
.tab-btn.active .nav-icon { opacity: 1; }

/* Pie de sidebar: usuario/rol + cerrar sesión, ahora en la parte inferior (antes vivían arriba, en
   <header>) -- misma información, mismo id #sesionUsuarioTexto, sin cambio de app.js. */
.sidebar-pie {
  grid-column: 1; grid-row: 3; background: var(--sap-blue-dark); padding: 12px 14px;
  border-top: 1px solid rgba(255,255,255,.1); overflow: hidden;
}
.sidebar-pie-usuario { font-size: 11px; color: rgba(255,255,255,.75); white-space: nowrap; margin-bottom: 6px; }
.sidebar-pie-salir {
  background: none; border: 1px solid rgba(255,255,255,.3); color: rgba(255,255,255,.85);
  font-size: 11px; padding: 5px 10px; border-radius: 5px; cursor: pointer; white-space: nowrap; width: 100%;
}
.sidebar-pie-salir:hover { background: rgba(255,255,255,.12); color: #fff; }

/* Botón ☰ fijar/desfijar -- fuera del header/nav colapsables (nunca se recorta con overflow:hidden),
   siempre clickeable sin importar el estado del sidebar. */
.sidebar-toggle {
  position: fixed; top: 10px; left: 10px; z-index: 30;
  width: 26px; height: 26px; border-radius: 6px; border: 1px solid rgba(255,255,255,.3);
  background: rgba(255,255,255,.12); color: #fff; font-size: 14px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center; transition: background .15s;
}
.sidebar-toggle:hover { background: rgba(255,255,255,.25); }

.tab-panel { grid-column: 2; grid-row: 1 / -1; min-height: 200px; overflow-y: auto; overflow-x: hidden; background: var(--background); }

.resumen { display: flex; gap: 12px; padding: 16px 24px; flex-wrap: wrap; }
/* Ronda "REDISEÑO VISUAL INTEGRAL — ETAPA 1": tarjeta blanca con sombra mínima y esquinas suaves en
   vez de borde duro; la etiqueta ya no lleva una franja celeste interna -- queda como texto simple
   debajo del número, igual criterio que ya se probó en el Dashboard. */
.resumen .card {
  background: var(--surface); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
  min-width: 110px; overflow: hidden; display: flex; flex-direction: column-reverse;
}
.resumen .card .n { padding: 10px 14px 4px; font-size: 22px; font-weight: 700; color: var(--sap-blue-dark); font-variant-numeric: tabular-nums; }
.resumen .card .l { color: var(--text-secondary); font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; font-weight: 600; padding: 2px 14px 10px; margin: 0; background: none; border-bottom: none; }
/* KPI superiores de Cumplimiento (Semanal / Acumulado Mensual / Acumulado Anual): mismo ancho,
   mismo alto, mismo padding -- nunca dependen del largo del texto de cada etiqueta. */
#dbAcumulado.resumen { flex-wrap: nowrap; }
#dbAcumulado .card { flex: 1 1 0; min-width: 0; text-align: center; }
/* Cuadros resumen de Registro de Condición (Programados/Ejecutados/Pendientes/No Ejecutados/Avance %):
   centrados -- SOLO este módulo, ".resumen .card" es un componente compartido con otras pantallas. */
#rcResumen .card { text-align: center; }

/* Ronda "REDISEÑO VISUAL INTEGRAL — ETAPA 1": barra blanca compacta en vez de franja celeste --
   mismo criterio ya probado en el Dashboard, ahora aplicado a TODOS los módulos que comparten esta
   clase (Seguimiento, Reportes, Equipo 360, Programa Semanal, Registro de Condición, Base Maestra,
   Usuarios). Radios más suaves en selects/inputs/botones en vez de esquinas duras. */
.filtros { display: flex; gap: 8px; padding: 10px 14px; flex-wrap: wrap; align-items: center; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; margin: 12px 24px; }
.filtros select, .filtros input { background: var(--surface); border: 1px solid var(--border); color: var(--text-primary); padding: 6px 10px; border-radius: 6px; font-size: 13px; font-family: inherit; height: 32px; }
.filtros select:focus, .filtros input:focus { outline: none; border-color: var(--sap-blue); box-shadow: 0 0 0 2px var(--sap-blue-light); }
.filtros button { background: var(--sap-blue); border: 1px solid var(--sap-blue); color: white; padding: 0 16px; height: 32px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 600; font-family: inherit; transition: background .15s, border-color .15s; }
.filtros button:hover { background: var(--sap-blue-active); border-color: var(--sap-blue-active); }
.filtros button.secundario { background: var(--surface); border-color: var(--border); color: var(--text-primary); }
.filtros button.secundario:hover { background: var(--sap-blue-light); border-color: var(--sap-blue); color: var(--sap-blue-dark); }

main { padding: 4px 24px 40px; }
table { width: 100%; border-collapse: collapse; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; box-shadow: 0 1px 3px rgba(16,24,40,.04); }
th, td { padding: 8px 12px; text-align: left; border-bottom: 1px solid var(--border); font-size: 13px; color: var(--text-primary); font-variant-numeric: tabular-nums; }
th { background: var(--panel-header-bg); color: var(--text-secondary); font-weight: 700; text-transform: uppercase; font-size: 11px; letter-spacing: .03em; border-bottom: 1px solid var(--border); }
tbody tr:nth-child(even) td { background: var(--table-row-alt); }
tbody tr:hover td { background: var(--table-hover); cursor: pointer; }
tbody tr.selected td { background: var(--table-selected); }
td:first-child { font-weight: 600; }

.badge { display: inline-block; padding: 2px 9px; border-radius: 10px; font-size: 11px; font-weight: 700; letter-spacing: .01em; }
.badge.ok { background: color-mix(in srgb, var(--success) 15%, white); color: var(--success); }
.badge.tolerable { background: color-mix(in srgb, var(--information) 18%, white); color: color-mix(in srgb, var(--information) 75%, black); }
.badge.review { background: color-mix(in srgb, var(--warning) 15%, white); color: var(--warning); }
.badge.error { background: color-mix(in srgb, var(--critical) 12%, white); color: var(--critical); }
.badge.sin-programar { background: color-mix(in srgb, var(--neutral) 14%, white); color: var(--neutral); }
.badge.programada { background: color-mix(in srgb, var(--sap-blue) 12%, white); color: var(--sap-blue); }
.badge.placeholder { background: color-mix(in srgb, var(--pending) 14%, white); color: var(--pending); }
.badge.pendiente-suave { background: color-mix(in srgb, var(--pending) 12%, white); color: var(--pending); }
.badge.completado { background: color-mix(in srgb, var(--success) 15%, white); color: var(--success); }

/* Botón "Editar" de un registro ya ejecutado/no ejecutado (ronda "EDITAR INSPECCIÓN — SOLO
   ADMINISTRADOR", Registro de Condición) -- discreto, solo visible para ADMINISTRADOR. */
.btn-editar-inspeccion {
  border: 1px solid var(--border); background: var(--surface); color: var(--sap-blue);
  border-radius: 6px; width: 20px; height: 20px; line-height: 1; font-size: 11px; cursor: pointer;
  padding: 0; margin-left: 4px; vertical-align: middle;
}
.btn-editar-inspeccion:hover { background: var(--sap-blue-lighter); border-color: var(--sap-blue); }

/* Ronda "REDISEÑO VISUAL INTEGRAL — ETAPA 1": modal con encabezado limpio en vez de banner azul
   sólido -- título en azul oscuro sobre blanco, línea fina debajo, botón X consistente en cualquier
   estado (ya no necesita un color especial para "flotar" sobre un fondo oscuro). Esquinas más suaves. */
.modal-bg { position: fixed; inset: 0; background: rgba(15,23,42,.4); display: none; align-items: flex-start; justify-content: center; padding: 40px 20px; overflow-y: auto; z-index: 10; }
.modal-bg.open { display: flex; }
.modal { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; max-width: 900px; width: 100%; padding: 16px 0 20px; box-shadow: 0 16px 40px rgba(16,24,40,.18); }
/* ">" a propósito -- solo el título real del modal (hijo directo) lleva el encabezado propio; un
   <h2>/<h3> que aparezca DENTRO del contenido (p.ej. el encabezado del Reporte Técnico, sección 18)
   nunca debe heredarlo, solo un tratamiento tipo documento (ver más abajo).
   El redondeo de las esquinas superiores vive en el propio h2 (no en overflow:hidden del .modal):
   un combobox con lista desplegable (Modo de Falla) necesita poder salirse del cuadro del modal. */
.modal > h2 {
  margin: -16px 0 16px; color: var(--sap-blue-dark); font-size: 15px; font-weight: 700;
  background: var(--panel-header-bg); border-bottom: 1px solid var(--border);
  padding: 14px 24px; text-transform: uppercase; letter-spacing: .02em; border-radius: 10px 10px 0 0;
}
.modal .encabezado { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 0 24px 16px; font-size: 13px; background: var(--background); border: 1px solid var(--border); border-radius: 8px; padding: 12px; }
.modal .encabezado div span { display: block; color: var(--text-secondary); font-size: 11px; text-transform: uppercase; letter-spacing: .02em; opacity: .85; }
.modal .cerrar { float: right; background: none; border: none; color: var(--text-secondary); font-size: 20px; cursor: pointer; line-height: 1; padding: 4px; margin: 0 10px 0 0; }
.modal .cerrar:hover { color: var(--critical); }
.modal:has(> h2) .cerrar { margin-top: -10px; }
.modal > *:not(.cerrar):not(h2) { margin-left: 24px; margin-right: 24px; }
/* Encabezados de sección DENTRO de un documento (Reporte Técnico, sección 18 del pedido): azul
   corporativo como color de texto/borde, nunca una banda llena -- el cuerpo del reporte se mantiene
   blanco. */
.modal h3 { font-size: 13px; text-transform: uppercase; letter-spacing: .02em; color: var(--sap-blue-dark); border-bottom: 2px solid var(--panel-header-bg); padding-bottom: 6px; margin: 20px 0 8px; }
#reporteTecnicoContenido h2 { color: var(--sap-blue-dark); font-size: 18px; }

.arbol .equipo { border: 1px solid var(--border); border-radius: 6px; margin-bottom: 8px; overflow: hidden; }
.arbol .equipo-titulo { font-weight: 700; padding: 8px 10px; color: var(--panel-header-text); background: var(--panel-header-bg); border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.arbol .componente { margin-left: 16px; padding: 6px 10px 6px 0; border-top: 1px dashed var(--border); }
.arbol .componente-titulo { font-size: 13px; color: var(--sap-blue-dark); font-weight: 700; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.arbol .actividad { margin-left: 16px; font-size: 12px; padding: 3px 0; display: flex; gap: 8px; align-items: center; color: var(--text-primary); }
/* Ronda "EDICIÓN MANUAL BASE MAESTRA": botones pequeños de Editar/Desactivar dentro del árbol
   Equipo → Componente → Actividad -- misma familia de botón secundario que el resto de la app, solo
   más chico para caber en una fila de árbol. En Equipo/Componente quedan a la derecha por el
   space-between del contenedor; en Actividad (ya era flex con gap) se empujan al final con
   margin-left:auto. */
.arbol-acciones { display: flex; gap: 4px; flex: none; }
.arbol .actividad .arbol-acciones { margin-left: auto; }
.arbol-acciones button { padding: 2px 8px; font-size: 11px; border-radius: 4px; cursor: pointer; font-family: inherit; font-weight: 600; transition: background .15s, border-color .15s, color .15s; }
.arbol-acciones button.secundario { background: var(--surface); border: 1px solid var(--border); color: var(--text-primary); }
.arbol-acciones button.secundario:hover { background: var(--sap-blue-light); border-color: var(--sap-blue); color: var(--sap-blue-dark); }
/* Botón "Eliminar" (ronda "ELIMINACIÓN REAL DE EQUIPO SIN HISTORIAL"): mismo rojo que .peligro en
   .form-actions -- se distingue a propósito de Editar/Desactivar porque es la única acción
   irreversible de las tres. */
.arbol-acciones button.peligro { background: var(--critical); border: 1px solid var(--critical); color: white; }
.arbol-acciones button.peligro:hover { background: #950000; border-color: #950000; }

form.form-inline { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }
form.form-inline label { font-size: 12px; color: var(--text-secondary); display: block; margin-bottom: 4px; font-weight: 600; }
form.form-inline input, form.form-inline select, form.form-inline textarea { width: 100%; background: var(--surface); border: 1px solid var(--border); color: var(--text-primary); padding: 7px 9px; border-radius: 6px; font-family: inherit; font-size: 13px; }
form.form-inline input:focus, form.form-inline select:focus, form.form-inline textarea:focus { outline: none; border-color: var(--sap-blue); box-shadow: 0 0 0 2px var(--sap-blue-light); }
form.form-inline .full { grid-column: 1 / -1; }

/* Combobox de búsqueda "Modo de Falla" (catálogo real de 128 valores, ver /api/modos-falla):
   el input de texto es puramente de filtro/presentación -- el Codigo real vive en el
   <input type="hidden"> que sigue siendo #inspModoFalla, sin cambiar la lógica de guardado. */
.combo-modofalla { position: relative; }
.combo-lista {
  display: none; position: absolute; z-index: 20; top: calc(100% + 2px); left: 0; right: 0;
  max-height: 240px; overflow-y: auto; background: var(--surface); border: 1px solid var(--border);
  border-radius: 6px; box-shadow: 0 4px 12px rgba(10, 61, 120, .18);
}
.combo-item { padding: 7px 10px; font-size: 13px; color: var(--text-primary); cursor: pointer; }
.combo-item:hover { background: var(--sap-blue-light); }
.combo-vacio { padding: 7px 10px; font-size: 13px; color: var(--text-secondary); font-style: italic; }
.form-actions { margin-top: 16px; display: flex; gap: 10px; }
.form-actions button { padding: 0 18px; height: 34px; border-radius: 6px; border: 1px solid transparent; cursor: pointer; font-size: 13px; font-weight: 600; font-family: inherit; transition: background .15s, border-color .15s; }
.form-actions .primario { background: var(--sap-blue); border-color: var(--sap-blue); color: white; }
.form-actions .primario:hover { background: var(--sap-blue-active); border-color: var(--sap-blue-active); }
.form-actions .secundario { background: var(--surface); border-color: var(--border); color: var(--text-primary); }
.form-actions .secundario:hover { background: var(--sap-blue-light); border-color: var(--sap-blue); color: var(--sap-blue-dark); }
.form-actions .peligro { background: var(--critical); border-color: var(--critical); color: white; }
.form-actions .peligro:hover { background: #950000; border-color: #950000; }
.error-msg { color: var(--critical); font-size: 13px; margin-top: 8px; font-weight: 600; }
/* Lista de candidatos de "Registrar No Programado" (búsqueda por TAG parcial/Descripción). */
.np-resultados { max-height: 220px; overflow-y: auto; border: 1px solid var(--border); border-radius: 6px; }
.np-resultado-item { padding: 7px 10px; cursor: pointer; border-bottom: 1px solid var(--border); font-size: 13px; }
.np-resultado-item:last-child { border-bottom: none; }
.np-resultado-item:hover { background: var(--sap-blue-lighter); }
.preview-fechas { margin-top: 10px; font-size: 13px; }
.preview-fechas ol { margin: 6px 0 0 20px; padding: 0; }
.aviso { background: color-mix(in srgb, var(--warning) 10%, white); border: 1px solid var(--warning); color: color-mix(in srgb, var(--warning) 80%, black); padding: 8px 12px; border-radius: 6px; font-size: 12px; margin-top: 10px; }

/* Últimas 4 condiciones (círculos, Registro de Condición) -- colores semánticos sin cambios (sección 19) */
.historial-circulos { display: flex; align-items: center; gap: 14px; padding: 10px 12px; background: var(--surface-alt); border: 1px solid var(--border); border-radius: 6px; }
.historial-circulos .hc-item { display: flex; flex-direction: column; align-items: center; gap: 4px; cursor: pointer; }
.historial-circulos .hc-dot { width: 22px; height: 22px; border-radius: 50%; border: 2px solid transparent; }
.historial-circulos .hc-dot.normal { background: var(--success); }
.historial-circulos .hc-dot.tolerable { background: var(--information); }
.historial-circulos .hc-dot.precaucion { background: var(--warning); }
.historial-circulos .hc-dot.critico { background: var(--critical); }
.historial-circulos .hc-dot.vacio { background: var(--surface); border-color: var(--border); }
.historial-circulos .hc-item.hc-ultima .hc-dot { border-color: var(--sap-blue); box-shadow: 0 0 0 3px var(--sap-blue-light); }
.historial-circulos .hc-fecha { font-size: 10px; color: var(--text-secondary); }
.historial-circulos .hc-arrow { color: var(--text-secondary); font-size: 16px; }
.historial-circulos .hc-link { margin-left: auto; font-size: 12px; color: var(--sap-blue); background: none; border: none; cursor: pointer; font-weight: 600; }
.historial-circulos .hc-link:hover { color: var(--sap-blue-dark); text-decoration: underline; }
.historial-detalle { margin-top: 8px; padding: 10px 12px; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; font-size: 12px; }
.historial-detalle div { margin-bottom: 3px; }

.toast {
  position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%) translateY(20px);
  background: var(--sap-blue-dark); border: 1px solid var(--sap-blue-dark); color: #fff;
  padding: 12px 20px; border-radius: 6px; font-size: 14px; box-shadow: 0 8px 24px rgba(10,45,90,.3);
  opacity: 0; pointer-events: none; transition: opacity .25s, transform .25s; z-index: 100; max-width: 90vw;
}
.toast.visible { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ==================== Navegación de semana (Dashboard) ==================== */
.db-nav-flecha { background: var(--surface); border: 1px solid var(--border); color: var(--sap-blue-dark); font-size: 16px; width: 34px; height: 34px; border-radius: 6px; cursor: pointer; transition: background .15s, border-color .15s; }
.db-nav-flecha:hover { border-color: var(--sap-blue); color: var(--sap-blue); background: var(--sap-blue-light); }

/* Gráfico de barras verticales (CSS puro, sin librerías) */
.grafico-barras-v { display: flex; align-items: flex-end; gap: 8px; height: 140px; padding: 6px 4px 0; overflow-x: auto; }
.grafico-barras-v .gv-col { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; flex: 1 0 28px; height: 100%; min-width: 28px; }
.grafico-barras-v .gv-valor { font-size: 10px; color: var(--text-primary); margin-bottom: 3px; white-space: nowrap; font-weight: 600; }
.grafico-barras-v .gv-barras { display: flex; align-items: flex-end; gap: 2px; width: 100%; justify-content: center; height: 92px; background-image: linear-gradient(var(--border) 1px, transparent 1px); background-size: 100% 25%; background-position: bottom; }
.grafico-barras-v .gv-bar { width: 9px; border-radius: 1px 1px 0 0; background: var(--sap-blue); min-height: 2px; }
.grafico-barras-v .gv-bar.serie-ejecutados { background: var(--success); }
.grafico-barras-v .gv-bar.serie-precaucion { background: var(--warning); }
.grafico-barras-v .gv-bar.serie-critico { background: var(--critical); }
.grafico-barras-v .gv-label { font-size: 10px; color: var(--text-secondary); margin-top: 5px; white-space: nowrap; }
.gv-leyenda { display: flex; gap: 14px; font-size: 11px; color: var(--text-secondary); padding: 2px 0 0; font-weight: 600; }
.gv-leyenda span::before { content: '●'; margin-right: 5px; }

/* Tarjetas de gráfico del Dashboard: ambas comparten exactamente ancho/alto/padding/línea base --
   grilla 50/50, altura fija, encabezado azul-claro tipo panel SAP, cuerpo blanco. */
.dashboard-chart-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; align-items: stretch; }
.dashboard-chart-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: 6px; padding: 0;
  height: 320px; min-height: 320px; max-height: 320px;
  display: flex; flex-direction: column; overflow: hidden;
}
.dashboard-chart-card-header { flex: 0 0 auto; background: var(--panel-header-bg); border-bottom: 1px solid var(--border); padding: 8px 14px; }
.dashboard-chart-card-header h4 { margin: 0 0 4px; font-size: 12px; color: var(--panel-header-text); text-transform: uppercase; letter-spacing: .03em; font-weight: 700; }
.dashboard-chart-body { flex: 1; min-height: 0; height: auto; padding: 8px 14px 4px; }
.dashboard-chart-body .gv-col { height: 100%; }
.dashboard-chart-body .gv-barras { height: calc(100% - 32px); }
@media (max-width: 860px) {
  .dashboard-chart-grid { grid-template-columns: 1fr; }
  .dashboard-chart-card { height: 300px; min-height: 300px; max-height: 300px; }
}

/* ==================== REDISEÑO VISUAL — DASHBOARD PRINCIPAL: cabecera ejecutiva compacta, barra de
   filtros siempre visible, KPIs bajos, tarjetas de condición y grilla de dos columnas en la fila 3.
   Todo queda scoped bajo #tabDashboard (o bajo clases db-* exclusivas del Dashboard) -- .resumen/.card
   y .dash-seccion siguen siendo EXACTAMENTE los mismos que usan Seguimiento, Reportes, Equipos 360,
   Programa Semanal y Registro de Condición; ningún endpoint ni fórmula cambia, solo el envoltorio
   visual de los mismos datos que ya traía cargarDashboard(). ==================== */
/* Ronda "AJUSTE EJECUTIVO — COLORES + DISTRIBUCIÓN + ORDEN": paleta propia del Dashboard, en
   variables NUEVAS (--db-*), nunca redefiniendo --sap-blue-dark/--success/--information/--warning/
   --critical de :root -- esas las usan Base Maestra, Registro de Condición, Equipo 360, Seguimiento
   y Generador de Reportes; cambiarlas de raíz repintaría todos esos módulos. Todo lo que use esta
   paleta nueva vive dentro de selectores #tabDashboard/.db-*, jamás en :root ni en clases globales. */
#tabDashboard {
  --db-navy: #163A5F;
  --db-blue-2: #2F6690;
  --db-blue-3: #5FA8D3;
  /* Ronda "AJUSTE VISUAL — CONTRASTE DE FONDO" (histórico: #F4F6F8 -> #EEF2F6 -> #E9EFF5 -> #DDE6EF,
     ajustado un poco más oscuro en cada ronda hasta lograr contraste claro contra las tarjetas
     #FFFFFF sin llegar a un azul fuerte ni a un Dashboard oscuro). Sigue siendo una única variable,
     escopada a #tabDashboard -- no afecta a ningún otro módulo (Base Maestra/Registro de Condición/
     etc. no leen --db-bg). */
  --db-bg: #D3DEE9;
  /* Ronda "PALETA OFICIAL DE CONDICIÓN": única fuente de verdad para Normal/Tolerable/Precaución/
     Crítico en todo el Dashboard -- ya eran variables centralizadas antes de esta ronda (badges,
     Condición de Activos, Alertas, Top Críticos, Riesgo Operacional, Tendencia de Condición,
     Precaución/Crítico por semana, y el donut vía app.js ya las leían con var(--db-*), nunca un
     color fijo) -- solo se actualiza el VALOR de las 4, sin crear una segunda estructura. */
  --db-normal: #00B050;
  --db-tolerable: #0000FF;
  --db-precaucion: #FFFF00;
  --db-critico: #FF0000;
  --db-no-ejecutado: #6B7280;
  /* Ronda "CONSISTENCIA SEMÁNTICA": "Ejecutados" (serie de cumplimiento en el gráfico "Programados
     vs Ejecutados") NO es una condición de equipo -- reutilizaba --db-normal solo porque compartía
     el mismo verde antes de esta ronda. Con --db-normal ahora reservada exclusivamente para el
     estado NORMAL (#00B050), "Ejecutados" pasa a su propia variable independiente, con el verde que
     tenía la paleta anterior. */
  --db-ejecutados: #2E7D32;
  background: var(--db-bg);
}

/* Cabecera: fondo claro (no franja azul completa), título en azul oscuro, semana/fecha integrados
   como subtítulo de una sola línea. */
.db-header {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px;
  padding: 14px 18px; background: var(--surface); border-bottom: 1px solid var(--border);
}
/* Ronda "TIPOGRAFÍA Y LEGIBILIDAD — 1664x896": todo se percibía demasiado pequeño a 100% de zoom --
   aumento moderado de tamaños de texto/números y del padding INTERNO de cabecera/filtros/tarjetas en
   todo el Dashboard, sin tocar ninguna otra pestaña (todo sigue escopado a #tabDashboard/.db-*). */
.db-header-titulos h1 { margin: 0; font-size: 19px; font-weight: 700; letter-spacing: -.005em; color: var(--db-navy); }
.db-header-titulos p { margin: 4px 0 0; font-size: 12.5px; font-weight: 500; letter-spacing: .01em; color: var(--text-secondary); }
.db-header-titulos p #dbSemanaTexto { font-weight: 700; color: var(--db-navy); }
.db-header-derecha { display: flex; align-items: center; gap: 8px; }
.db-header-derecha .db-nav-flecha { width: 29px; height: 29px; font-size: 13px; background: var(--surface); border: 1px solid var(--border); color: var(--db-navy); }
.db-header-derecha .db-nav-flecha:hover { background: var(--db-bg); border-color: var(--db-blue-2); }
#tabDashboard #btnActualizarDashboard, #tabDashboard #btnExportarPdf { background: var(--surface); border: 1px solid var(--border); color: var(--db-navy); font-size: 13px; }
#tabDashboard #btnActualizarDashboard:hover, #tabDashboard #btnExportarPdf:hover { background: var(--db-bg); border-color: var(--db-blue-2); }

/* Filtros: barra blanca compacta, ya no una franja de color -- deja de leerse como barra de sistema. */
.db-filtros {
  display: flex; align-items: center; gap: 7px; flex-wrap: nowrap; overflow-x: auto;
  padding: 10px 18px; background: var(--surface); border-bottom: 1px solid var(--border);
}
.db-filtros select, .db-filtros input[type="text"], .db-filtros input[type="number"] {
  height: 30px; font-size: 12.5px; padding: 0 9px; border: 1px solid var(--border); border-radius: 5px;
  background: var(--surface); color: var(--text-primary); font-family: inherit;
}
.db-filtros select { width: 142px; flex: none; }
.db-filtros input[type="text"] { width: 104px; }
.db-filtros label { font-size: 11.5px; color: var(--text-secondary); display: flex; align-items: center; gap: 4px; white-space: nowrap; flex: none; }
.db-filtros label input { width: 44px; }
.db-filtros label:first-of-type input { width: 62px; }
/* Ronda "CORREGIR FILTRO SEMANA": #dbSemana es el segundo <label> de la barra, así que la regla de
   arriba (:first-of-type, pensada para Año) nunca lo alcanza -- se quedaba en el ancho genérico de
   44px, insuficiente para 2 dígitos + las flechas nativas del input[type=number] (el valor se
   recortaba, ej. "35" se veía como "3"). Ancho mínimo suficiente para el máximo real (semana 52) sin
   agrandarlo de más -- no toca la regla genérica de 44px, que sigue sirviendo a cualquier otro campo
   numérico futuro de esta barra. */
.db-filtros label #dbSemana { width: 54px; }
.db-filtros button { height: 30px; padding: 0 15px; font-size: 12.5px; flex: none; border-radius: 5px; }

/* Fila 1 -- KPIs: reutiliza .resumen/.card tal cual (mismos datos, mismo <div id="dbKpis">), pero
   más bajas SOLO dentro del Dashboard -- .resumen/.card en Seguimiento/Reportes/Equipos 360/Programa
   Semanal/Registro de Condición quedan intactos (selector con ancestro #tabDashboard). */
#tabDashboard > .resumen#dbKpis { padding: 14px 18px 0; gap: 12px; }
#tabDashboard > .resumen#dbKpis .card { flex: 1 1 160px; min-width: 150px; }
/* Ronda "AJUSTE EJECUTIVO": Cumplimiento con más jerarquía que las demás (punto 2 -- "mayor
   jerarquía visual"), sin volverla un bloque de color completo -- solo número más grande. */
#tabDashboard > .resumen#dbKpis .card:nth-child(3) .n { font-size: 36px; color: var(--db-navy); }

/* Tarjetas blancas, radio suave, sombra mínima (ronda "ELIMINAR ASPECTO SAP") -- sin ícono (la app no
   usa íconos en ningún otro módulo); el indicador de estado es la línea superior de color. */
#tabDashboard .card { border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05); border-top: 4px solid var(--border); }
#tabDashboard .card.db-kpi-info { border-top-color: var(--db-blue-2); }
#tabDashboard .card.db-kpi-precaucion { border-top-color: var(--db-precaucion); }
#tabDashboard .card.db-kpi-critico { border-top-color: var(--db-critico); }

/* Todas las tarjetas .card del Dashboard (KPIs, Acumulado, Precaución/Crítico) centradas -- pedido
   explícito del usuario tras ver la captura ("centrar las letras"). Scoped a #tabDashboard: no toca
   .card en Seguimiento/Reportes/Equipos 360/Programa Semanal/Registro de Condición.
   Jerarquía tipográfica ejecutiva: el número es lo primero que debe leerse -- grande, con peso, color
   de marca; la etiqueta queda secundaria. Ronda "TIPOGRAFÍA Y LEGIBILIDAD": números más grandes
   (26px->30px) y más padding interno (más "protagonismo", pedido explícito) sin agrandar el ancho
   mínimo de la tarjeta más de lo necesario. */
#tabDashboard .card .n, #tabDashboard .card .l { text-align: center; }
#tabDashboard .card .n {
  font-size: 30px; font-weight: 800; letter-spacing: -.01em; line-height: 1; color: var(--db-navy);
  padding: 13px 14px 6px;
}
#tabDashboard .card .l {
  font-size: 11px; font-weight: 600; letter-spacing: .05em; color: var(--text-secondary); background: none; border-bottom: none;
  padding: 4px 12px 10px;
}

/* Fila 2 -- Condición de Activos: 4 tarjetas nuevas (mismos datos de condiciones-semana que ya
   alimentaban el panel de barras "Condición de equipos por semana", solo un renderer distinto --
   ver renderCondicionCards() en app.js, llamado con el array que cargarDashboard() ya trae).
   Se mantienen bajas a propósito (punto 3: "no hacer tarjetas altas") -- el número crece un poco
   para leerse de inmediato, pero el padding vertical de la tarjeta no aumenta. */
.db-condiciones-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 9px; padding: 10px 18px 0; }
/* Ronda "TIPOGRAFÍA Y LEGIBILIDAD": Condición de Activos gana protagonismo (número 26px->29px, más
   padding interno) -- pedido explícito ("permitir identificar rápidamente Normal/Tolerable/
   Precaución/Crítico"). */
.db-cond-card {
  background: var(--surface); border: 1px solid var(--border); border-left: 4px solid var(--border);
  border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05); padding: 11px 13px;
  display: flex; align-items: center; justify-content: space-between;
}
.db-cond-info { display: flex; flex-direction: column; text-align: center; flex: 1; }
.db-cond-n { font-size: 29px; font-weight: 800; letter-spacing: -.01em; font-variant-numeric: tabular-nums; line-height: 1.05; color: var(--text-primary); }
.db-cond-l { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--text-secondary); margin-top: 3px; }
.db-cond-pct { font-size: 14px; font-weight: 700; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.db-cond-normal { border-left-color: var(--db-normal); }
.db-cond-normal .db-cond-n { color: var(--db-normal); }
.db-cond-tolerable { border-left-color: var(--db-tolerable); }
.db-cond-tolerable .db-cond-n { color: var(--db-tolerable); }
.db-cond-precaucion { border-left-color: var(--db-precaucion); }
/* Ronda "PALETA OFICIAL DE CONDICIÓN": excepción deliberada -- el amarillo puro (#FFFF00) como
   color de TEXTO sobre la tarjeta blanca es ilegible (a diferencia del borde/acento, que sí
   funciona bien en amarillo puro). Regla de legibilidad del pedido ("PRECAUCIÓN: texto negro") --
   el número usa texto oscuro en vez del amarillo, el acento/borde sigue siendo el amarillo oficial. */
.db-cond-precaucion .db-cond-n { color: var(--text-primary); }
.db-cond-critico { border-left-color: var(--db-critico); }
.db-cond-critico .db-cond-n { color: var(--db-critico); }

/* ==================== Ronda "REDISEÑO DEL DASHBOARD PRINCIPAL — LubriAnalytics": fila 2 (4 paneles
   ejecutivos) y fila 3 (Condición de Activos | Alertas | No Monitoreados). Densidad tipo
   LubriAnalytics -- tarjetas bajas, márgenes chicos, scroll interno donde corresponde, nunca
   comprimiendo tipografía. 1920px = layout completo (4 y 3 columnas); 1366px reorganiza (nunca
   aprieta) -- ver breakpoints abajo. ==================== */
/* Ronda "TIPOGRAFÍA Y LEGIBILIDAD": gap entre tarjetas 12px->10px, padding interno 10/12/12->12/14/14
   -- mismo criterio que .db-fila-situacion (menos espacio ENTRE, más espacio DENTRO). */
.db-fila-paneles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin: 14px 18px 0; align-items: start; }
.db-panel-ejecutivo { margin: 0; }
.db-panel-ejecutivo h2 { justify-content: flex-start; }
.db-panel-ejecutivo > *:not(h2) { margin: 12px 14px 14px; }
/* Ronda "CORRECCIÓN DEFINITIVA — DISEÑO COMPACTO TIPO LUBRIANALYTICS": 4 columnas se conservan hasta
   1366px (una sola fila en las pantallas ejecutivas típicas), igual criterio que .db-fila-situacion. */
@media (max-width: 1300px) {
  .db-fila-paneles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Panel 1 -- Resumen Ejecutivo: lista compacta etiqueta/valor. Ronda "TIPOGRAFÍA Y LEGIBILIDAD",
   punto 4: repite datos que ya están en los KPIs superiores -- se reduce ligeramente su peso visual
   (fuente algo menor, filas más ajustadas) en vez de agrandarlo como al resto de paneles, para que no
   compita visualmente con la información que sí es nueva en esta fila. Los datos NO se alteran. */
.db-resumen-ejecutivo { display: flex; flex-direction: column; gap: 1px; }
.db-re-fila { display: flex; justify-content: space-between; align-items: baseline; padding: 3.5px 2px; border-bottom: 1px solid var(--border); font-size: 11.5px; }
.db-re-fila:last-child { border-bottom: none; }
.db-re-l { color: var(--text-secondary); }
.db-re-v { font-weight: 700; color: var(--sap-blue-dark); font-variant-numeric: tabular-nums; }

/* Panel 2 -- Cumplimiento por Ruta: TODAS las rutas, scroll interno (nunca hace crecer el Dashboard). */
.db-panel-scroll { max-height: 220px; overflow-y: auto; }

/* Panel 3 -- Distribución por Condición: donut CSS puro + leyenda. Nunca "salud"/health index.
   Ronda "TIPOGRAFÍA Y LEGIBILIDAD": donut más grande (108px->136px) y leyenda más legible -- pedido
   explícito ("el gráfico debe ser más grande y sus leyendas más fáciles de leer"). */
.db-donut-wrap { display: flex; align-items: center; gap: 16px; }
.db-donut { width: 136px; height: 136px; border-radius: 50%; flex: none; position: relative; }
.db-donut-centro { position: absolute; inset: 23px; background: var(--surface); border-radius: 50%; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.db-donut-total { font-size: 24px; font-weight: 800; color: var(--text-primary); line-height: 1; font-variant-numeric: tabular-nums; }
.db-donut-total-l { font-size: 9px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: .04em; margin-top: 2px; }
.db-donut-leyenda { display: flex; flex-direction: column; gap: 8px; font-size: 13px; }
.db-donut-item { display: flex; align-items: center; gap: 7px; color: var(--text-secondary); }
.db-donut-item i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; flex: none; }
.db-donut-item b { color: var(--text-primary); margin-left: auto; padding-left: 10px; }

/* Panel 4 -- Riesgo Operacional (ronda "ETAPA 2 — REDISEÑO DASHBOARD"): reemplaza a "Exposición
   Operacional" (eliminado por redundante -- sus 4 conteos ya viven en Resumen Ejecutivo/No
   Monitoreados/Alertas). Misma tabla que antes vivía en Tendencias ("Riesgo por Área"), mismo
   endpoint/dato (dashboard/riesgo-por-area), solo se reubica arriba dentro de un panel compacto con
   scroll interno -- igual criterio que el panel 2 (Cumplimiento por Ruta). Ronda "TIPOGRAFÍA Y
   LEGIBILIDAD": texto/padding levemente mayores para facilitar lectura. */
.tabla-riesgo-operacional { width: 100%; border-collapse: collapse; background: none; border: none; border-radius: 0; box-shadow: none; }
.tabla-riesgo-operacional th, .tabla-riesgo-operacional td { padding: 6px 4px; font-size: 12.5px; border-bottom: 1px solid var(--border); background: none; }
.tabla-riesgo-operacional th { text-transform: none; font-size: 11px; }
.tabla-riesgo-operacional th:not(:first-child), .tabla-riesgo-operacional td:not(:first-child) { text-align: center; }
.tabla-riesgo-operacional tbody tr:last-child td { border-bottom: none; }

/* Ronda "AJUSTE EJECUTIVO — COLORES + DISTRIBUCIÓN + ORDEN": rótulo de agrupación visual (Situación
   Operacional / Desempeño del Programa) -- una etiqueta liviana, NUNCA otra tarjeta con borde/sombra
   (pedido explícito: "no demasiados bordes"), para que varios paneles existentes "se sientan parte
   de una misma sección" sin fusionar su contenido ni crear un panel contenedor nuevo. */
.db-grupo-titulo {
  margin: 16px 18px 6px; font-size: 11.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; color: var(--db-blue-2);
}
#tabDashboard > .db-grupo-titulo:first-of-type { margin-top: 12px; }

/* Situación Operacional: 5 paneles (Resumen Ejecutivo, Distribución por Condición, Riesgo
   Operacional, No Monitoreados, Condición de Activos). 5 columnas en desktop ancho, se reorganiza
   sin comprimir en pantallas menores -- mismo criterio de "align-items:start" que el resto de filas
   de paneles (cada tarjeta solo tan alta como su contenido, nunca estiradas parejo). Ronda
   "TIPOGRAFÍA Y LEGIBILIDAD": gap entre tarjetas reducido levemente (10px->8px, "espacios muertos
   ENTRE tarjetas") -- compensa el mayor padding interno de cada tarjeta. */
.db-fila-situacion { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px; margin: 0 18px; align-items: start; }
.db-fila-situacion .dash-seccion { margin: 0; }
/* 5 columnas se conservan hasta 1366px (una sola fila en las pantallas ejecutivas típicas -- punto
   6 "menos longitud vertical"); solo baja a 3/2/1 en pantallas realmente angostas. */
@media (max-width: 1300px) {
  .db-fila-situacion { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 1024px) {
  .db-fila-situacion { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 767px) {
  .db-fila-situacion { grid-template-columns: 1fr; }
}

/* Condición de Activos: en columna angosta, 2x2 en vez de 4 en línea (igual de legible). */
.db-condiciones-grid-vertical { grid-template-columns: repeat(2, 1fr); padding: 10px 12px 12px; gap: 8px; }

/* Alertas: la ronda "REDISEÑO VISUAL INTEGRAL" pidió eliminar la duplicación -- "Equipos en
   Precaución"/"Equipos Críticos" ya se ven en la fila principal de KPIs, así que estas 2 tarjetas
   quedan ocultas AQUÍ (el panel Alertas pasa a ser únicamente la mini-lista). El id/estructura se
   mantiene intacto -- cargarDashboard() lo sigue poblando igual, por compatibilidad. */
#dbPrecaucionCritico { display: none; }

/* Ronda "AJUSTE EJECUTIVO": Alertas Prioritarias sube de importancia -- acento superior propio para
   que se distinga de inmediato como una de las secciones clave. */
.db-alertas-full { border-top: 3px solid var(--db-navy); }
.db-alertas-full h2 { color: var(--db-navy); }

/* Ronda "TIPOGRAFÍA Y LEGIBILIDAD", punto 5: proporción invertida a Alertas 40% / Top Críticos 60%
   (antes 58/42) -- pedido explícito para que Top Críticos tenga más espacio útil y sus columnas
   (Tecnología/Condición/Diagnóstico) no queden "excesivamente truncadas". Ambos con altura acotada
   (ver .db-tabla-criticos-scroll) para que queden equilibrados entre sí. Se colapsa a 1 columna en
   tablet/móvil, igual criterio que el resto de filas de paneles. */
.db-fila-alertas-criticos { display: grid; grid-template-columns: 2fr 3fr; gap: 10px; margin: 10px 18px 0; align-items: start; }
.db-fila-alertas-criticos .dash-seccion { margin: 0; }
@media (max-width: 1200px) {
  .db-fila-alertas-criticos { grid-template-columns: 1fr; }
}
/* Top Críticos gana altura controlada con scroll interno al compartir fila con Alertas (antes crecía
   sin límite mostrando todas las filas -- "usar altura controlada/scroll interno... en lugar de
   alargar excesivamente todo el Dashboard"). En móvil se desactiva el tope: la vista de tarjeta ya
   scrollea con toda la página, un segundo scroll interno ahí sería confuso. */
.db-tabla-criticos-scroll { max-height: 460px; }
@media (max-width: 767px) {
  .db-tabla-criticos-scroll, .db-tabla-detalle-scroll { max-height: none; overflow: visible; }
}

/* Ronda "CORRECCIÓN DEFINITIVA": Equipos No Monitoreados -- Detalle y Ranking Multi-Semana comparten
   fila 50/50 en desktop (antes uno debajo del otro). Info de análisis operativo (nivel 3) -- se
   permite más detalle/altura que las secciones ejecutivas de arriba, con scroll interno acotado. */
.db-fila-nomonitoreados-detalle { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 10px 18px 0; align-items: start; }
.db-fila-nomonitoreados-detalle .dash-seccion { margin: 0 !important; }
@media (max-width: 1024px) {
  .db-fila-nomonitoreados-detalle { grid-template-columns: 1fr; }
}
.db-tabla-detalle-scroll { max-height: 480px; }
/* Las tablas quedan un nivel más adentro (.dash-seccion > .db-panel-scroll > table) -- el ancho/
   margen que antes ponía ".dash-seccion > table" directamente ahora lo da el wrapper. Acotado a estos
   2 contenedores nuevos -- NUNCA ".dash-seccion > .db-panel-scroll" genérico, que afectaría también a
   Cumplimiento por Ruta y Riesgo Operacional (ya validados, fuera de esta ronda). */
#tabDashboard .db-tabla-criticos-scroll, #tabDashboard .db-tabla-detalle-scroll { margin: 0 16px 16px; }
#tabDashboard .db-tabla-criticos-scroll > table, #tabDashboard .db-tabla-detalle-scroll > table { width: 100%; margin: 0; }

/* Alertas: mini-lista SOLO TAG/Componente + condición (el diagnóstico completo vive en "Top
   Equipos Críticos"). TAG arriba, Componente debajo en texto secundario -- mismo patrón ya usado en
   Registro de Condición, nunca repetir el TAG como si fuera la descripción.
   Ronda "AJUSTE EJECUTIVO": al pasar a ancho completo se agranda el límite de alto (de 220px a
   420px) para que la lista se vea sin scroll en el caso normal -- "no esconder esta información",
   "no scroll interno innecesario" -- pero se conserva un tope razonable ante un caso extremo con
   decenas de alertas simultáneas (evita que la página crezca sin límite). */
/* Ronda "TIPOGRAFÍA Y LEGIBILIDAD": fuente/padding mayores -- "TAG/equipo claramente visible...
   facilitar identificación inmediata de Precaución/Crítico". */
.db-alertas-lista { margin: 8px 12px 12px; display: flex; flex-direction: column; gap: 1px; max-height: 420px; overflow-y: auto; }
.db-alerta-fila { display: flex; align-items: center; gap: 8px; padding: 7px 6px 7px 10px; border-bottom: 1px solid var(--border); border-left: 4px solid transparent; font-size: 13px; cursor: pointer; }
.db-alerta-fila:hover { background: var(--table-hover); }
.db-alerta-fila:last-child { border-bottom: none; }
/* CRÍTICO tiene prioridad visual sobre PRECAUCIÓN. */
.db-alerta-critico { border-left-color: var(--db-critico); }
.db-alerta-precaucion { border-left-color: var(--db-precaucion); }
.db-alerta-info { display: flex; flex-direction: column; flex: 1; min-width: 0; line-height: 1.3; }
.db-alerta-tag { font-weight: 700; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.db-alerta-comp { font-size: 11px; color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.db-alerta-tec { flex: none; font-size: 10.5px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: .02em; max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.db-alerta-vacio { padding: 10px 12px; color: var(--text-secondary); font-size: 12px; }

/* No Monitoreados: total destacado + 2 mini-listas (causas / rutas). Ronda "TIPOGRAFÍA Y
   LEGIBILIDAD": mayor protagonismo, mismo criterio que Condición de Activos. */
.db-nomon-resumen { padding: 11px 13px 13px; }
.db-nomon-total { text-align: center; padding-bottom: 9px; margin-bottom: 9px; border-bottom: 1px solid var(--border); }
.db-nomon-n { font-size: 29px; font-weight: 800; color: var(--db-navy); line-height: 1; font-variant-numeric: tabular-nums; }
.db-nomon-l { font-size: 10.5px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: .03em; margin-top: 3px; }
.db-nomon-detalle { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.db-nomon-h { display: block; font-size: 10px; font-weight: 700; color: var(--text-secondary); text-transform: uppercase; letter-spacing: .03em; margin-bottom: 4px; }
.db-nomon-item { display: flex; justify-content: space-between; gap: 6px; font-size: 12px; padding: 2.5px 0; }
.db-nomon-item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-secondary); }
.db-nomon-item b { color: var(--text-primary); flex: none; }

/* Ronda "AJUSTE PUNTUAL — REDISTRIBUIR LOS 6 GRÁFICOS": grilla única de 3 columnas x 2 filas para
   los 6 gráficos de Tendencias/Modos de Falla (antes en 2 secciones separadas, filas de 1-2
   columnas). Todos comparten .dashboard-chart-card (altura uniforme) sea cual sea su tipo real de
   gráfico (barras verticales CSS, barras horizontales renderBarras(), o el SVG de Pareto) -- ver
   overflow-y:auto de abajo como red de seguridad para cuando el contenido natural (p.ej. Ranking con
   muchos modos de falla) sea más alto que la tarjeta. 3 columnas >=1300px, 2 columnas 768-1299px
   (pedido explícito: "puede pasar a 2 columnas si 3 perjudican la legibilidad"), 1 columna <768px. */
.db-grid-tendencias6 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
@media (max-width: 1299px) {
  .db-grid-tendencias6 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 767px) {
  .db-grid-tendencias6 { grid-template-columns: 1fr; }
}
/* Altura un poco mayor que la fila de 2 columnas anterior (218px->248px): con 3 columnas cada
   tarjeta es más angosta, y el SVG de Pareto (relación de aspecto fija 480:250) y sus etiquetas
   rotadas necesitan algo más de alto para seguir siendo legibles. */
#tabDashboard .dashboard-chart-card { height: 248px; min-height: 248px; max-height: 248px; }
#tabDashboard .grafico-barras-v { height: 150px; }
#tabDashboard .dashboard-chart-card-header h4 { font-size: 12.5px; }
#tabDashboard .gv-leyenda { font-size: 11.5px; }
#tabDashboard .chip { font-size: 12.5px; padding: 6px 14px; }
/* Red de seguridad: Tendencia de Condición/Ranking de Modos de Falla usan renderBarras() (lista de
   filas, alto natural variable según cantidad de datos) -- si en algún filtro/semana esa lista es más
   alta que la tarjeta, scrollea internamente en vez de desbordar sobre la tarjeta vecina. Los
   gráficos de barras verticales y el SVG de Pareto ya llenan el 100% del alto disponible sin
   necesitar scroll, así que esto no les afecta. */
#tabDashboard .dashboard-chart-body { overflow-y: auto; }

/* Márgenes laterales reducidos en todas las secciones del Dashboard -- mismo ancho que
   header/filtros/KPIs, para que todo el módulo respire igual. Ronda "TIPOGRAFÍA Y LEGIBILIDAD",
   punto 6: reducir espacios MUERTOS entre tarjetas (margen superior 12px->10px) mientras se aumenta
   el espacio INTERNO de cada una (ver reglas de arriba) -- pedido explícito. */
#tabDashboard .dash-seccion { margin-left: 18px; margin-right: 18px; margin-top: 10px; }
#tabDashboard .dash-seccion > .dash-grid, #tabDashboard .dash-seccion > .dashboard-chart-grid { margin: 10px 16px 12px; }
#tabDashboard .dash-seccion > table { margin-bottom: 12px; }

/* Radio suave + sombra mínima -- .dash-seccion es exclusivo del Dashboard (así que se define acá
   directamente); .panel ya recibe el mismo tratamiento de forma GLOBAL más abajo (ronda "REDISEÑO
   VISUAL INTEGRAL — ETAPA 1"), no hace falta repetirlo aquí. */
#tabDashboard .dash-seccion, #tabDashboard .dashboard-chart-card {
  border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
}
#tabDashboard .dash-seccion h2, #tabDashboard .dashboard-chart-card-header h4, #tabDashboard .panel h4 {
  font-weight: 700; letter-spacing: .01em; color: var(--db-navy);
}
/* Ronda "TIPOGRAFÍA Y LEGIBILIDAD": encabezados de sección un poco más grandes (13px->14px) y con
   algo más de padding vertical (8px->10px) -- títulos más presentes, pedido explícito del punto 1/6. */
#tabDashboard .dash-seccion h2 { font-size: 14px; padding-top: 10px; padding-bottom: 10px; }
#tabDashboard .dashboard-chart-card-header h4 { padding-top: 8px; padding-bottom: 8px; }
/* Ronda "AJUSTE EJECUTIVO", punto 8 (tablas): encabezado azul-grisáceo muy suave, exclusivo del
   Dashboard -- el resto de la app conserva su encabezado blanco/--panel-header-bg de siempre. Ronda
   "TIPOGRAFÍA Y LEGIBILIDAD": tablas con texto/padding levemente mayores en todo el Dashboard. */
#tabDashboard th { background: color-mix(in srgb, var(--db-navy) 6%, white); color: var(--db-blue-2); font-weight: 700; }
#tabDashboard tbody tr:hover td { background: color-mix(in srgb, var(--db-blue-3) 10%, white); }

/* Ronda "AJUSTE EJECUTIVO", punto 8 (tablas -- badges de Condición, filas Crítico/Precaución) y
   punto 9 (gráficos de barras): overrides SOLO dentro de #tabDashboard con la paleta nueva.
   .badge.ok/.tolerable/.review/.error son compartidos por toda la app (Registro de Condición,
   Equipo 360, Seguimiento) -- fuera del Dashboard conservan exactamente su color actual. */
/* Ronda "PALETA OFICIAL DE CONDICIÓN": con colores puros (#00B050/#0000FF/#FFFF00/#FF0000) el
   badge pasa de "fondo muy claro + texto del color" a fondo SÓLIDO + texto de alto contraste --
   con el tono de precaución (amarillo puro), texto del mismo color sobre un fondo apenas teñido
   habría quedado prácticamente ilegible; fondo sólido + texto negro es el patrón estándar de
   advertencia (igual criterio que una señal de precaución) y cumple la regla de contraste pedida
   para las 4 condiciones (blanco/blanco/negro/blanco). */
#tabDashboard .badge.ok { background: var(--db-normal); color: #fff; }
#tabDashboard .badge.tolerable { background: var(--db-tolerable); color: #fff; }
#tabDashboard .badge.review { background: var(--db-precaucion); color: #1F2937; }
#tabDashboard .badge.error { background: var(--db-critico); color: #fff; }
#tabDashboard tr.fila-critico td { border-left: 3px solid var(--db-critico); }
#tabDashboard tr.fila-precaucion td { border-left: 3px solid var(--db-precaucion); }
#tabDashboard .bar-fill.normal { background: var(--db-normal); }
#tabDashboard .bar-fill.tolerable { background: var(--db-tolerable); }
#tabDashboard .bar-fill.precaucion { background: var(--db-precaucion); }
#tabDashboard .bar-fill.critico { background: var(--db-critico); }
#tabDashboard .grafico-barras-v .gv-bar.serie-ejecutados { background: var(--db-ejecutados); }
#tabDashboard .grafico-barras-v .gv-bar.serie-precaucion { background: var(--db-precaucion); }
#tabDashboard .grafico-barras-v .gv-bar.serie-critico { background: var(--db-critico); }

/* ==================== Dashboard ejecutivo (secciones 1-6): cada bloque es un panel SAP con
   cabecera azul-clara propia, nunca un título flotando sobre el fondo. ==================== */
.dash-seccion { margin: 20px 24px 0; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
.dash-seccion h2 {
  font-size: 13px; margin: 0; padding: 10px 16px; display: flex; align-items: center; gap: 8px;
  color: var(--panel-header-text); text-transform: uppercase; letter-spacing: .02em; font-weight: 700;
  background: var(--panel-header-bg); border-bottom: 1px solid var(--border);
}
.dash-seccion h2 .num { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 50%; background: var(--sap-blue); color: #fff; font-size: 10px; font-weight: 700; text-transform: none; }
.dash-seccion .sub { color: var(--text-secondary); font-size: 12px; margin: 10px 16px 0; }
.dash-seccion > .resumen { padding: 12px 16px 4px; }
.dash-seccion > .dash-grid, .dash-seccion > .dashboard-chart-grid { margin: 12px 16px 16px; }
.dash-seccion > .chip-group { margin: 0 16px 16px; }
.dash-seccion > table { width: calc(100% - 32px); margin: 0 16px 16px; }
.dash-seccion > h4 { margin: 16px 16px 6px; }

/* Recorte real de texto largo a 2 líneas visibles (ronda "AUTOAJUSTAR TABLAS DEL DASHBOARD"):
   max-height/overflow puesto DIRECTAMENTE en un <td> no funciona de forma confiable -- el motor de
   tablas del navegador igual estira la fila al alto natural del contenido (se comprobó con datos
   reales: filas de hasta 8 líneas). La técnica que sí funciona es recortar un DIV INTERNO dentro de
   la celda con -webkit-line-clamp (display:-webkit-box) -- el <td> en sí sigue siendo un table-cell
   normal, solo el div de adentro se recorta, así que nunca rompe el modelo de tabla. Se usa mediante
   un helper que envuelve el texto: ver clampTexto() en app.js. */
.clamp-texto { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

/* Dashboard, punto 3 "Equipos Críticos y Precaución": texto más compacto -- SOLO esta tabla
   (".dash-seccion > table" de arriba es compartida con otras secciones del Dashboard, como
   "No Monitoreados"). Actividad/Modo de Falla/Diagnóstico/Recomendación usan .clamp-texto. */
.tabla-criticos { table-layout: fixed; }
/* Ronda "CORREGIR TOP EQUIPOS CRÍTICOS": padding vertical reducido (6px->4px) -- filas más bajas y
   compactas, altura de fila sigue determinada por el contenido (nunca una altura fija grande). */
.tabla-criticos th, .tabla-criticos td { padding: 4px 10px; font-size: 12.5px; line-height: 1.3; vertical-align: top; }
/* Ronda "AJUSTE VISUAL PUNTUAL": Área/Tecnología se quitaron -- la tabla pasó de 6 a 4 columnas
   (1=TAG/Componente, 2=Condición, 3=Diagnóstico, 4=Fecha). Los nth-child de abajo se renumeraron para
   seguir apuntando a TAG y Fecha (antes 1 y 6, ahora 1 y 4) y al centrado de TAG/Condición/Fecha
   (antes 1/3/4/6, ahora 1/2/4 -- ya no existe una columna "3=Tecnología" que centrar). El TAG no debe
   envolver en varias líneas (mismo criterio que Registro de Condición) -- si no, la fila entera crece
   para acomodarlo y el recorte de las demás columnas de abajo no sirve de nada. */
.tabla-criticos td:nth-child(1), .tabla-criticos td:nth-child(4) { white-space: nowrap; }
.tabla-criticos th:nth-child(1), .tabla-criticos td:nth-child(1),
.tabla-criticos th:nth-child(2), .tabla-criticos td:nth-child(2),
.tabla-criticos th:nth-child(4), .tabla-criticos td:nth-child(4) { text-align: center; }
/* Ronda "CORRECCIÓN DEFINITIVA — LUBRIANALYTICS": al compartir fila con Alertas la tabla queda más
   angosta -- sin recorte, el badge de Condición (p.ej. "PRECAUCION") se desbordaba literalmente
   encima de la columna vecina (bug real, confirmado visualmente). Todas las columnas salvo
   Diagnóstico (ahora columna 3 -- ya usa su propio recorte de 2 líneas vía .clamp-texto, incompatible
   con nowrap) truncan con elipsis en vez de desbordar. Restringido a >=768px: por debajo la tabla pasa
   a vista de tarjeta (móvil) con sus propias reglas de white-space:normal -- esta regla nunca debe
   competir con esas. */
@media (min-width: 768px) {
  .tabla-criticos th:not(:nth-child(3)), .tabla-criticos td:not(:nth-child(3)) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}
/* Ronda "TIPOGRAFÍA Y LEGIBILIDAD": con Top Críticos ahora al 60% del ancho (antes 42%) hay más
   espacio real -- badge/subtítulo de componente crecen un poco (siguen con elipsis como red de
   seguridad, ya no hace tanta falta con el ancho nuevo). */
.tabla-criticos .badge { font-size: 10.5px; padding: 2px 7px; }
/* Ronda "REDISEÑO EJECUTIVO": celda 1 ahora es TAG + Componente apilados. El nth-child(1) de
   arriba sigue con nowrap para que el TAG nunca envuelva; el Componente (línea secundaria, puede
   ser más largo) trunca con elipsis en vez de desbordar la celda de ancho fijo (20%). */
.tabla-criticos td:nth-child(1) .td-componente-sub { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11.5px; color: var(--muted); }

/* Dashboard, punto 4 "Equipos No Monitoreados": mismo tratamiento que el punto 3 -- compacto,
   columna TAG centrada y sin envolver, Actividad/Causa con .clamp-texto.
   Ronda "AJUSTE PUNTUAL": Equipo/Observación/Ruta se quitaron -- la tabla pasó de 7 a 4 columnas
   (1=TAG, 2=Actividad, 3=Causa, 4=Fecha programada). El centrado que antes tenía la columna 2
   (Equipo, texto corto) ya NO aplica -- Actividad es texto largo y debe quedar a la izquierda. */
.tabla-no-monitoreados { table-layout: fixed; }
.tabla-no-monitoreados th, .tabla-no-monitoreados td { padding: 6px 10px; font-size: 12.5px; line-height: 1.35; vertical-align: top; }
.tabla-no-monitoreados td:nth-child(1) { white-space: nowrap; }
.tabla-no-monitoreados th:nth-child(1), .tabla-no-monitoreados td:nth-child(1) { text-align: center; }
/* Ronda "CORRECCIÓN DEFINITIVA": esta tabla ahora comparte fila con "Ranking Multi-Semana" (~50% del
   ancho) -- el TAG (nowrap sin overflow:hidden) se desbordaba encima de la columna Equipo (bug real,
   mismo patrón que Top Críticos). Solo >=768px -- a partir de ahí el nth-child(1) pasa a
   white-space:normal en la vista de tarjeta móvil, que no debe competir con esto. */
@media (min-width: 768px) {
  .tabla-no-monitoreados th:nth-child(1), .tabla-no-monitoreados td:nth-child(1) { overflow: hidden; text-overflow: ellipsis; }
}

/* Sub-tabla "Ranking multi-semana" dentro del mismo punto 4 -- nunca tuvo colgroup ni compactación;
   Actividad con .clamp-texto (mismo motivo que arriba). */
.tabla-ranking-noejec { table-layout: fixed; }
.tabla-ranking-noejec th, .tabla-ranking-noejec td { padding: 6px 10px; font-size: 12.5px; line-height: 1.35; vertical-align: top; }
.tabla-ranking-noejec td:nth-child(1) { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tabla-ranking-noejec th:nth-child(1), .tabla-ranking-noejec td:nth-child(1),
.tabla-ranking-noejec th:nth-child(2), .tabla-ranking-noejec td:nth-child(2),
.tabla-ranking-noejec th:nth-child(4), .tabla-ranking-noejec td:nth-child(4) { text-align: center; }
/* Módulo Seguimiento: mismo tratamiento de compactación que las tablas del Dashboard -- TAG/Equipo
   sin envolver, Diagnóstico/Recomendación recortados a 2 líneas con .clamp-texto (title nativo =
   tooltip con el texto completo al pasar el mouse, pedido explícito del usuario). El resto de las
   columnas se leen completas, sin recorte -- solo más compactas. */
.tabla-seguimiento { table-layout: fixed; }
.tabla-seguimiento th, .tabla-seguimiento td { padding: 5px 8px; font-size: 12px; line-height: 1.3; vertical-align: top; overflow-wrap: anywhere; }
.tabla-seguimiento td:nth-child(1), .tabla-seguimiento td:nth-child(2), .tabla-seguimiento td:nth-child(13), .tabla-seguimiento td:nth-child(14) { white-space: nowrap; }
.tabla-seguimiento th:nth-child(1), .tabla-seguimiento td:nth-child(1),
.tabla-seguimiento th:nth-child(2), .tabla-seguimiento td:nth-child(2),
.tabla-seguimiento th:nth-child(8), .tabla-seguimiento td:nth-child(8),
.tabla-seguimiento th:nth-child(9), .tabla-seguimiento td:nth-child(9),
.tabla-seguimiento th:nth-child(12), .tabla-seguimiento td:nth-child(12),
.tabla-seguimiento th:nth-child(13), .tabla-seguimiento td:nth-child(13),
.tabla-seguimiento th:nth-child(14), .tabla-seguimiento td:nth-child(14) { text-align: center; }

.dash-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
.dash-grid-3 { grid-template-columns: 1fr 1fr 1fr; }
.dash-grid > div { min-width: 0; }
/* Ronda "REDISEÑO VISUAL INTEGRAL — ETAPA 1": radio suave + sombra mínima global (antes solo el
   Dashboard lo tenía) -- .panel es compartido por Dashboard/Programa Semanal/otros módulos. */
.panel { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.04); padding: 0; overflow: hidden; }
.panel h4 { margin: 0 0 10px; font-size: 12px; color: var(--sap-blue-dark); text-transform: uppercase; letter-spacing: .03em; font-weight: 700; background: var(--panel-header-bg); border-bottom: 1px solid var(--border); padding: 8px 12px; }
.panel > *:not(h4) { margin-left: 12px; margin-right: 12px; }
.panel > table { width: calc(100% - 24px); }
.panel > *:last-child { margin-bottom: 12px; }

.bar-row { display: grid; grid-template-columns: 152px 1fr 40px; gap: 8px; align-items: center; font-size: 12px; margin-bottom: 8px; }
.bar-row .lbl { color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: default; }
.bar-track { background: var(--track-bg); border-radius: 6px; height: 10px; overflow: hidden; border: 1px solid var(--border); }
.bar-fill { height: 100%; background: var(--sap-blue); }
.bar-fill.normal { background: var(--success); }
.bar-fill.tolerable { background: var(--information); }
.bar-fill.precaucion { background: var(--warning); }
.bar-fill.critico { background: var(--critical); }
.bar-row .val { text-align: right; color: var(--text-secondary); font-weight: 600; font-variant-numeric: tabular-nums; }

/* Color como INDICADOR (borde izquierdo), nunca la fila completa pintada (sección 16 del pedido). */
tr.fila-critico td { border-left: 3px solid var(--critical); }
tr.fila-precaucion td { border-left: 3px solid var(--warning); }

.chip-group { display: flex; gap: 6px; flex-wrap: wrap; }
.chip { background: var(--surface); border: 1px solid var(--border); color: var(--text-secondary); padding: 5px 13px; border-radius: 6px; font-size: 12px; font-weight: 600; cursor: pointer; transition: background .15s, border-color .15s, color .15s; }
.chip:hover { border-color: var(--sap-blue); color: var(--sap-blue); }
.chip.active { background: var(--sap-blue); border-color: var(--sap-blue); color: #fff; }

/* ==================== Programa Semanal -- Vista Semanal (planificación pura) ==================== */
.semana-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 10px; padding: 12px 24px 30px; align-items: start; }
.semana-dia { background: var(--surface); border: 1px solid var(--border); border-radius: 6px; min-height: 120px; display: flex; flex-direction: column; overflow: hidden; }
.semana-dia .dia-cabecera { padding: 8px 10px; border-bottom: 1px solid var(--border); background: var(--surface-alt); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--panel-header-text); display: flex; justify-content: space-between; }
.semana-dia .dia-cabecera .fecha { color: var(--panel-header-text); font-weight: 400; text-transform: none; opacity: .8; }
.semana-dia .dia-cuerpo { padding: 8px; display: flex; flex-direction: column; gap: 6px; flex: 1; }
/* El color de la tarjeta identifica la TÉCNICA DE INSPECCIÓN de forma SECUNDARIA (sección 14 del
   pedido) -- nunca el estado de ejecución, que sigue mostrándose únicamente en el badge .b-estado. */
.bloque-ruta { background: var(--surface); border: 1px solid var(--border); border-left: 4px solid var(--border); border-radius: 6px; padding: 7px 9px; font-size: 12px; cursor: pointer; transition: box-shadow .15s; }
.bloque-ruta:hover { box-shadow: 0 2px 6px rgba(10,45,90,.12); }
.bloque-ruta .b-ruta { font-weight: 700; margin-bottom: 2px; color: var(--text-primary); }
.bloque-ruta .b-tecnica { margin-bottom: 3px; }
.bloque-ruta .b-meta { color: var(--text-secondary); font-size: 11px; line-height: 1.5; }
.bloque-ruta .b-ot { margin-top: 4px; font-size: 11px; color: var(--text-secondary); display: flex; align-items: center; flex-wrap: wrap; gap: 2px; }
.bloque-ruta .b-estado { margin-top: 4px; }
.dia-vacio { color: var(--text-secondary); font-size: 11px; padding: 8px 4px; text-align: center; }

/* Texto "Pendiente" fuera de una celda de inspector (p.ej. OT sin asignar) -- ronda "OT EN PROGRAMA
   SEMANAL". Distinto de .campo-inspector.pendiente (esa es una celda entera atenuada). */
span.pendiente { color: var(--pending); font-style: italic; }

.badge-tecnica { font-size: 10px; font-weight: 700; letter-spacing: .02em; padding: 1px 7px; border-radius: 999px; display: inline-block; }
.bloque-ruta.tec-vibracion { border-left-color: var(--tec-vibracion); }
.bloque-ruta.tec-termografia { border-left-color: var(--tec-termografia); }
.bloque-ruta.tec-aceite { border-left-color: var(--tec-aceite); }
.bloque-ruta.tec-ut { border-left-color: var(--tec-ut); }
.bloque-ruta.tec-visual { border-left-color: var(--tec-visual); }
.bloque-ruta.tec-otra { border-left-color: var(--tec-otra); }
.badge-tecnica.tec-vibracion { color: var(--tec-vibracion); background: color-mix(in srgb, var(--tec-vibracion) 14%, white); }
.badge-tecnica.tec-termografia { color: var(--tec-termografia); background: color-mix(in srgb, var(--tec-termografia) 15%, white); }
.badge-tecnica.tec-aceite { color: var(--tec-aceite); background: color-mix(in srgb, var(--tec-aceite) 14%, white); }
.badge-tecnica.tec-ut { color: var(--tec-ut); background: color-mix(in srgb, var(--tec-ut) 14%, white); }
.badge-tecnica.tec-visual { color: var(--tec-visual); background: color-mix(in srgb, var(--tec-visual) 16%, white); }
.badge-tecnica.tec-otra { color: var(--tec-otra); background: color-mix(in srgb, var(--tec-otra) 14%, white); }

.leyenda-tecnica { display: flex; flex-wrap: wrap; gap: 4px 16px; padding: 10px 24px; margin: 12px 24px 0; font-size: 12px; color: var(--text-secondary); background: var(--surface); border: 1px solid var(--border); border-radius: 6px; }
.leyenda-tecnica .l-item { display: inline-flex; align-items: center; gap: 6px; }
.leyenda-tecnica .l-punto { width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex: none; }

/* ==================== Vista Consolidada (Programa Semanal) ==================== */
.vc-toggle { display: flex; gap: 4px; margin: 0 0 10px; }
.vc-toggle button { background: var(--surface); border: 1px solid var(--border); color: var(--text-secondary); padding: 7px 14px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 600; transition: background .15s, border-color .15s, color .15s; }
.vc-toggle button:hover { border-color: var(--sap-blue); color: var(--sap-blue); }
.vc-toggle button.active { background: var(--sap-blue); border-color: var(--sap-blue); color: #fff; }

/* Base Maestra: sub-pestañas RUTAS / EQUIPOS -- misma vista maestra, dos formas de mirarla. */
.bm-subtabs { display: flex; gap: 4px; padding: 16px 24px 0; }
.bm-subtab { background: var(--surface-alt); border: 1px solid var(--border); color: var(--text-secondary); padding: 8px 18px; border-radius: 6px 6px 0 0; cursor: pointer; font-size: 13px; font-weight: 600; transition: background .15s, color .15s; }
.bm-subtab:hover { color: var(--sap-blue); }
.bm-subtab.active { background: var(--panel-header-bg); border-color: var(--border); color: var(--panel-header-text); box-shadow: inset 0 2px 0 var(--sap-blue); }

.bm-sync-bar { display: flex; align-items: center; gap: 14px; padding: 12px 24px 0; }
.bm-sync-indicador { color: var(--text-secondary); font-size: 12px; }

.campo-sistema { color: var(--text-primary); }
.campo-inspector { color: var(--text-primary); }
/* "Pendiente" discreto (sección 10 del pedido): nunca debe competir visualmente con datos reales --
   cuando SÍ hay información real, .campo-inspector (sin .pendiente) usa el color de texto normal,
   con más contraste que este gris-azulado apagado. */
.campo-inspector.pendiente { color: var(--pending); font-style: italic; opacity: .6; }
/* Ronda "ETAPA 3 — MÓDULOS OPERATIVOS": se retira el tinte azul que separaba las columnas "de
   inspector" (era una franja de color de marca, el mismo tipo de elemento SAP que Etapa 1 eliminó
   en el resto de la app) -- la separación entre "datos del sistema" (1-8) y "datos del inspector"
   (9-13, desde la ronda "SIMPLIFICACIÓN REGISTRO DE CONDICIÓN" que quitó Diagnóstico/Recomendación)
   queda como un único borde vertical discreto al inicio del bloque (columna 9, Modo de Falla), sin
   color de marca. Ver el bloque de comentario más abajo sobre columnas posicionales -- si el número
   de columnas cambia, este selector también debe revisarse. */
table.consolidada th:nth-child(9), table.consolidada td:nth-child(9) { border-left: 2px solid var(--border); }

/* ==================== Registro de Condición -- distribución de anchos (ronda "MEJORA VISUAL —
   REGISTRO DE CONDICIÓN", ajustada en "ELIMINAR COLUMNA ACTIVIDAD" y en "SIMPLIFICACIÓN REGISTRO DE
   CONDICIÓN" -- esta última QUITA Diagnóstico y Recomendación del listado, puramente presentación:
   los campos se siguen pidiendo/guardando igual, solo dejan de tener <td> propia acá; siguen
   accesibles con "Ver detalle" y en Equipo 360/Seguimiento/Generador de Reportes/PDF-Excel):
   table-layout:fixed + <colgroup> reparte el ancho a propósito (más para TAG/Descripción/Ruta, menos
   para Orden/Semana/Programado/Estado/Modo de Falla/Condición/Reporte/Analista SGS/Analista MMG) en
   vez de columnas iguales -- nunca más se corta un TAG en tres líneas.
   IMPORTANTE: estas reglas son POSICIONALES (nth-child) -- si el número de columnas de la tabla
   vuelve a cambiar (agregar/quitar una), estos índices deben revisarse TODOS juntos en el mismo
   cambio (bloque desktop de acá + los 3 bloques responsive de abajo: tablet vertical, tablet
   horizontal y celular), nunca dejarse "para después" (así se rompieron silenciosamente antes).
   Columnas actuales (14): 1 Orden, 2 Semana, 3 Programado, 4 Estado, 5 TAG, 6 Descripción,
   7 Ruta, 8 OT, 9 Modo de Falla, 10 Condición, 11 Reporte, 12 Analista SGS, 13 Analista MMG,
   14 Generar Reporte. ==================== */
table.consolidada { table-layout: fixed; }
/* Compactación (ronda "COMPACTAR REGISTRO DE CONDICIÓN"): mismo layout de columnas de arriba, solo
   se reduce el padding/tipografía de celda para que quepan más filas visibles sin scroll. */
table.consolidada th, table.consolidada td {
  padding: 4px 7px; height: auto; vertical-align: top;
  font-family: inherit; font-size: 12.5px; font-weight: 400;
  color: var(--text-primary); line-height: 1.25;
}
/* Hover sutil propio de esta tabla (más suave que el --table-hover general) para poder seguir una
   fila con la mirada de izquierda a derecha (TAG -> DESCRIPCIÓN -> RUTA -> DIAGNÓSTICO -> RECOMENDACIÓN). */
table.consolidada tbody tr:hover td { background: #EAF3FC; }
/* Encabezados (ronda "TÍTULOS EN NEGRITA Y CENTRADO"): todas las columnas, sin excepción -- solo los
   títulos de cabecera, el contenido de las celdas mantiene su alineación propia (TAG/Descripción/etc.).
   overflow-wrap:break-word (ronda "SIMPLIFICACIÓN REGISTRO DE CONDICIÓN"): con columnas angostas
   (Reporte/Analista SGS/Analista MMG) una sola palabra sin espacios ("Reporte", "Analista") no tiene
   dónde cortar y se desbordaba visualmente sobre la columna vecina -- bug real detectado en pruebas a
   1366px, se ve como texto de dos encabezados pegado/ilegible. Rompe la palabra en dos líneas en vez
   de desbordar. */
table.consolidada thead th { font-weight: 700; text-align: center; overflow-wrap: break-word; font-size: 10.5px; }
table.consolidada th.col-corta, table.consolidada td.col-corta,
table.consolidada th:nth-child(1), table.consolidada td:nth-child(1),
table.consolidada th:nth-child(2), table.consolidada td:nth-child(2),
table.consolidada th:nth-child(3), table.consolidada td:nth-child(3),
table.consolidada th:nth-child(4), table.consolidada td:nth-child(4),
table.consolidada th:nth-child(10), table.consolidada td:nth-child(10),
table.consolidada th:nth-child(11), table.consolidada td:nth-child(11),
table.consolidada th:nth-child(12), table.consolidada td:nth-child(12),
table.consolidada th:nth-child(13), table.consolidada td:nth-child(13) { text-align: center; }
/* TAG: nunca se corta en varias líneas (sección 4 del pedido). */
table.consolidada td:nth-child(5) { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 700; vertical-align: middle; }
/* Columnas de texto largo: alineadas a la izquierda, palabras completas, máximo ~3 líneas visibles
   (sección 6: nunca text-align:justify, nunca cortar palabras por la mitad). NUNCA usar
   -webkit-line-clamp aquí: exige display:-webkit-box, que rompe por completo el modelo de tabla
   (display:table-cell) y descuadra filas/columnas -- max-height + overflow logra el mismo resultado
   visual sin sacar la celda de su rol de table-cell. Descripción (6) y Ruta (7) -- ya no Actividad,
   que se eliminó de la tabla. */
table.consolidada td:nth-child(6), table.consolidada td:nth-child(7),
table.consolidada td.col-inspector:not(.col-corta) {
  text-align: left; overflow-wrap: normal; word-break: normal; white-space: normal; hyphens: none;
  max-height: 4.2em; overflow: hidden; position: relative;
}
/* Ronda "ETAPA 3": degradado sutil al final del texto recortado -- mismo max-height/overflow de
   arriba, solo cambia la sensación visual de "corte seco" a "hay más contenido". Se aplica siempre
   (no solo cuando el texto realmente desborda) porque en CSS puro no hay forma de detectar el
   desborde real sin JS -- en celdas con texto corto el degradado es tan bajo (10px) que no se nota. */
table.consolidada td:nth-child(6)::after, table.consolidada td:nth-child(7)::after,
table.consolidada td.col-inspector:not(.col-corta)::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 10px;
  background: linear-gradient(to bottom, transparent, var(--surface)); pointer-events: none;
}
table.consolidada tbody tr:hover td:nth-child(6)::after, table.consolidada tbody tr:hover td:nth-child(7)::after,
table.consolidada tbody tr:hover td.col-inspector:not(.col-corta)::after {
  background: linear-gradient(to bottom, transparent, #EAF3FC);
}
/* Columna DESCRIPCIÓN (sección "ELIMINAR COLUMNA ACTIVIDAD"): ahora muestra lo que antes mostraba
   Actividad (f.actividad -- la descripción real del punto/componente, ver ConstruirNombreActividad
   en el backend), con la misma jerarquía visual entre línea principal y línea secundaria (más
   discreta) que ya tenía Actividad -- ver renderActividadRegistro() en app.js, que separa por el
   mismo " - " con el que el backend construye NombreActividad. Solo cambia DÓNDE se muestra ese
   valor, nunca el valor en sí ni cómo se calcula. */
table.consolidada td:nth-child(6) { max-height: 5.4em; }
.act-principal { color: var(--text-primary); }
.act-secundaria { color: var(--text-secondary); font-size: 11px; font-weight: 400; line-height: 1.25; margin-top: 1px; }
/* Separador sutil al iniciar una nueva Ruta (sección 11): SOLO presentación, la fila sigue siendo un
   registro independiente, nunca se fusiona ni usa rowspan. */
table.consolidada tbody tr.fila-nueva-ruta td { border-top: 2px solid var(--sap-blue-light); }

/* ==================== RONDA "CORRECCIÓN VISUAL PUNTUAL — REGISTRO DE CONDICIÓN EN ESCRITORIO":
   SOLO tipografía + padding, ningún ancho/columna/estructura tocado. Scoped a @media(min-width:1200px)
   a propósito -- tablet (768-1199) y celular (<768) ya redeclaran su propio font-size/padding dentro
   de sus propios @media más abajo (que no cambian con esta ronda), así que esta reducción NUNCA puede
   heredarse hacia ellos: fuera de este media query la regla simplemente no aplica a ningún ancho. */
@media (min-width: 1200px) {
  table.consolidada thead th { font-size: 10px; }
  table.consolidada th, table.consolidada td { padding: 3px 4px; font-size: 11.5px; }
  table.consolidada .act-secundaria { font-size: 9.5px; }
  /* white-space:nowrap explícito -- "NO EJECUTADO" tiene un espacio (punto de corte legal); a este
     ancho de columna alcanzaba a envolver en 2 líneas ("NO" / "EJECUTADO"), detectado por medición
     real. Los badges siempre deben quedar en una sola línea. */
  table.consolidada .badge { font-size: 9.5px; padding: 2px 6px; white-space: nowrap; }

  /* RONDA "AJUSTE FINAL — REGISTRO DE CONDICIÓN EN ESCRITORIO": la celda de Condición no siempre
     muestra un badge -- cuando la fila es NO_EJECUTADO sin condición técnica, muestra en texto
     plano la causa real (f.causaNoEjecucion, catálogo de 13 códigos en backend, algunos largos:
     "EQUIPO_DETENIDO", "FALTA_INSTRUMENTO", "INTERFERENCIA_OPERACIONAL" -- ver
     CatalogSeedConfigurations.cs). Exigir que TODOS entren en una sola línea forzaba la columna a un
     ancho excesivo, robándole demasiado a Descripción. Se permite que ESTE texto envuelva (máximo
     ~2 líneas para los casos largos) en vez de invadir Reporte -- "anywhere" porque son palabras con
     "_" sin espacios, sin puntos de corte naturales. Scoped por [data-label="Condición"] (ver
     inspector(..., 'Condición') en app.js) -- afecta SOLO esta columna, nunca el resto de la tabla.
     Los badges reales (NORMAL/TOLERABLE/PRECAUCION/CRITICO) se protegen explícitamente abajo para
     que NUNCA envuelvan, sin importar que hereden estas reglas de su celda contenedora. */
  table.consolidada td[data-label="Condición"] {
    overflow-wrap: anywhere; word-break: break-word; white-space: normal;
  }
  table.consolidada td[data-label="Condición"] .badge {
    white-space: nowrap; overflow-wrap: normal; word-break: normal;
  }
}

/* Tablet / pantallas medianas: navegación vuelve a barra horizontal superior (sección 6: "si esto
   requiere cambios funcionales importantes, no hacerlo" -- en viewport angosto el sidebar deja de
   ser práctico, así que se revierte a la disposición horizontal ya validada). */
@media (max-width: 1024px) {
  /* El sidebar auto-ocultable es un truco de escritorio (ancho de sobra en el borde izquierdo) --
     en tablet/móvil vuelve siempre a la barra horizontal de siempre, sin importar data-sidebar ni
     hover (selectores con la misma o mayor especificidad que las reglas de estado del sidebar). */
  body, body[data-sidebar="fijado"], body[data-sidebar="contraido"],
  body:has(header:hover), body:has(.tabs:hover) { grid-template-columns: 1fr; grid-template-rows: auto auto auto 1fr; }
  header { grid-column: 1; grid-row: 1; flex-direction: row; align-items: center; justify-content: space-between; padding: 14px 20px; overflow: visible; }
  header .db-path { background: rgba(255,255,255,.12); padding: 4px 10px; border-radius: 6px; }
  .tabs { grid-column: 1; grid-row: 2; flex-direction: row; overflow-x: auto; overflow-y: hidden; flex-wrap: nowrap; -webkit-overflow-scrolling: touch; padding: 6px 8px; }
  .nav-grupo { flex-direction: row; margin-bottom: 0; gap: 2px; }
  .nav-grupo-titulo { display: none; } /* sin espacio horizontal para subtítulos de grupo en móvil */
  .tab-btn { padding: 12px 16px; font-size: 14px; white-space: nowrap; border-left: none; border-bottom: 3px solid transparent; border-radius: 0; width: auto; }
  .tab-btn.active { border-left: none; border-bottom-color: #fff; }
  .sidebar-pie { grid-column: 1; grid-row: 3; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 20px; }
  .sidebar-pie-usuario { margin-bottom: 0; }
  .sidebar-pie-salir { width: auto; }
  .tab-panel { grid-column: 1; grid-row: 4; }
  .sidebar-toggle { display: none; } /* sin sentido en la barra horizontal siempre visible */
  .filtros button, .form-actions button { padding: 10px 18px; font-size: 14px; min-height: 40px; height: auto; }
  .filtros select, .filtros input, form.form-inline input, form.form-inline select { padding: 10px; font-size: 14px; min-height: 40px; height: auto; }
  table { display: block; overflow-x: auto; white-space: nowrap; }
  .modal { max-width: 96vw; }
  form.form-inline { grid-template-columns: 1fr; }
  .dash-grid { grid-template-columns: 1fr; }
  .dash-seccion { margin-left: 12px; margin-right: 12px; }
  .semana-grid { grid-template-columns: repeat(2, 1fr); padding: 0 12px 24px; }
}
@media (min-width: 1025px) and (max-width: 1400px) {
  .semana-grid { grid-template-columns: repeat(4, 1fr); }
}
@media (max-width: 640px) {
  .modal .encabezado { grid-template-columns: 1fr 1fr; }
}

/* ==================== RONDA "RESPONSIVE R1" (estructura global + navegación + Dashboard) ====================
   Regla de trabajo no negociable: NINGUNA línea de este bloque vive fuera de un @media con
   max-width <= 1199px -- así 1366x768 y 1920x1080 (desktop >=1200px) quedan garantizados sin tocar
   ni una sola regla de arriba. Las reglas de aquí SÍ tienen prioridad sobre el bloque histórico
   "@media (max-width: 1024px)" de arriba para el rango que ambos comparten (768-1024px): misma
   especificidad, pero éste va después en el archivo, así que gana por orden de cascada -- es
   intencional, reemplaza aquel comportamiento ("volver a barra horizontal") por el rail/drawer reales
   que pide esta etapa, sección 3 y sección 2 del pedido.
   Overlay del panel de navegación de celular y botón "Filtros" (inyectado por JS en TODOS los
   viewports, ver inicializarFiltrosColapsables() en app.js): ambas clases nuevas, ocultas por
   defecto -- solo el @media de celular más abajo las vuelve a mostrar. Así en tablet/escritorio el
   botón queda invisible y cada .filtros/.db-filtros se ve exactamente igual que hoy. */
.sidebar-overlay, .filtros-toggle { display: none; }

/* ---- TABLET (768px-1199px): sidebar contraíble (rail), nunca la barra horizontal de antes ---- */
@media (min-width: 768px) and (max-width: 1199px) {
  :root { --sidebar-w-colapsado: 60px; --sidebar-w: 210px; }
  /* !important necesario: la regla de hover de escritorio (:not([data-sidebar=...]):has(header:hover),
     más arriba en este archivo) es MÁS específica que un simple body:has(...) -- sin !important
     seguiría ganando ella y el rail se expandiría a 210px con el mouse/trackpad de una tablet 2-en-1,
     pero SIN mostrar etiquetas (esas sí quedan bien controladas más abajo) -- bug real detectado en
     pruebas, no solo cosmético. */
  body, body[data-sidebar="fijado"], body[data-sidebar="contraido"],
  body:has(header:hover), body:has(.tabs:hover) {
    grid-template-columns: var(--sidebar-w-colapsado) 1fr !important; grid-template-rows: auto 1fr auto;
  }
  body[data-sidebar="fijado"] { grid-template-columns: var(--sidebar-w) 1fr !important; }
  .sidebar-toggle { display: flex; }
  header { grid-column: 1; grid-row: 1; flex-direction: column; align-items: stretch; padding: 16px 8px 12px; overflow: hidden; min-width: 0; }
  header .db-path { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
  body:not([data-sidebar="fijado"]) header h1,
  body:not([data-sidebar="fijado"]) .header-subtitulo,
  body:not([data-sidebar="fijado"]) header .db-path { display: none; }
  .tabs { grid-column: 1; grid-row: 2; flex-direction: column; overflow-x: hidden; overflow-y: auto; padding: 10px 6px; }
  .nav-grupo { flex-direction: column; margin-bottom: 10px; }
  body:not([data-sidebar="fijado"]) .nav-grupo-titulo,
  body:not([data-sidebar="fijado"]) .tab-label { display: none; }
  /* El viejo bloque "@media (max-width:1024px)" oculta .nav-grupo-titulo sin condición -- cuando el
     rail SÍ está fijado/expandido (210px, hay espacio) se restaura. */
  body[data-sidebar="fijado"] .nav-grupo-titulo { display: block; }
  .tab-btn { justify-content: center; padding: 10px 4px; border-left: none; border-bottom: none; border-radius: 6px; width: 100%; min-height: 44px; }
  body[data-sidebar="fijado"] .tab-btn { justify-content: flex-start; padding: 9px 12px; border-left: 3px solid transparent; }
  body[data-sidebar="fijado"] .tab-btn.active { border-left-color: var(--information); }
  .sidebar-pie { grid-column: 1; grid-row: 3; padding: 10px 6px; }
  body:not([data-sidebar="fijado"]) .sidebar-pie-usuario { display: none; }
  body:not([data-sidebar="fijado"]) .sidebar-pie-salir { font-size: 10px; padding: 8px 2px; }
  .tab-panel { grid-column: 2; grid-row: 1 / -1; }

  .resumen { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
  #tabDashboard .db-fila-3paneles { grid-template-columns: repeat(2, 1fr); }
  form.form-inline { grid-template-columns: 1fr 1fr; }
}

/* ---- CELULAR (<768px): sidebar en panel superpuesto (drawer), oculto por defecto ---- */
@media (max-width: 767px) {
  body, body[data-sidebar="fijado"], body[data-sidebar="contraido"],
  body:has(header:hover), body:has(.tabs:hover) { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }

  header { grid-column: 1; grid-row: 1; flex-direction: column; align-items: flex-start; padding: 12px 16px 10px 52px; overflow: visible; gap: 2px; min-width: 0; }
  header h1 { font-size: 14px; white-space: normal; }
  .header-subtitulo { display: none; } /* información secundaria: cada módulo ya trae su propio subtítulo debajo del título */
  /* #dbPath muestra la ruta real configurada de la BD (salud.baseDeDatos, ver init() en app.js) --
     puede ser larga y sin espacios; sin esto, un <div> de bloque con texto irrompible estira el grid
     de body entero más allá del viewport (bug real detectado en pruebas: el ítem de grid "header" sin
     min-width:0 vuelve a su min-content, que es el ancho completo del texto). */
  header .db-path { font-size: 9px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
  .sidebar-toggle { display: flex; z-index: 60; }

  /* Panel superpuesto: nunca ocupa espacio permanente -- position:fixed + translateX fuera de pantalla
     hasta que body[data-sidebar-movil="abierto"] (ver alternarSidebarMovil() en app.js). .sidebar-pie
     vive DENTRO de <nav class="tabs"> en el HTML (último hijo, no un hermano al nivel de body) -- un
     solo panel fixed (.tabs) que desliza completo; .sidebar-pie solo se empuja al fondo de esa misma
     columna flex con margin-top:auto, nunca su propio position:fixed (rompería con el transform de acá). */
  .tabs {
    position: fixed; left: 0; top: 0; bottom: 0; width: 82vw; max-width: 300px; z-index: 50;
    background: var(--sap-blue-dark); transform: translateX(-100%); transition: transform .2s ease;
    box-shadow: 4px 0 24px rgba(0,0,0,.25); flex-direction: column; overflow-y: auto; overflow-x: hidden;
    padding: 56px 10px 10px;
  }
  .sidebar-pie { margin-top: auto; justify-content: center; }
  body[data-sidebar-movil="abierto"] .tabs { transform: translateX(0); }
  body[data-sidebar-movil="abierto"] .sidebar-overlay { display: block; position: fixed; inset: 0; background: rgba(15,23,42,.45); z-index: 45; }
  .nav-grupo { flex-direction: column; margin-bottom: 10px; gap: 1px; }
  /* El viejo bloque "@media (max-width:1024px)" oculta .nav-grupo-titulo (pensado para la barra
     horizontal, sin espacio para subtítulos) -- acá SÍ hay espacio de sobra (panel de 82vw), se
     restaura. */
  .nav-grupo-titulo { display: block; }
  /* Neutraliza los residuos del viejo bloque "@media (max-width:1024px)" pensados para la barra
     horizontal (border-left:none, border-radius:0, white-space:nowrap) -- acá vuelve a ser lista
     vertical, con la misma marca de activo (borde izquierdo) que ya usa escritorio. */
  .tab-btn {
    min-height: 46px; font-size: 14px; width: 100%; white-space: normal; text-align: left;
    border-left: 3px solid transparent; border-bottom: none; border-radius: 6px; padding: 11px 14px;
  }
  /* El viejo bloque "@media (max-width:1024px)" también pone .tab-btn.active{border-left:none} para
     la barra horizontal (más específico que el reset de arriba) -- se re-declara acá para que el
     acento de color a la izquierda vuelva a verse en la lista vertical del panel. */
  .tab-btn.active { border-left-color: var(--information); border-bottom: none; }
  .tab-panel { grid-column: 1; grid-row: 2; }

  /* ---- Filtros colapsables (componente GLOBAL, botón inyectado por inicializarFiltrosColapsables() en app.js) ---- */
  .filtros-toggle { display: flex; width: 100%; justify-content: center; margin-bottom: 4px; min-height: 40px; }
  .filtros:not(.filtros-abierto) > *:not(.filtros-toggle),
  .db-filtros:not(.filtros-abierto) > *:not(.filtros-toggle) { display: none; }
  .filtros.filtros-abierto, .db-filtros.filtros-abierto { flex-direction: column; align-items: stretch; }
  .filtros.filtros-abierto > *, .db-filtros.filtros-abierto > * { width: 100%; }
  .filtros button, .db-filtros button, .form-actions button { min-height: 44px; }

  /* ---- KPIs: grid 2 columnas (todos los módulos comparten .resumen/.card, sección "componente compartido") ---- */
  .resumen { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; padding: 10px 12px; }

  /* ---- Dashboard: paneles y filas a 1 columna, cabecera compacta ---- */
  .db-header { padding: 10px 12px; }
  .db-header-titulos h1 { font-size: 14px; }
  #tabDashboard .db-fila-paneles, #tabDashboard .db-fila-3paneles { grid-template-columns: 1fr; margin-left: 12px; margin-right: 12px; }
  #tabDashboard .dash-seccion { margin-left: 12px; margin-right: 12px; }

  /* ---- Tablas prioritarias del Dashboard (Top Críticos / No Monitoreados): tarjeta por fila.
     Requiere data-label en cada <td> (ver cargarDashboard() en app.js) -- Riesgo Operacional y el
     Ranking multi-semana (información complementaria) se quedan con el scroll horizontal genérico. ---- */
  .tabla-criticos, .tabla-no-monitoreados { table-layout: auto; }
  .tabla-criticos thead, .tabla-no-monitoreados thead { display: none; }
  .tabla-criticos tbody tr, .tabla-no-monitoreados tbody tr {
    display: block; margin: 0 0 10px; border: 1px solid var(--border); border-radius: 8px;
    padding: 6px 10px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
  }
  .tabla-criticos tbody tr.fila-critico, .tabla-criticos tbody tr.fila-precaucion { border-left-width: 4px; }
  .tabla-criticos tbody tr.fila-critico td, .tabla-criticos tbody tr.fila-precaucion td { border-left: none; }
  .tabla-criticos td, .tabla-no-monitoreados td {
    display: flex; gap: 10px; justify-content: space-between; align-items: flex-start;
    padding: 4px 0; border-bottom: none; white-space: normal;
  }
  .tabla-criticos td:nth-child(1), .tabla-criticos td:nth-child(4),
  .tabla-no-monitoreados td:nth-child(1) { white-space: normal; }
  .tabla-criticos td::before, .tabla-no-monitoreados td::before {
    content: attr(data-label); font-weight: 700; color: var(--text-secondary); font-size: 10.5px;
    text-transform: uppercase; letter-spacing: .02em; flex: 0 0 42%;
  }
  /* Ronda "REDISEÑO EJECUTIVO": la celda 1 ahora lleva TAG + Componente (dos líneas). El layout de
     tarjeta de arriba (label 42% a la izquierda, valor a la derecha, todo en una fila) sirve para un
     valor de una sola línea -- con dos líneas apiladas se ve mejor como encabezado de tarjeta: label
     arriba, TAG y Componente abajo en columna, en vez de forzar las dos líneas al lado del label. */
  .tabla-criticos td:nth-child(1) { flex-direction: column; align-items: flex-start; gap: 2px; }
  .tabla-criticos td:nth-child(1) .td-componente-sub { white-space: normal; overflow: visible; text-overflow: clip; }

  /* ---- Modales a pantalla casi completa ---- */
  .modal-bg { padding: 0; align-items: stretch; }
  .modal { max-width: 100vw; width: 100vw; min-height: 100vh; border-radius: 0; }
  .modal .cerrar { padding: 10px; font-size: 24px; }
}

/* ==================== RONDA "RESPONSIVE R2" (Programa Semanal + Registro de Condición +
   Generador de Reportes, celular y tablet). Misma regla no negociable que R1: nada fuera de un
   @media <=1199px, y las clases nuevas (.col-movil-*, .titulo-modulo, .btn-ot, etc.) llevan un valor
   por defecto NEUTRO aquí, sin media query, para que desktop/tablet no cambien un píxel salvo que un
   bloque de abajo los pise explícitamente. ==================== */

/* El botón "Generar Reporte" del listado de Generador de Reportes perdía su estilo en línea al
   agregarle una clase para poder targetearlo en celular -- se reproduce aquí el valor exacto que
   tenía antes (padding:4px 8px;font-size:11px), así que escritorio/tablet quedan pixel-iguales. */
.btn-generar-reporte-listado { padding: 4px 8px; font-size: 11px; }

/* Celdas exclusivas de la tarjeta móvil de Registro de Condición (Técnica, Ver detalle): no existen
   como columna visible en la tabla real de escritorio/tablet -- se agregan al final de cada fila
   (ver cargarVistaConsolidada() en app.js) y quedan ocultas salvo que el @media de celular las
   reactive explícitamente. */
table.consolidada .col-movil-tecnica, table.consolidada .col-movil-verdetalle { display: none; }

/* ---- TABLET (768-1199px) ---- */
@media (min-width: 768px) and (max-width: 1199px) {
  /* Generador de Reportes: 2 columnas de técnicas (el auto-fill nativo daría 4-5 en este ancho). */
  .gr-grid { grid-template-columns: repeat(2, 1fr); }
}

/* Generador de Reportes (listado): "tabla normal en horizontal, compacta en vertical" -- el bloque
   histórico "@media (max-width:1024px)" la fuerza a display:block (pensado para el celular de
   entonces); acá se revierte a tabla real en todo el rango tablet, con overflow-x contenido en
   <main> como red de seguridad (.tab-panel tiene overflow-x:hidden, así que sin esto cualquier
   desborde quedaría recortado e ilegible en vez de scrolleable).
   Registro de Condición (table.consolidada) NO usa esta técnica -- ver el bloque de grilla con
   columnas por prioridad más abajo (ronda "CORRECCIÓN RESPONSIVE — ENCABEZADOS"): con 16 columnas
   reales, aunque sea con scroll, los encabezados largos ("ANALISTA MMG", "MODO DE FALLA") se
   superponen/aprietan de forma ilegible -- hay que ocultar columnas de verdad, no solo compactarlas. */
@media (min-width: 768px) and (max-width: 1199px) {
  .tabla-generador-listado { display: table; table-layout: auto; }
  .tabla-generador-listado thead { display: table-header-group; }
  .tabla-generador-listado tbody tr { display: table-row; }
  .tabla-generador-listado td, .tabla-generador-listado th { display: table-cell; }
  #tabGeneradorReportes main, #tabRegistroCondicion main { overflow-x: auto; }
  /* Badges (Estado/Condición) de Registro de Condición: columnas angostas + texto de badge normal
     partían la píldora en 2-3 líneas ilegibles -- nunca deben envolver, solo achicarse un poco. */
  table.consolidada .badge { white-space: nowrap; font-size: 10px; padding: 2px 6px; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .tabla-generador-listado th, .tabla-generador-listado td { font-size: 11.5px; padding: 4px 6px; }
}

/* ==================== Registro de Condición en TABLET (ronda "CORRECCIÓN RESPONSIVE —
   ENCABEZADOS"): sigue siendo una tabla real (nunca tarjetas, eso es solo celular), pero mostrando
   ÚNICAMENTE las columnas prioritarias -- las 16 columnas completas de escritorio, aunque sea con
   scroll, hacen que encabezados largos se aprieten/superpongan (defecto real reportado). Las columnas
   secundarias siguen existiendo en el DOM (mismos <td>/<th> que ya usa escritorio, mismos datos, cero
   endpoints nuevos) -- solo quedan display:none y accesibles vía "Ver detalle" (el clic de la fila,
   igual que en escritorio).
   Técnica de "tabla-grilla" -- ¡OJO! cada <tr> es SU PROPIO grid independiente (grid-template-columns
   repetido en header y en cada fila del cuerpo), NUNCA un solo grid gigante para toda la tabla: si
   "order" se aplicara sobre un único grid que contiene las 102 filas, la especificación de CSS Grid
   reordena de forma GLOBAL (todos los TAG de las 102 filas primero, después todas las Descripción...)
   -- bug real que se vio en pruebas, la tabla salía irreconocible. Con cada fila como su propio grid,
   "order" solo reordena DENTRO de esa fila, igual que ya funciona en las tarjetas de celular (ahí cada
   <tr> es su propio flex). thead/tbody se dejan como bloques simples; table.consolidada NO es grid en
   sí misma, solo estructura visual -- así escritorio (display:table normal, intacto) es inmune. */
@media (min-width: 768px) and (max-width: 1023px) {
  /* Vertical: TAG | DESCRIPCIÓN | TÉCNICA | ESTADO | CONDICIÓN | FECHA | ACCIÓN. Mínimos ajustados
     para que sumen (con los gaps) menos que el ancho útil típico a 768px con el rail contraído
     (~660px) -- así en la práctica NO hace falta el scroll de <main>, que queda solo como red de
     seguridad genuina (ver bloque de arriba) si el contenido de alguna celda lo empuja igual.
     overflow-x:visible es OBLIGATORIO acá: el bloque histórico "table{overflow-x:auto}" (arriba en
     este archivo) hace que la tabla absorba su propio desborde -- <main> nunca lo ve, así que su
     overflow-x:auto (la red de seguridad real) nunca se activa donde el usuario lo espera; bug real
     detectado en pruebas con Seguimiento (el botón "Gestionar" quedaba invisible sin ningún scroll
     alcanzable). */
  table.consolidada { display: block; table-layout: auto; border: 1px solid var(--border); border-radius: 8px; overflow: visible; /* shorthand a propósito, no overflow-x solo: si overflow-y queda "hidden" (de
    la regla base .table{overflow:hidden} para las esquinas redondeadas), la spec de CSS fuerza el
    valor usado de "visible" en el otro eje a volver "auto" -- bug real, no teórico, que se vio en
    pruebas: overflow-x:visible solo NUNCA tomaba efecto mientras overflow-y siguiera hidden. */ }
  table.consolidada thead, table.consolidada tbody { display: block; }
  table.consolidada tr {
    display: grid; width: max-content; min-width: 100%;
    grid-template-columns: minmax(95px,1fr) minmax(112px,1.8fr) minmax(72px,.9fr) minmax(80px,.8fr) minmax(80px,.8fr) minmax(74px,.7fr) minmax(90px,1fr);
    column-gap: 6px;
  }
  table.consolidada th, table.consolidada td {
    display: flex; align-items: flex-start; padding: 8px 5px; font-size: 12px; line-height: 1.3;
    white-space: normal; overflow-wrap: anywhere; border-bottom: 1px solid var(--border);
    max-height: none; height: auto; text-align: left;
  }
  table.consolidada th {
    align-items: flex-start; font-weight: 700; text-transform: uppercase; font-size: 10.5px;
    background: var(--panel-header-bg); border-bottom: 2px solid var(--border); white-space: normal;
  }
  table.consolidada td::after { display: none; } /* degradado de recorte de escritorio, no aplica acá */
  /* La regla de escritorio "td:nth-child(6/7), td.col-inspector:not(.col-corta) { max-height:4.2em;
     overflow:hidden }" es MÁS específica que el reset genérico de arriba -- sin repetirla acá con el
     mismo selector, Diagnóstico/Descripción quedaban cortados a 3 líneas con el resto del texto
     invisible (bug real detectado en pruebas: la fila se veía más baja de lo que su contenido real
     necesitaba). */
  table.consolidada td:nth-child(6), table.consolidada td:nth-child(7),
  table.consolidada td.col-inspector:not(.col-corta) { max-height: none; overflow: visible; }
  /* Ocultas (disponibles en "Ver detalle"): Orden, Semana, Ruta, OT, Modo de Falla, Reporte,
     Analista SGS, Analista MMG. Diagnóstico/Recomendación ya NO existen como <td> en esta tabla
     (ronda "SIMPLIFICACIÓN REGISTRO DE CONDICIÓN") -- nada que ocultar acá, la numeración de las
     columnas que quedan después ya corrió 2 lugares hacia atrás. */
  table.consolidada th:nth-child(1), table.consolidada td:nth-child(1),
  table.consolidada th:nth-child(2), table.consolidada td:nth-child(2),
  table.consolidada th:nth-child(7), table.consolidada td:nth-child(7),
  table.consolidada th:nth-child(8), table.consolidada td:nth-child(8),
  table.consolidada th:nth-child(9), table.consolidada td:nth-child(9),
  table.consolidada th:nth-child(11), table.consolidada td:nth-child(11),
  table.consolidada th:nth-child(12), table.consolidada td:nth-child(12),
  table.consolidada th:nth-child(13), table.consolidada td:nth-child(13),
  table.consolidada .col-movil-verdetalle { display: none; }
  table.consolidada .col-movil-tecnica { display: flex; }
  /* Orden visual (independiente del orden real del <tr>, intacto para escritorio). */
  table.consolidada th:nth-child(5), table.consolidada td:nth-child(5) { order: 1; } /* TAG */
  table.consolidada th:nth-child(6), table.consolidada td:nth-child(6) { order: 2; } /* Descripción */
  table.consolidada .col-movil-tecnica { order: 3; } /* Técnica */
  table.consolidada th:nth-child(4), table.consolidada td:nth-child(4) { order: 4; } /* Estado */
  table.consolidada th:nth-child(10), table.consolidada td:nth-child(10) { order: 5; } /* Condición */
  table.consolidada th:nth-child(3), table.consolidada td:nth-child(3) { order: 6; } /* Fecha */
  table.consolidada th:nth-child(14), table.consolidada td:nth-child(14) { order: 7; } /* Acción */
}
@media (min-width: 1024px) and (max-width: 1199px) {
  /* Horizontal: TAG | DESCRIPCIÓN | RUTA | OT | ESTADO | CONDICIÓN | ACCIÓN (7 columnas -- ronda
     "SIMPLIFICACIÓN REGISTRO DE CONDICIÓN": Diagnóstico ya no existe como <td> en esta tabla en
     NINGÚN breakpoint, tampoco acá; el espacio que ocupaba se reparte entre Descripción y Ruta).
     Mismo criterio de "cada <tr> es su propio grid" que en el bloque vertical de arriba -- ver esa
     nota. Mínimos ajustados para que quepan (con gaps) en el ancho útil a 1024px (~900px).
     overflow-x:visible obligatorio -- ver la nota extensa en el bloque vertical de arriba. */
  table.consolidada { display: block; table-layout: auto; border: 1px solid var(--border); border-radius: 8px; overflow: visible; /* shorthand a propósito, no overflow-x solo: si overflow-y queda "hidden" (de
    la regla base .table{overflow:hidden} para las esquinas redondeadas), la spec de CSS fuerza el
    valor usado de "visible" en el otro eje a volver "auto" -- bug real, no teórico, que se vio en
    pruebas: overflow-x:visible solo NUNCA tomaba efecto mientras overflow-y siguiera hidden. */ }
  table.consolidada thead, table.consolidada tbody { display: block; }
  table.consolidada tr {
    display: grid; width: max-content; min-width: 100%;
    grid-template-columns: minmax(100px,1fr) minmax(160px,2.4fr) minmax(120px,1.6fr) minmax(80px,.7fr) minmax(90px,.9fr) minmax(90px,.9fr) minmax(110px,1.1fr);
    column-gap: 8px;
  }
  table.consolidada th, table.consolidada td {
    display: flex; align-items: flex-start; padding: 7px 6px; font-size: 12.5px; line-height: 1.35;
    white-space: normal; overflow-wrap: anywhere; border-bottom: 1px solid var(--border);
    max-height: none; height: auto; text-align: left;
  }
  table.consolidada th {
    align-items: flex-start; font-weight: 700; text-transform: uppercase; font-size: 11px;
    background: var(--panel-header-bg); border-bottom: 2px solid var(--border); white-space: normal;
  }
  table.consolidada td::after { display: none; }
  /* La regla de escritorio para Descripción/Ruta (td:nth-child(6/7), .col-inspector:not(.col-corta))
     es más específica que el reset genérico -- se repite acá para que el texto se vea completo. */
  table.consolidada td:nth-child(6), table.consolidada td:nth-child(7),
  table.consolidada td.col-inspector:not(.col-corta) { max-height: none; overflow: visible; }
  /* Ocultas (disponibles en "Ver detalle"): Orden, Semana, Fecha, Modo de Falla, Reporte,
     Analista SGS, Analista MMG. */
  table.consolidada th:nth-child(1), table.consolidada td:nth-child(1),
  table.consolidada th:nth-child(2), table.consolidada td:nth-child(2),
  table.consolidada th:nth-child(3), table.consolidada td:nth-child(3),
  table.consolidada th:nth-child(9), table.consolidada td:nth-child(9),
  table.consolidada th:nth-child(11), table.consolidada td:nth-child(11),
  table.consolidada th:nth-child(12), table.consolidada td:nth-child(12),
  table.consolidada th:nth-child(13), table.consolidada td:nth-child(13),
  table.consolidada .col-movil-tecnica, table.consolidada .col-movil-verdetalle { display: none; }
  table.consolidada th:nth-child(5), table.consolidada td:nth-child(5) { order: 1; } /* TAG */
  table.consolidada th:nth-child(6), table.consolidada td:nth-child(6) { order: 2; } /* Descripción */
  table.consolidada th:nth-child(7), table.consolidada td:nth-child(7) { order: 3; } /* Ruta */
  table.consolidada th:nth-child(8), table.consolidada td:nth-child(8) { order: 4; } /* OT */
  table.consolidada th:nth-child(4), table.consolidada td:nth-child(4) { order: 5; } /* Estado */
  table.consolidada th:nth-child(10), table.consolidada td:nth-child(10) { order: 6; } /* Condición */
  table.consolidada th:nth-child(14), table.consolidada td:nth-child(14) { order: 7; } /* Acción */
}

/* ---- CELULAR (<768px) ---- */
@media (max-width: 767px) {
  /* Títulos de módulo sin font-size propio (ej. "GENERADOR DE REPORTES") heredaban el h2 gigante del
     navegador -- en desktop entra en una línea y no se nota, en celular se parte en 3 líneas enormes.
     Mismo tamaño/tratamiento que ya usan Programa Semanal y Registro de Condición. */
  .titulo-modulo { font-size: 15px; color: var(--sap-blue-dark); text-transform: uppercase; letter-spacing: .02em; }

  /* ==================== Programa Semanal: 1 columna, días apilados Lunes -> Domingo (nunca la
     grilla de 2/4 columnas heredada de reglas viejas, pensadas para "reducir" no para adaptar). Las
     tarjetas .bloque-ruta siguen siendo las mismas, mismo clic -> mismo modal de detalle por TAG. ==================== */
  .semana-grid { grid-template-columns: 1fr; gap: 12px; padding: 0 12px 24px; }
  .semana-dia { min-height: 0; }
  /* Ronda "CONTINUACIÓN — Programa Semanal celular": encabezado de día más prominente (antes 11px
     gris apenas distinguible de las tarjetas de abajo) -- ahora con más peso, tinte de marca y borde
     inferior de color, así el usuario nunca pierde de vista qué día está mirando al scrollear una
     jornada larga. */
  .semana-dia .dia-cabecera {
    font-size: 14px; padding: 10px 14px; background: var(--sap-blue-lighter);
    border-bottom: 2px solid var(--sap-blue); position: sticky; top: 0; z-index: 1;
  }
  .semana-dia .dia-cabecera .fecha { font-size: 12px; font-weight: 600; }
  /* Tarjeta de Ruta: más aire y jerarquía tipográfica clara (nombre de ruta primero y más grande,
     técnica/estado como badges bien visibles, metadatos secundarios discretos) -- mismos campos que
     ya se aprobaron, sin agregar ni quitar información. */
  .bloque-ruta { padding: 12px 14px; }
  .bloque-ruta .b-ruta { font-size: 14.5px; margin-bottom: 5px; }
  .bloque-ruta .b-tecnica { margin-bottom: 6px; }
  .bloque-ruta .b-tecnica .badge-tecnica { font-size: 11px; padding: 3px 10px; }
  .bloque-ruta .b-meta { font-size: 11.5px; }
  .bloque-ruta .b-estado { margin-top: 8px; }
  .bloque-ruta .b-estado .badge { font-size: 11px; padding: 3px 10px; }
  /* "Editar OT"/"Asignar OT": botón con estilo en línea (padding:2px 8px;font-size:11px) pensado para
     mouse -- !important es la única forma de pisar un style="" inline sin tocar la plantilla de
     app.js por completo; se reordena la fila para que el botón quede debajo del texto OT, con área
     táctil real (line 1). */
  .b-ot { flex-direction: column; align-items: flex-start !important; gap: 6px; }
  .btn-ot {
    padding: 9px 16px !important; font-size: 13px !important; margin-left: 0 !important;
    min-height: 40px; width: 100%;
  }

  /* ==================== Registro de Condición: tarjeta por inspección (TAG, Descripción, Condición,
     Técnica, Fecha, Diagnóstico, Recomendación, Ver detalle, Generar Reporte) -- mismos datos que la
     tabla de escritorio, Orden/Semana/Ruta/OT/Modo de Falla/Reporte/Analistas quedan a un toque de
     distancia en "Ver detalle" (mismo modal que ya abre el clic de la fila en escritorio). ==================== */
  table.consolidada { table-layout: auto; }
  table.consolidada thead { display: none; }
  /* RONDA "CORRECCIÓN FINAL — HOVER DE ESCRITORIO EN CELULAR": faltaba este display:block en tbody
     (el bloque de tablet, más arriba, sí lo tiene). Sin él, <tbody> queda con su display interno de
     tabla por defecto (table-row-group) mientras <table> pasa a block (por la regla histórica
     "table{display:block}" de @media max-width:1024px) -- la combinación deja que cada <tr> (ya
     display:flex) se angoste al ancho de su contenido en vez de ocupar el 100% del contenedor,
     incluso sin ningún :hover de por medio. Defecto real, confirmado con medición de anchos. */
  table.consolidada tbody { display: block; }
  table.consolidada tbody tr {
    display: flex; flex-direction: column; margin: 0 0 12px; padding: 10px 12px 12px;
    border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
    background: var(--surface);
  }
  table.consolidada tbody tr.fila-nueva-ruta td { border-top: none; }
  table.consolidada td {
    display: block; padding: 4px 0; border-bottom: none; white-space: normal;
    text-align: left; vertical-align: top;
  }
  table.consolidada td:nth-child(5) { white-space: normal; overflow: visible; text-overflow: clip; }
  table.consolidada td:nth-child(6), table.consolidada td:nth-child(7),
  table.consolidada td.col-inspector:not(.col-corta) { max-height: none; overflow: visible; }
  table.consolidada td:nth-child(6)::after, table.consolidada td:nth-child(7)::after,
  table.consolidada td.col-inspector:not(.col-corta)::after { display: none; }
  table.consolidada td::before {
    content: attr(data-label); display: block; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em; color: var(--text-secondary); margin-bottom: 2px;
  }
  /* Columnas que NO van en la tarjeta (siguen accesibles en "Ver detalle"): Orden, Semana, OT,
     Modo de Falla, Reporte, Analista SGS, Analista MMG. Diagnóstico/Recomendación ya NO existen como
     <td> en esta tabla (ronda "SIMPLIFICACIÓN REGISTRO DE CONDICIÓN") -- nunca vuelven a aparecer en
     la tarjeta, ni siquiera para inspecciones ejecutadas; quedan accesibles solo en "Ver detalle". */
  table.consolidada td:nth-child(1), table.consolidada td:nth-child(2),
  table.consolidada td:nth-child(8),
  table.consolidada td:nth-child(9), table.consolidada td:nth-child(11),
  table.consolidada td:nth-child(12), table.consolidada td:nth-child(13) { display: none; }
  table.consolidada .col-movil-tecnica, table.consolidada .col-movil-verdetalle { display: block; }
  /* Cabecera de tarjeta (TAG + Condición + Estado), luego info principal (Descripción, Técnica,
     Ruta, Fecha), luego Acciones -- independiente del orden real de columnas de escritorio, que no
     se toca. */
  table.consolidada td:nth-child(5) { order: 1; } /* TAG */
  table.consolidada td:nth-child(10) { order: 2; } /* Condición */
  table.consolidada td:nth-child(4) { order: 3; font-size: 13px; } /* Estado */
  table.consolidada td:nth-child(6) { order: 4; margin-top: 4px; } /* Descripción */
  table.consolidada .col-movil-tecnica { order: 5; } /* Técnica */
  table.consolidada td:nth-child(7) { order: 6; } /* Ruta */
  table.consolidada td:nth-child(3) { order: 7; color: var(--text-secondary); font-size: 12px; } /* Fecha */
  table.consolidada .col-movil-verdetalle { order: 8; margin-top: 6px; }
  table.consolidada td:nth-child(14) { order: 9; }
  table.consolidada .col-movil-verdetalle button, table.consolidada td:nth-child(14) button {
    width: 100%; min-height: 42px; font-size: 13.5px;
  }

  /* ==================== Generador de Reportes ==================== */
  .gr-grid { grid-template-columns: 1fr; }
  .gr-card-body .gr-n { font-size: 24px; }

  /* Listado por técnica: misma técnica de tarjeta que Registro de Condición, pero SIN ocultar
     ninguna columna (esta tabla no tiene un modal de detalle al que mandar datos secundarios, así
     que "mismos datos" acá significa que todo sigue visible, solo reordenado por prioridad). */
  .tabla-generador-listado thead { display: none; }
  .tabla-generador-listado tbody tr {
    display: flex; flex-direction: column; margin: 0 0 12px; padding: 10px 12px 12px;
    border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
    background: var(--surface);
  }
  .tabla-generador-listado td {
    display: block; padding: 4px 0; border-bottom: none; white-space: normal; text-align: left;
  }
  .tabla-generador-listado td::before {
    content: attr(data-label); display: block; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em; color: var(--text-secondary); margin-bottom: 2px;
  }
  .tabla-generador-listado td:nth-child(2) { order: 1; } /* TAG */
  .tabla-generador-listado td:nth-child(3) { order: 2; } /* Descripción */
  .tabla-generador-listado td:nth-child(6) { order: 3; } /* Condición */
  .tabla-generador-listado td:nth-child(1) { order: 4; color: var(--text-secondary); font-size: 12px; } /* Fecha */
  .tabla-generador-listado td:nth-child(7) { order: 5; } /* Diagnóstico */
  .tabla-generador-listado td:nth-child(8) { order: 6; } /* Recomendación */
  .tabla-generador-listado td:nth-child(4) { order: 7; } /* Área */
  .tabla-generador-listado td:nth-child(5) { order: 8; } /* Ruta */
  .tabla-generador-listado td:nth-child(9) { order: 9; } /* Analista */
  .tabla-generador-listado td:nth-child(10) { order: 10; } /* Reporte */
  .tabla-generador-listado td:nth-child(11) { order: 11; margin-top: 4px; } /* Acción */
  .btn-generar-reporte-listado { width: 100%; min-height: 44px; font-size: 14px; padding: 10px; }

  /* Preparar Reporte: evidencias apiladas a ancho completo (los campos con min-width:160px del
     toolbar chocaban entre sí en 390px) -- el resto del modal ya hereda el tratamiento genérico de
     R1 (modal 100vw/100vh, form-inline a 1 columna, botones >=44px de .form-actions/.filtros). Estos
     3 botones NO están dentro de esas clases así que quedaban en ~21px de alto (defecto real
     detectado probando el modal con varios puntos/evidencias reales): "Quitar" (por punto/componente/
     hallazgo), "+ Punto/Componente/Hallazgo" y "+ Adjuntar imagen". */
  .prep-item-header button, .prep-agregar, .prep-evidencias-toolbar button {
    min-height: 44px; padding: 0 16px; font-size: 13px;
  }
  .prep-agregar { width: 100%; }
  .prep-evidencias-toolbar > * { width: 100%; }
  .ev-grid { grid-template-columns: 1fr; }
  /* Cada tarjeta de evidencia: botones de acción (↑ ↓ Ampliar Eliminar) también táctiles -- antes
     compartían una fila apretada de 4 botones angostos. */
  .ev-card-actions { flex-wrap: wrap; }
  .ev-card-actions button { min-height: 40px; flex: 1 1 40%; font-size: 12px; }

  /* Vista Previa: el escalado real lo hace ajustarEscalaVistaPrevia() (transform:scale, ver app.js)
     -- acá solo se reduce el padding lateral del visor para dejarle más ancho útil a la hoja. */
  .vp-scroll { padding: 14px 8px; margin: 0 -8px; }
}

/* ==================== RONDA "AUDITORÍA RESPONSIVE POR MÓDULO" (Seguimiento, Equipo 360/Historial y
   Confiabilidad, Reportes). Misma regla no negociable de siempre: nada fuera de un @media <=1199px.
   Cada módulo tiene una función distinta y por eso una estrategia distinta -- ver la auditoría
   previa a este código:
     - Seguimiento: la fila YA abre "Gestionar" (abrirGestionCaso, sin cambios de esta ronda) y ese
       modal YA mostraba Diagnóstico/Recomendación completos desde una ronda anterior -- acá solo se
       prioriza qué columnas se ven directo vs. cuáles quedan a un clic, igual que Registro de
       Condición.
     - Equipo 360/Historial: pantalla ANALÍTICA sin detalle alternativo completo (su modal de
       histórico no trae Recomendación/Modo de Falla/Analista) -- NINGUNA columna se oculta en ningún
       breakpoint, solo se reordena (celular) o se compacta con scroll contenido (tablet).
     - Reportes: 8 tipos con columnas distintas generadas por JS -- técnica 100% genérica por
       data-label, sin nth-child (una regla posicional rota en un tipo de reporte rompería otro). ==== */

/* ---- TABLET (768-1199px): Equipo 360 y Reportes -- tabla real, compacta, SIN ocultar columnas.
   overflow-x contenido en <main> (.tab-panel tiene overflow-x:hidden) como red de seguridad genuina,
   no decorativa: con 11-14 columnas completas es esperable necesitar scroll en algún tipo de reporte
   angosto, y la regla es justamente "nunca ocultar" acá. ---- */
@media (min-width: 768px) and (max-width: 1199px) {
  /* overflow:visible (shorthand, ambos ejes) obligatorio -- la regla base ".table{overflow:hidden}"
     + la vieja "table{overflow-x:auto}" hacían que ESTA tabla absorbiera su propio desborde en vez
     de dejarlo llegar a <main> (mismo bug real ya documentado en Registro de Condición/Seguimiento
     más arriba: overflow-x:visible solo nunca alcanza si el otro eje no es también visible). */
  table.tabla-eq360, table.tabla-reportes { display: table; table-layout: auto; overflow: visible; }
  table.tabla-eq360 thead, table.tabla-reportes thead { display: table-header-group; }
  table.tabla-eq360 tbody tr, table.tabla-reportes tbody tr { display: table-row; }
  table.tabla-eq360 td, table.tabla-eq360 th,
  table.tabla-reportes td, table.tabla-reportes th { display: table-cell; }
  #tabEquipos360 main, #tabReportes main, #tabSeguimiento main { overflow-x: auto; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  table.tabla-eq360 th, table.tabla-eq360 td,
  table.tabla-reportes th, table.tabla-reportes td { font-size: 11.5px; padding: 5px 7px; }
}
/* Badges (Condición) en columnas angostas: mismo defecto real ya corregido en Registro de Condición
   (el texto de la píldora partía en 2-3 líneas ilegibles) -- se previene acá de entrada para
   Seguimiento y Equipo 360/Reportes, que también muestran badges de Condición en tablet. */
@media (min-width: 768px) and (max-width: 1199px) {
  table.tabla-seguimiento .badge, table.tabla-eq360 .badge, table.tabla-reportes .badge {
    white-space: nowrap; font-size: 10px; padding: 2px 6px;
  }
}

/* ---- Seguimiento en TABLET: mismo criterio que Registro de Condición -- columnas priorizadas,
   cada <tr> es SU PROPIO grid (nunca un solo grid para toda la tabla, "order" reordena de forma
   global si se comparte -- ver la nota extensa en el bloque de Registro de Condición más arriba).
   Columnas reales (14): 1 Condición, 2 TAG, 3 Equipo, 4 Área, 5 Tecnología, 6 Ruta, 7 Componente/
   Punto, 8 Primera detección, 9 Última inspección, 10 Modo de Falla, 11 Analista, 12 Días abierto,
   13 Estado, 14 Gestionar. El resto (Área/Tecnología/fechas/Modo de Falla/Analista) sigue accesible
   con un clic en la fila -- "Gestionar" ya lo mostraba todo desde antes de esta ronda. ---- */
@media (min-width: 768px) and (max-width: 1023px) {
  /* Vertical: Condición | TAG | Equipo | Ruta | Estado | Días abierto | Gestionar */
  table.tabla-seguimiento {
    display: block; table-layout: auto; border: 1px solid var(--border); border-radius: 8px;
    overflow: visible; /* shorthand a propósito, no overflow-x solo: si overflow-y queda "hidden" (de
    la regla base .table{overflow:hidden} para las esquinas redondeadas), la spec de CSS fuerza el
    valor usado de "visible" en el otro eje a volver "auto" -- bug real, no teórico, que se vio en
    pruebas: overflow-x:visible solo NUNCA tomaba efecto mientras overflow-y siguiera hidden. */
  }
  table.tabla-seguimiento thead, table.tabla-seguimiento tbody { display: block; }
  table.tabla-seguimiento tr {
    display: grid; width: max-content; min-width: 100%;
    /* Máximos en px definidos (nunca "fr") -- mismo defecto real encontrado y corregido en la
       ronda "AUDITORÍA VISUAL GLOBAL FINAL" (ver esa nota extensa, tablas de Base Maestra más
       abajo): con width:max-content por fila, un "fr" en un contenedor de tamaño intrínseco se
       resuelve como el max-content del contenido, así que una fila con un TAG/Equipo más largo que
       las demás estiraba SU fila más que las otras -- desalineaba las columnas entre filas. Con un
       tope en px el texto largo envuelve en vez de ensanchar la columna, y todas las filas quedan
       con exactamente el mismo ancho de columna. */
    grid-template-columns: minmax(85px,110px) minmax(95px,130px) minmax(150px,230px) minmax(130px,190px) minmax(90px,110px) minmax(75px,90px) minmax(95px,120px);
    column-gap: 8px;
  }
  table.tabla-seguimiento th, table.tabla-seguimiento td {
    display: flex; align-items: flex-start; padding: 8px 6px; font-size: 12px; line-height: 1.3;
    white-space: normal; overflow-wrap: anywhere; border-bottom: 1px solid var(--border);
    max-height: none; height: auto; text-align: left;
  }
  table.tabla-seguimiento th {
    align-items: flex-start; font-weight: 700; text-transform: uppercase; font-size: 10.5px;
    background: var(--panel-header-bg); border-bottom: 2px solid var(--border); white-space: normal;
    overflow-wrap: break-word;
  }
  table.tabla-seguimiento th:nth-child(4), table.tabla-seguimiento td:nth-child(4),
  table.tabla-seguimiento th:nth-child(5), table.tabla-seguimiento td:nth-child(5),
  table.tabla-seguimiento th:nth-child(7), table.tabla-seguimiento td:nth-child(7),
  table.tabla-seguimiento th:nth-child(8), table.tabla-seguimiento td:nth-child(8),
  table.tabla-seguimiento th:nth-child(9), table.tabla-seguimiento td:nth-child(9),
  table.tabla-seguimiento th:nth-child(10), table.tabla-seguimiento td:nth-child(10),
  table.tabla-seguimiento th:nth-child(11), table.tabla-seguimiento td:nth-child(11) { display: none; }
  table.tabla-seguimiento th:nth-child(1), table.tabla-seguimiento td:nth-child(1) { order: 1; } /* Condición */
  table.tabla-seguimiento th:nth-child(2), table.tabla-seguimiento td:nth-child(2) { order: 2; } /* TAG */
  table.tabla-seguimiento th:nth-child(3), table.tabla-seguimiento td:nth-child(3) { order: 3; } /* Equipo */
  table.tabla-seguimiento th:nth-child(6), table.tabla-seguimiento td:nth-child(6) { order: 4; } /* Ruta */
  table.tabla-seguimiento th:nth-child(13), table.tabla-seguimiento td:nth-child(13) { order: 5; } /* Estado */
  table.tabla-seguimiento th:nth-child(12), table.tabla-seguimiento td:nth-child(12) { order: 6; } /* Días abierto */
  table.tabla-seguimiento th:nth-child(14), table.tabla-seguimiento td:nth-child(14) { order: 7; } /* Gestionar */
}
@media (min-width: 1024px) and (max-width: 1199px) {
  /* Horizontal: Condición | TAG | Equipo | Ruta | Última inspección | Estado | Días abierto | Gestionar */
  table.tabla-seguimiento {
    display: block; table-layout: auto; border: 1px solid var(--border); border-radius: 8px;
    overflow: visible; /* shorthand a propósito, no overflow-x solo: si overflow-y queda "hidden" (de
    la regla base .table{overflow:hidden} para las esquinas redondeadas), la spec de CSS fuerza el
    valor usado de "visible" en el otro eje a volver "auto" -- bug real, no teórico, que se vio en
    pruebas: overflow-x:visible solo NUNCA tomaba efecto mientras overflow-y siguiera hidden. */
  }
  table.tabla-seguimiento thead, table.tabla-seguimiento tbody { display: block; }
  table.tabla-seguimiento tr {
    display: grid; width: max-content; min-width: 100%;
    /* Máximos en px definidos, mismo motivo que el bloque vertical de arriba (ver esa nota). */
    grid-template-columns: minmax(90px,115px) minmax(100px,140px) minmax(170px,250px) minmax(140px,200px) minmax(95px,115px) minmax(90px,115px) minmax(80px,100px) minmax(100px,130px);
    column-gap: 8px;
  }
  table.tabla-seguimiento th, table.tabla-seguimiento td {
    display: flex; align-items: flex-start; padding: 8px 6px; font-size: 12.5px; line-height: 1.35;
    white-space: normal; overflow-wrap: anywhere; border-bottom: 1px solid var(--border);
    max-height: none; height: auto; text-align: left;
  }
  table.tabla-seguimiento th {
    align-items: flex-start; font-weight: 700; text-transform: uppercase; font-size: 11px;
    background: var(--panel-header-bg); border-bottom: 2px solid var(--border); white-space: normal;
    overflow-wrap: break-word;
  }
  table.tabla-seguimiento th:nth-child(4), table.tabla-seguimiento td:nth-child(4),
  table.tabla-seguimiento th:nth-child(5), table.tabla-seguimiento td:nth-child(5),
  table.tabla-seguimiento th:nth-child(7), table.tabla-seguimiento td:nth-child(7),
  table.tabla-seguimiento th:nth-child(8), table.tabla-seguimiento td:nth-child(8),
  table.tabla-seguimiento th:nth-child(10), table.tabla-seguimiento td:nth-child(10),
  table.tabla-seguimiento th:nth-child(11), table.tabla-seguimiento td:nth-child(11) { display: none; }
  table.tabla-seguimiento th:nth-child(1), table.tabla-seguimiento td:nth-child(1) { order: 1; } /* Condición */
  table.tabla-seguimiento th:nth-child(2), table.tabla-seguimiento td:nth-child(2) { order: 2; } /* TAG */
  table.tabla-seguimiento th:nth-child(3), table.tabla-seguimiento td:nth-child(3) { order: 3; } /* Equipo */
  table.tabla-seguimiento th:nth-child(6), table.tabla-seguimiento td:nth-child(6) { order: 4; } /* Ruta */
  table.tabla-seguimiento th:nth-child(9), table.tabla-seguimiento td:nth-child(9) { order: 5; } /* Última inspección */
  table.tabla-seguimiento th:nth-child(13), table.tabla-seguimiento td:nth-child(13) { order: 6; } /* Estado */
  table.tabla-seguimiento th:nth-child(12), table.tabla-seguimiento td:nth-child(12) { order: 7; } /* Días abierto */
  table.tabla-seguimiento th:nth-child(14), table.tabla-seguimiento td:nth-child(14) { order: 8; } /* Gestionar */
}

/* ---- CELULAR (<768px) ---- */
@media (max-width: 767px) {
  /* ==================== Seguimiento: tarjeta por caso. Prioridad aprobada: Condición, TAG, Equipo,
     Estado, Días abierto, Ruta/Componente y Gestionar -- Área/Tecnología/fechas/Modo de Falla/
     Analista quedan a un toque ("Gestionar", que ya los mostraba todos desde antes de esta ronda). ==== */
  table.tabla-seguimiento { table-layout: auto; }
  table.tabla-seguimiento thead { display: none; }
  /* Mismo motivo y misma corrección que table.consolidada más arriba -- ver esa nota extensa. */
  table.tabla-seguimiento tbody { display: block; }
  table.tabla-seguimiento tbody tr {
    display: flex; flex-direction: column; margin: 0 0 12px; padding: 10px 12px 12px;
    border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
    background: var(--surface);
  }
  table.tabla-seguimiento td {
    display: block; padding: 4px 0; border-bottom: none; white-space: normal; text-align: left;
  }
  table.tabla-seguimiento td::before {
    content: attr(data-label); display: block; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em; color: var(--text-secondary); margin-bottom: 2px;
  }
  table.tabla-seguimiento td:nth-child(4), table.tabla-seguimiento td:nth-child(5),
  table.tabla-seguimiento td:nth-child(8), table.tabla-seguimiento td:nth-child(9),
  table.tabla-seguimiento td:nth-child(10), table.tabla-seguimiento td:nth-child(11) { display: none; }
  table.tabla-seguimiento td:nth-child(1) { order: 1; } /* Condición */
  table.tabla-seguimiento td:nth-child(2) { order: 2; } /* TAG */
  table.tabla-seguimiento td:nth-child(3) { order: 3; margin-top: 4px; } /* Equipo */
  table.tabla-seguimiento td:nth-child(13) { order: 4; font-size: 13px; } /* Estado */
  table.tabla-seguimiento td:nth-child(12) { order: 5; color: var(--text-secondary); font-size: 12px; } /* Días abierto */
  table.tabla-seguimiento td:nth-child(6) { order: 6; margin-top: 4px; } /* Ruta */
  table.tabla-seguimiento td:nth-child(7) { order: 7; } /* Componente/Punto */
  table.tabla-seguimiento td:nth-child(14) { order: 8; margin-top: 6px; } /* Gestionar */
  table.tabla-seguimiento td:nth-child(14) button { width: 100%; min-height: 42px; font-size: 13.5px; }

  /* ==================== Equipo 360/Historial: tarjeta con las 11 columnas COMPLETAS, solo
     reordenadas (nunca ocultas -- esta pantalla es analítica y su modal de histórico no las repite
     todas, ver la auditoría). TAG/Fecha/Condición arriba, Diagnóstico/Recomendación con espacio de
     sobra, el resto abajo. ==================== */
  table.tabla-eq360 { table-layout: auto; }
  table.tabla-eq360 thead { display: none; }
  table.tabla-eq360 tbody tr {
    display: flex; flex-direction: column; margin: 0 0 12px; padding: 10px 12px 12px;
    border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
    background: var(--surface);
  }
  table.tabla-eq360 td {
    display: block; padding: 4px 0; border-bottom: none; white-space: normal; text-align: left;
    overflow-wrap: anywhere;
  }
  table.tabla-eq360 td::before {
    content: attr(data-label); display: block; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em; color: var(--text-secondary); margin-bottom: 2px;
  }
  table.tabla-eq360 td:nth-child(2) { order: 1; } /* TAG */
  table.tabla-eq360 td:nth-child(1) { order: 2; color: var(--text-secondary); font-size: 12px; } /* Fecha */
  table.tabla-eq360 td:nth-child(7) { order: 3; } /* Condición */
  table.tabla-eq360 td:nth-child(8) { order: 4; margin-top: 6px; } /* Diagnóstico */
  table.tabla-eq360 td:nth-child(9) { order: 5; } /* Recomendación */
  table.tabla-eq360 td:nth-child(3) { order: 6; margin-top: 6px; } /* Equipo */
  table.tabla-eq360 td:nth-child(4) { order: 7; } /* Componente */
  table.tabla-eq360 td:nth-child(5) { order: 8; } /* Tecnología */
  table.tabla-eq360 td:nth-child(6) { order: 9; } /* Ruta */
  table.tabla-eq360 td:nth-child(10) { order: 10; } /* Modo de Falla */
  table.tabla-eq360 td:nth-child(11) { order: 11; } /* Analista */

  /* ==================== Reportes: técnica 100% genérica -- SIN nth-child, ninguna columna se
     oculta ni se reordena (los 8 tipos tienen estructuras distintas; una regla posicional que
     funcione para uno rompería otro). El orden visual de la tarjeta es simplemente el orden real de
     columnas de cada tipo de reporte, que ya sale razonable desde el backend. ==================== */
  table.tabla-reportes { table-layout: auto; }
  table.tabla-reportes thead { display: none; }
  table.tabla-reportes tbody tr {
    display: block; margin: 0 0 12px; padding: 10px 12px 12px;
    border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
    background: var(--surface);
  }
  table.tabla-reportes td {
    display: block; padding: 4px 0; border-bottom: none; white-space: normal; text-align: left;
    overflow-wrap: anywhere;
  }
  table.tabla-reportes td::before {
    content: attr(data-label); display: block; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em; color: var(--text-secondary); margin-bottom: 2px;
  }
  /* Celdas sin data-label (mensajes tipo "Sin resultados...", colspan): sin etiqueta, texto normal. */
}

/* ==================== REPORTE AUTOMÁTICO POR INSPECCIÓN -- Etapa 2 (contenido técnico
   multi-instancia, evidencias, Vista Previa). Reutiliza los tokens SAP ya definidos arriba, nunca
   colores nuevos sueltos. ==================== */
.prep-lista-items { display: flex; flex-direction: column; gap: 12px; margin-top: 10px; }
.prep-item-card { border: 1px solid var(--border); border-radius: 6px; background: var(--surface); overflow: hidden; }
.prep-item-header {
  display: flex; align-items: center; justify-content: space-between; padding: 7px 12px;
  background: var(--panel-header-bg); color: var(--panel-header-text); font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .02em;
}
.prep-item-header button { padding: 3px 10px; font-size: 11px; height: auto; }
.prep-item-body { padding: 12px; }
.prep-item-body form.form-inline { margin-top: 0; }
.prep-agregar { margin-top: 10px; }

.prep-ut-matriz-caja { margin-top: 10px; }
.prep-ut-matriz-caja label.etiqueta { font-size: 12px; color: var(--text-secondary); font-weight: 600; display: block; margin-bottom: 4px; }

/* ---- Evidencias ---- */
.prep-evidencias-toolbar { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; margin-top: 10px; padding: 12px; background: var(--surface-alt); border: 1px solid var(--border); border-radius: 6px; }
.prep-evidencias-toolbar > div { display: flex; flex-direction: column; gap: 4px; }
.prep-evidencias-toolbar label { font-size: 11px; color: var(--text-secondary); font-weight: 600; text-transform: uppercase; letter-spacing: .02em; }
.prep-evidencias-toolbar select, .prep-evidencias-toolbar input[type=text] { background: var(--surface); border: 1px solid var(--border); color: var(--text-primary); padding: 6px 8px; border-radius: 6px; font-size: 13px; font-family: inherit; }
.ev-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 12px; margin-top: 14px; }
.ev-card { border: 1px solid var(--border); border-radius: 6px; background: var(--surface); overflow: hidden; display: flex; flex-direction: column; }
.ev-thumb-wrap { position: relative; background: var(--surface-alt); }
.ev-thumb { width: 100%; height: 120px; object-fit: cover; display: block; cursor: zoom-in; }
.ev-thumb-tipo { position: absolute; top: 6px; left: 6px; background: rgba(23,54,93,.85); color: #fff; font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 999px; letter-spacing: .02em; }
.ev-card-body { padding: 8px; display: flex; flex-direction: column; gap: 6px; flex: 1; }
.ev-card-body select, .ev-card-body input { width: 100%; background: var(--surface); border: 1px solid var(--border); color: var(--text-primary); padding: 5px 7px; border-radius: 6px; font-size: 12px; font-family: inherit; }
.ev-card-actions { display: flex; gap: 4px; justify-content: space-between; padding: 0 8px 8px; }
.ev-card-actions button { flex: 1; padding: 4px 0; font-size: 11px; height: auto; }
.ev-vacio { color: var(--text-secondary); font-size: 13px; font-style: italic; padding: 14px; text-align: center; }

.ev-lightbox-bg { position: fixed; inset: 0; background: rgba(10,20,35,.88); display: none; align-items: center; justify-content: center; z-index: 20; padding: 30px; }
.ev-lightbox-bg.open { display: flex; }
.ev-lightbox-bg img { max-width: 100%; max-height: 90vh; box-shadow: 0 12px 40px rgba(0,0,0,.5); border-radius: 6px; }
.ev-lightbox-cerrar { position: fixed; top: 18px; right: 24px; background: none; border: none; color: #fff; font-size: 30px; cursor: pointer; line-height: 1; }

/* ---- Vista Previa: hoja A4 aproximada, nunca el PDF final ---- */
.vp-scroll { max-height: 78vh; overflow-y: auto; background: #6b7d90; padding: 24px; margin: 0 -24px; border-radius: 0 0 6px 6px; }
.hoja-a4 {
  width: 210mm; min-height: 297mm; max-width: 100%; margin: 0 auto; background: #fff; color: #1a1a1a;
  box-shadow: 0 8px 28px rgba(0,0,0,.35); padding: 14mm 12mm; box-sizing: border-box; font-family: "72", Arial, sans-serif;
}
.vp-marca { display: flex; align-items: center; justify-content: space-between; border-bottom: 3px solid var(--sap-blue-dark); padding-bottom: 8px; }
.vp-marca .vp-scm { font-size: 13px; font-weight: 700; letter-spacing: .06em; color: var(--sap-blue-dark); text-transform: uppercase; }
.vp-marca .vp-numero { font-size: 11px; color: #55606b; }
.vp-titulo-reporte { font-size: 19px; font-weight: 700; color: #17365D; margin: 10px 0 14px; letter-spacing: .01em; }
.vp-tabla-datos { width: 100%; border-collapse: collapse; margin-bottom: 14px; }
.vp-tabla-datos td { border: 1px solid #c9d4de; padding: 5px 9px; font-size: 11.5px; vertical-align: top; }
.vp-tabla-datos td.vp-label { background: #eef3f8; font-weight: 700; color: #3c5674; width: 130px; text-transform: uppercase; font-size: 10px; letter-spacing: .02em; }
.vp-condicion-caja { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-radius: 6px; margin-bottom: 14px; border: 1px solid; }
.vp-condicion-caja .vp-etq { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; font-weight: 700; opacity: .8; }
.vp-condicion-caja .vp-valor { font-size: 18px; font-weight: 800; letter-spacing: .02em; }
/* Ronda "VISTA PREVIA Y PDF DEBEN COINCIDIR": la caja de condición pasa del tinte suave anterior a los
   colores OFICIALES sólidos (los mismos valores hexadecimales que --db-normal/--db-tolerable/
   --db-precaucion/--db-critico, ya usados por #tabDashboard .badge.*) -- es la única excepción
   deliberada a "no modificar Vista Previa": el PDF reproduce exactamente este mismo tratamiento (ver
   rcCondicionBox), así que ambos deben partir del mismo color para representar la condición "de la
   misma manera". Se repiten como literales (no var(--db-*)) porque esas variables están
   intencionalmente escopadas a #tabDashboard (ver su propio comentario, ronda "PALETA OFICIAL DE
   CONDICIÓN") -- #modalVistaPrevia vive fuera de ese árbol y nunca las heredaría. */
.vp-condicion-caja.c-ok { background: #00B050; border-color: #00B050; color: #fff; }
.vp-condicion-caja.c-tolerable { background: #0000FF; border-color: #0000FF; color: #fff; }
.vp-condicion-caja.c-review { background: #FFFF00; border-color: #FFFF00; color: #1F2937; }
.vp-condicion-caja.c-error { background: #FF0000; border-color: #FF0000; color: #fff; }
.vp-seccion { margin-bottom: 14px; }
.vp-seccion h4 { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: #17365D; border-bottom: 1.5px solid #c9d4de; padding-bottom: 4px; margin: 0 0 8px; }
.vp-texto { font-size: 12px; line-height: 1.5; color: #262f38; white-space: pre-wrap; }
.vp-tecnico-item { border: 1px solid #d5dee6; border-radius: 6px; padding: 8px 10px; margin-bottom: 8px; }
.vp-tecnico-item .vp-tecnico-item-titulo { font-size: 11px; font-weight: 700; color: #17365D; margin-bottom: 4px; }
.vp-tecnico-item table { width: 100%; border-collapse: collapse; font-size: 11px; }
.vp-tecnico-item table td, .vp-tecnico-item table th { border: 1px solid #d5dee6; padding: 3px 6px; }
.vp-tecnico-item table th { background: #eef3f8; font-size: 9.5px; text-transform: uppercase; }
.vp-campos-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px 14px; font-size: 11.5px; margin-bottom: 6px; }
.vp-campos-grid span { color: #6b7684; font-size: 9.5px; text-transform: uppercase; display: block; }
.vp-evidencia-grupo { margin-bottom: 10px; }
.vp-evidencia-grupo-titulo { font-size: 10.5px; font-weight: 700; color: #3c5674; margin-bottom: 5px; }
.vp-evidencia-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.vp-evidencia-grid.single { grid-template-columns: 1fr; }
.vp-evidencia-card { border: 1px solid #d5dee6; border-radius: 2px; overflow: hidden; }
.vp-evidencia-card img { width: 100%; display: block; object-fit: contain; background: #eef1f4; max-height: 260px; }
.vp-evidencia-card .vp-ev-pie { padding: 5px 7px; font-size: 10px; color: #3c4650; }
.vp-evidencia-card .vp-ev-pie strong { display: block; font-size: 10.5px; color: #17365D; }
.vp-pie { margin-top: 20px; padding-top: 8px; border-top: 1px solid #c9d4de; font-size: 9.5px; color: #8b94a0; display: flex; justify-content: space-between; }

/* ---- Vista Previa dirigida por Plantilla Excel (Etapa B): la plantilla activa manda sobre el
   formato -- estas clases solo distinguen visualmente el ORIGEN de cada valor, nunca alteran la
   grilla en sí (esa la define el layout extraído del Excel, ver construirGrillaExcel en app.js). ---- */
.exc-hoja { background: #fff; }
.exc-tabla { border-collapse: collapse; width: 100%; table-layout: fixed; }
.exc-tabla td { overflow: hidden; vertical-align: middle; padding: 1px 3px; box-sizing: border-box; }
.exc-auto { color: #1a1a1a; }
.exc-manual { color: #17365D; background: #EAF1FA; border-radius: 2px; padding: 0 2px; }
.exc-calculado { color: #6B4E00; background: #FCF1DC; border-radius: 2px; padding: 0 2px; font-variant-numeric: tabular-nums; }
.exc-pendiente { color: #9B2C2C; background: #FBEAEA; border: 1px dashed #D98C8C; border-radius: 2px; padding: 0 4px; font-size: 10px; font-style: italic; }
.exc-imagen-celda { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.exc-imagen-celda img { max-width: 100%; max-height: 100%; object-fit: contain; }
.exc-leyenda { display: flex; gap: 14px; flex-wrap: wrap; font-size: 11px; padding: 8px 0; color: var(--text-secondary); }
.exc-leyenda span { display: inline-flex; align-items: center; gap: 5px; }
.exc-leyenda i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
.exc-leyenda i.a { background: #fff; border: 1px solid #ccc; }
.exc-leyenda i.m { background: #EAF1FA; border: 1px solid #17365D; }
.exc-leyenda i.c { background: #FCF1DC; border: 1px solid #6B4E00; }
.exc-leyenda i.p { background: #FBEAEA; border: 1px dashed #D98C8C; }

/* {{ESPECTROS_VIBRACION}} (Etapa C -- Vibración): a diferencia de una celda-imagen simple, esta debe
   poder crecer más allá de la altura nominal de fila del Excel ("continuar hacia abajo sin
   deformar" -- ronda "CORRECCIÓN OBLIGATORIA", punto 3), así que se excluye del overflow:hidden
   general de .exc-tabla td. */
.exc-tabla td:has(.exc-espectros-contenedor) { overflow: visible; height: auto; }
.exc-espectros-contenedor { display: flex; flex-direction: column; gap: 12px; padding: 6px 0; }
.exc-espectro-grupo { border: 1px solid #d5dee6; border-radius: 6px; padding: 8px; background: #f7f9fb; }
.exc-espectro-titulo { font-size: 11px; font-weight: 700; color: #17365D; text-transform: uppercase; letter-spacing: .02em; margin-bottom: 6px; }
.exc-espectro-galeria { display: flex; flex-wrap: wrap; gap: 10px; }
.exc-espectro-galeria img { max-width: 100%; width: 480px; max-height: 420px; object-fit: contain; background: #fff; border: 1px solid #e2e8ee; }
.exc-espectro-comentario { margin-top: 6px; font-size: 11.5px; }

/* ---- Generador de Reportes: tarjetas por técnica (landing) ---- */
.gr-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 14px; margin: 16px 24px 24px; }
.gr-card { background: var(--surface); border: 1px solid var(--border); border-radius: 6px; padding: 0; overflow: hidden; cursor: pointer; transition: box-shadow .15s, border-color .15s; text-align: left; }
.gr-card:hover { border-color: var(--sap-blue); box-shadow: 0 2px 10px rgba(10,45,90,.12); }
.gr-card.gr-sin-datos { cursor: default; opacity: .72; }
.gr-card.gr-sin-datos:hover { border-color: var(--border); box-shadow: none; }
.gr-card-header { background: var(--panel-header-bg); color: var(--panel-header-text); padding: 9px 12px; font-size: 12.5px; font-weight: 700; min-height: 34px; display: flex; align-items: center; }
.gr-card-body { padding: 12px; }
.gr-card-body .gr-n { font-size: 26px; font-weight: 700; color: var(--sap-blue-dark); font-variant-numeric: tabular-nums; }
.gr-card-body .gr-lbl { font-size: 11px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: .02em; margin-top: 2px; }
.gr-card-body .gr-vacio { font-size: 12.5px; color: var(--text-secondary); font-style: italic; }
.gr-card-body .gr-sub { font-size: 11px; color: var(--text-secondary); margin-top: 6px; }

/* ---- Vista Previa VT/UT: layouts lado a lado que replican la proporción del reporte maestro
   (Datos del equipo + foto principal; Calibración UT + matriz de espesores). Solo se usan desde
   construirVistaPreviaUt() -- las demás técnicas siguen con .vp-tabla-datos/.vp-tecnico-item tal cual. ---- */
.vp-equipo-foto-caja { display: flex; gap: 10px; align-items: stretch; margin-bottom: 14px; }
.vp-equipo-foto-caja .vp-tabla-datos { flex: 1.4; margin-bottom: 0; }
.vp-equipo-foto { flex: 1; border: 1px solid #d5dee6; border-radius: 2px; overflow: hidden; display: flex; align-items: center; justify-content: center; background: #eef1f4; min-height: 90px; }
.vp-equipo-foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
.vp-equipo-foto .vp-sin-foto { font-size: 10px; color: #8b94a0; font-style: italic; padding: 10px; text-align: center; }

.vp-ut-calibracion-matriz { display: flex; gap: 10px; align-items: flex-start; }
.vp-calibracion-tabla { flex: 0 0 34%; border-collapse: collapse; font-size: 10.5px; }
.vp-calibracion-tabla td { border: 1px solid #d5dee6; padding: 3px 6px; }
.vp-calibracion-tabla td.vp-label { background: #eef3f8; font-weight: 700; color: #3c5674; font-size: 9px; text-transform: uppercase; letter-spacing: .02em; width: 55%; }
.vp-ut-matriz-col { flex: 1; min-width: 0; }
.vp-ut-matriz-col table { width: 100%; }

/* ==================== RONDA "AUDITORÍA VISUAL GLOBAL FINAL" (Base Maestra, Administración de
   Usuarios y modales que nunca habían recibido tratamiento responsive). Misma regla no negociable
   de siempre: nada fuera de un @media <=1199px -- 1366x768/1920x1080 quedan sin tocar.
     - Base Maestra Rutas/Equipos: SÍ tienen detalle completo con un clic (abrirDetalle/
       abrirDetalleEquipo muestran todos los campos que se ocultan en tablet, ver auditoría) --
       mismo criterio que Registro de Condición/Seguimiento: tablet oculta columnas secundarias,
       celular muestra TODAS reordenadas en tarjeta (nunca se pierde nada, solo cambia de lugar).
     - Administración de Usuarios / "Rutas en las que participa" (dentro de Detalle de Equipo) /
       comparación Excel vs. BD (Sincronización, Paso 3): NINGÚN dato tiene una vista alternativa --
       acá NUNCA se oculta ninguna columna en ningún breakpoint, solo se compacta (tablet, tabla real
       con scroll contenido) o se convierte en tarjeta genérica por data-label (celular), igual
       criterio que Equipo 360/Reportes. ==================== */

/* Reemplaza el style="padding:4px 10px;font-size:12px" que antes llevaban inline los botones de
   Acciones de Usuarios (Editar/Restablecer contraseña/Desactivar-Activar) -- mismo valor exacto, así
   que desktop/tablet quedan pixel-idénticos; solo el @media de celular más abajo lo sobreescribe. */
.btn-usr-accion { padding: 4px 10px; font-size: 12px; }

/* ---- TABLET (768-1199px): compactar SIN ocultar Usuarios / Rutas-participa / comparación Excel.
   overflow:visible shorthand obligatorio (bug ya documentado: overflow-x:visible solo nunca alcanza
   si el otro eje sigue "hidden", heredado de la regla base table{overflow:hidden} para las esquinas
   redondeadas) + <main> como contenedor real del scroll. ---- */
@media (min-width: 768px) and (max-width: 1199px) {
  table.tabla-usuarios, table.tabla-rutas-participa, table.tabla-sync-comparacion {
    display: table; table-layout: auto; overflow: visible;
  }
  table.tabla-usuarios thead, table.tabla-rutas-participa thead, table.tabla-sync-comparacion thead { display: table-header-group; }
  table.tabla-usuarios tbody tr, table.tabla-rutas-participa tbody tr, table.tabla-sync-comparacion tbody tr { display: table-row; }
  table.tabla-usuarios td, table.tabla-usuarios th,
  table.tabla-rutas-participa td, table.tabla-rutas-participa th,
  table.tabla-sync-comparacion td, table.tabla-sync-comparacion th { display: table-cell; }
  #tabUsuarios main, #tabBaseMaestra main { overflow-x: auto; }
  #modalDetalleEquipo table.tabla-rutas-participa, #modalSincronizacion table.tabla-sync-comparacion {
    display: block; overflow-x: auto;
  }
  #modalDetalleEquipo table.tabla-rutas-participa tbody, #modalSincronizacion table.tabla-sync-comparacion tbody { display: table-row-group; }

  /* Red de seguridad genérica: cualquier fila de acciones de modal (.form-actions) o la barra de
     Sincronización que no quepa en el ancho disponible envuelve en vez de desbordar -- mismo defecto
     real que rompió "Desactivar Ruta" en celular, acá solo como prevención (no se vio roto en tablet
     durante la auditoría, pero el patrón de 3-4 botones se repite en varios modales). */
  .form-actions { flex-wrap: wrap; row-gap: 8px; }
  .bm-sync-bar { flex-wrap: wrap; row-gap: 8px; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  table.tabla-usuarios th, table.tabla-usuarios td,
  table.tabla-rutas-participa th, table.tabla-rutas-participa td,
  table.tabla-sync-comparacion th, table.tabla-sync-comparacion td { font-size: 11.5px; padding: 5px 7px; }
}

/* ---- Base Maestra RUTAS en TABLET: columnas priorizadas, cada <tr> es SU PROPIO grid (nunca un
   solo grid para toda la tabla -- "order" reordena de forma global si se comparte, ver la nota
   extensa en el bloque de Registro de Condición). Columnas reales (13): 1 Área(s), 2 Tecnología,
   3 Ruta, 4 Frecuencia, 5 N° Equipos, 6 N° Componentes/Puntos, 7 N° Actividades, 8 Fecha
   Inicialización, 9 Programación, 10 Estado, 11 Origen, 12 Próxima fecha, 13 Acciones. Todo lo que
   se oculta acá SÍ se repite en el modal "Detalle de Ruta" (abrirDetalle() en app.js) -- Frecuencia,
   Fecha Inicialización, Programación, cantidades y Origen están todos ahí; "Próxima fecha" NO está
   en ese modal, por eso se mantiene siempre visible. ---- */
@media (min-width: 768px) and (max-width: 1023px) {
  table.tabla-rutas-bm {
    display: block; table-layout: auto; border: 1px solid var(--border); border-radius: 8px; overflow: visible;
  }
  table.tabla-rutas-bm thead, table.tabla-rutas-bm tbody { display: block; }
  table.tabla-rutas-bm tr {
    display: grid; width: max-content; min-width: 100%;
    /* Máximos en px definidos (nunca "fr") -- con width:max-content por fila, un "fr" en un
       contenedor de tamaño intrínseco se resuelve como el max-content del contenido, así que una
       Ruta más larga que las demás (p.ej. "2W CConM Route 67 Fan Gearless CVB03/04") estiraba SU
       fila más que las otras -- desalineaba las columnas entre filas. Con un tope en px el texto
       largo envuelve en 2-3 líneas en vez de ensanchar la columna, y todas las filas quedan con
       exactamente el mismo ancho de columna. */
    grid-template-columns: minmax(140px,220px) minmax(90px,110px) minmax(100px,140px) minmax(90px,110px) minmax(95px,110px) minmax(70px,90px);
    column-gap: 8px;
  }
  table.tabla-rutas-bm th, table.tabla-rutas-bm td {
    display: flex; align-items: flex-start; padding: 8px 6px; font-size: 12px; line-height: 1.3;
    white-space: normal; overflow-wrap: anywhere; border-bottom: 1px solid var(--border); text-align: left;
  }
  table.tabla-rutas-bm th {
    font-weight: 700; text-transform: uppercase; font-size: 10.5px; background: var(--panel-header-bg);
    border-bottom: 2px solid var(--border); overflow-wrap: break-word;
  }
  table.tabla-rutas-bm th:nth-child(4), table.tabla-rutas-bm td:nth-child(4),
  table.tabla-rutas-bm th:nth-child(5), table.tabla-rutas-bm td:nth-child(5),
  table.tabla-rutas-bm th:nth-child(6), table.tabla-rutas-bm td:nth-child(6),
  table.tabla-rutas-bm th:nth-child(7), table.tabla-rutas-bm td:nth-child(7),
  table.tabla-rutas-bm th:nth-child(8), table.tabla-rutas-bm td:nth-child(8),
  table.tabla-rutas-bm th:nth-child(9), table.tabla-rutas-bm td:nth-child(9),
  table.tabla-rutas-bm th:nth-child(11), table.tabla-rutas-bm td:nth-child(11) { display: none; }
  table.tabla-rutas-bm th:nth-child(3), table.tabla-rutas-bm td:nth-child(3) { order: 1; } /* Ruta */
  table.tabla-rutas-bm th:nth-child(1), table.tabla-rutas-bm td:nth-child(1) { order: 2; } /* Área */
  table.tabla-rutas-bm th:nth-child(2), table.tabla-rutas-bm td:nth-child(2) { order: 3; } /* Tecnología */
  table.tabla-rutas-bm th:nth-child(10), table.tabla-rutas-bm td:nth-child(10) { order: 4; } /* Estado */
  table.tabla-rutas-bm th:nth-child(12), table.tabla-rutas-bm td:nth-child(12) { order: 5; } /* Próxima fecha */
  table.tabla-rutas-bm th:nth-child(13), table.tabla-rutas-bm td:nth-child(13) { order: 6; } /* Acciones */
}
@media (min-width: 1024px) and (max-width: 1199px) {
  table.tabla-rutas-bm {
    display: block; table-layout: auto; border: 1px solid var(--border); border-radius: 8px; overflow: visible;
  }
  table.tabla-rutas-bm thead, table.tabla-rutas-bm tbody { display: block; }
  table.tabla-rutas-bm tr {
    display: grid; width: max-content; min-width: 100%;
    /* Mismo tope en px definido que el bloque vertical de arriba -- ver esa nota. */
    grid-template-columns: minmax(160px,240px) minmax(100px,120px) minmax(110px,150px) minmax(100px,120px) minmax(105px,120px) minmax(80px,100px);
    column-gap: 8px;
  }
  table.tabla-rutas-bm th, table.tabla-rutas-bm td {
    display: flex; align-items: flex-start; padding: 8px 6px; font-size: 12.5px; line-height: 1.35;
    white-space: normal; overflow-wrap: anywhere; border-bottom: 1px solid var(--border); text-align: left;
  }
  table.tabla-rutas-bm th {
    font-weight: 700; text-transform: uppercase; font-size: 11px; background: var(--panel-header-bg);
    border-bottom: 2px solid var(--border); overflow-wrap: break-word;
  }
  table.tabla-rutas-bm th:nth-child(4), table.tabla-rutas-bm td:nth-child(4),
  table.tabla-rutas-bm th:nth-child(5), table.tabla-rutas-bm td:nth-child(5),
  table.tabla-rutas-bm th:nth-child(6), table.tabla-rutas-bm td:nth-child(6),
  table.tabla-rutas-bm th:nth-child(7), table.tabla-rutas-bm td:nth-child(7),
  table.tabla-rutas-bm th:nth-child(8), table.tabla-rutas-bm td:nth-child(8),
  table.tabla-rutas-bm th:nth-child(9), table.tabla-rutas-bm td:nth-child(9),
  table.tabla-rutas-bm th:nth-child(11), table.tabla-rutas-bm td:nth-child(11) { display: none; }
  table.tabla-rutas-bm th:nth-child(3), table.tabla-rutas-bm td:nth-child(3) { order: 1; } /* Ruta */
  table.tabla-rutas-bm th:nth-child(1), table.tabla-rutas-bm td:nth-child(1) { order: 2; } /* Área */
  table.tabla-rutas-bm th:nth-child(2), table.tabla-rutas-bm td:nth-child(2) { order: 3; } /* Tecnología */
  table.tabla-rutas-bm th:nth-child(10), table.tabla-rutas-bm td:nth-child(10) { order: 4; } /* Estado */
  table.tabla-rutas-bm th:nth-child(12), table.tabla-rutas-bm td:nth-child(12) { order: 5; } /* Próxima fecha */
  table.tabla-rutas-bm th:nth-child(13), table.tabla-rutas-bm td:nth-child(13) { order: 6; } /* Acciones */
}

/* ---- Base Maestra EQUIPOS en TABLET: mismo criterio. Columnas reales (10): 1 Área, 2 TAG,
   3 Descripción, 4 N° Rutas, 5 N° Componentes, 6 N° Actividades, 7 Técnicas/Tecnologías, 8 Estado,
   9 Origen, 10 Acciones. Lo oculto se recupera con "Ver" -> Detalle de Equipo (Descripción/Área/
   Estado/Origen ahí, y N° Rutas/Técnicas se leen de la tabla "Rutas en las que participa" del mismo
   modal). ---- */
@media (min-width: 768px) and (max-width: 1023px) {
  table.tabla-equipos-bm {
    display: block; table-layout: auto; border: 1px solid var(--border); border-radius: 8px; overflow: visible;
  }
  table.tabla-equipos-bm thead, table.tabla-equipos-bm tbody { display: block; }
  table.tabla-equipos-bm tr {
    display: grid; width: max-content; min-width: 100%;
    /* Tope en px definido, mismo motivo que Rutas (ver esa nota extensa): Descripción puede ser
       mucho más larga en un equipo que en otro y con "fr" desalineaba filas entre sí. */
    grid-template-columns: minmax(90px,110px) minmax(160px,280px) minmax(90px,110px) minmax(110px,150px) minmax(90px,110px) minmax(70px,90px);
    column-gap: 8px;
  }
  table.tabla-equipos-bm th, table.tabla-equipos-bm td {
    display: flex; align-items: flex-start; padding: 8px 6px; font-size: 12px; line-height: 1.3;
    white-space: normal; overflow-wrap: anywhere; border-bottom: 1px solid var(--border); text-align: left;
  }
  table.tabla-equipos-bm th {
    font-weight: 700; text-transform: uppercase; font-size: 10.5px; background: var(--panel-header-bg);
    border-bottom: 2px solid var(--border); overflow-wrap: break-word;
  }
  table.tabla-equipos-bm th:nth-child(4), table.tabla-equipos-bm td:nth-child(4),
  table.tabla-equipos-bm th:nth-child(5), table.tabla-equipos-bm td:nth-child(5),
  table.tabla-equipos-bm th:nth-child(6), table.tabla-equipos-bm td:nth-child(6),
  table.tabla-equipos-bm th:nth-child(9), table.tabla-equipos-bm td:nth-child(9) { display: none; }
  table.tabla-equipos-bm th:nth-child(2), table.tabla-equipos-bm td:nth-child(2) { order: 1; } /* TAG */
  table.tabla-equipos-bm th:nth-child(3), table.tabla-equipos-bm td:nth-child(3) { order: 2; } /* Descripción */
  table.tabla-equipos-bm th:nth-child(1), table.tabla-equipos-bm td:nth-child(1) { order: 3; } /* Área */
  table.tabla-equipos-bm th:nth-child(7), table.tabla-equipos-bm td:nth-child(7) { order: 4; } /* Técnicas/Tecnologías */
  table.tabla-equipos-bm th:nth-child(8), table.tabla-equipos-bm td:nth-child(8) { order: 5; } /* Estado */
  table.tabla-equipos-bm th:nth-child(10), table.tabla-equipos-bm td:nth-child(10) { order: 6; } /* Acciones */
}
@media (min-width: 1024px) and (max-width: 1199px) {
  table.tabla-equipos-bm {
    display: block; table-layout: auto; border: 1px solid var(--border); border-radius: 8px; overflow: visible;
  }
  table.tabla-equipos-bm thead, table.tabla-equipos-bm tbody { display: block; }
  table.tabla-equipos-bm tr {
    display: grid; width: max-content; min-width: 100%;
    /* Mismo tope en px definido que el bloque vertical de arriba -- ver esa nota. */
    grid-template-columns: minmax(100px,120px) minmax(190px,320px) minmax(100px,120px) minmax(130px,170px) minmax(100px,120px) minmax(80px,100px);
    column-gap: 8px;
  }
  table.tabla-equipos-bm th, table.tabla-equipos-bm td {
    display: flex; align-items: flex-start; padding: 8px 6px; font-size: 12.5px; line-height: 1.35;
    white-space: normal; overflow-wrap: anywhere; border-bottom: 1px solid var(--border); text-align: left;
  }
  table.tabla-equipos-bm th {
    font-weight: 700; text-transform: uppercase; font-size: 11px; background: var(--panel-header-bg);
    border-bottom: 2px solid var(--border); overflow-wrap: break-word;
  }
  table.tabla-equipos-bm th:nth-child(4), table.tabla-equipos-bm td:nth-child(4),
  table.tabla-equipos-bm th:nth-child(5), table.tabla-equipos-bm td:nth-child(5),
  table.tabla-equipos-bm th:nth-child(6), table.tabla-equipos-bm td:nth-child(6),
  table.tabla-equipos-bm th:nth-child(9), table.tabla-equipos-bm td:nth-child(9) { display: none; }
  table.tabla-equipos-bm th:nth-child(2), table.tabla-equipos-bm td:nth-child(2) { order: 1; } /* TAG */
  table.tabla-equipos-bm th:nth-child(3), table.tabla-equipos-bm td:nth-child(3) { order: 2; } /* Descripción */
  table.tabla-equipos-bm th:nth-child(1), table.tabla-equipos-bm td:nth-child(1) { order: 3; } /* Área */
  table.tabla-equipos-bm th:nth-child(7), table.tabla-equipos-bm td:nth-child(7) { order: 4; } /* Técnicas/Tecnologías */
  table.tabla-equipos-bm th:nth-child(8), table.tabla-equipos-bm td:nth-child(8) { order: 5; } /* Estado */
  table.tabla-equipos-bm th:nth-child(10), table.tabla-equipos-bm td:nth-child(10) { order: 6; } /* Acciones */
}

/* Badges (Estado/Programación) en columnas angostas: mismo defecto real ya corregido en Registro de
   Condición/Seguimiento -- se previene de entrada. */
@media (min-width: 768px) and (max-width: 1199px) {
  table.tabla-rutas-bm .badge, table.tabla-equipos-bm .badge, table.tabla-usuarios .badge { white-space: nowrap; font-size: 10px; padding: 2px 6px; }
}

/* ---- CELULAR (<768px) ---- */
@media (max-width: 767px) {
  /* Red de seguridad genérica (mismo defecto real que dejó "Desactivar Ruta" completamente fuera del
     viewport en el modal Detalle de Ruta, sin scroll posible para alcanzarlo -- medido con precisión:
     quedaba a 85px fuera de un viewport de 390px). Acciones apiladas a ancho completo cuando no caben
     en una fila; si ya caben, flex-wrap no cambia nada visualmente. */
  .form-actions { flex-wrap: wrap; }
  .form-actions button { flex: 1 1 100%; }

  /* "Actualizar desde Excel": el botón dejaba de tener ancho para su propio texto+ícono y lo
     partía en 2 líneas apretadas contra el indicador de última actualización. */
  .bm-sync-bar { flex-direction: column; align-items: stretch; row-gap: 8px; }
  .bm-sync-bar button { width: 100%; white-space: nowrap; }

  /* Etiquetas de KPI largas ("Administradores") se cortaban/desbordaban en la grilla de 2 columnas
     de .resumen -- acá SÍ se permiten 2 líneas (nunca truncar con "..."). Scoped a Usuarios porque
     es donde se detectó el defecto; el resto de pantallas ya usa etiquetas cortas de una palabra. */
  #tabUsuarios .resumen .card { min-width: 0; }
  #tabUsuarios .resumen .card .l { white-space: normal; overflow-wrap: break-word; }

  /* ==================== Base Maestra RUTAS: tarjeta con las 13 columnas COMPLETAS, solo
     reordenadas -- nunca ocultas (a diferencia de tablet, acá no hay ganancia de espacio real al
     ocultar y el modal "Ver" ya es redundante con la tarjeta). Ruta/Estado/Área/Tecnología arriba,
     el resto como información secundaria, Acciones al final a ancho completo. ==================== */
  table.tabla-rutas-bm { table-layout: auto; }
  table.tabla-rutas-bm thead { display: none; }
  table.tabla-rutas-bm tbody tr {
    display: flex; flex-direction: column; margin: 0 0 12px; padding: 10px 12px 12px;
    border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
    background: var(--surface);
  }
  table.tabla-rutas-bm td {
    display: block; padding: 4px 0; border-bottom: none; white-space: normal; text-align: left;
    overflow-wrap: anywhere;
  }
  table.tabla-rutas-bm td::before {
    content: attr(data-label); display: block; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em; color: var(--text-secondary); margin-bottom: 2px;
  }
  table.tabla-rutas-bm td:nth-child(3) { order: 1; font-weight: 700; font-size: 14px; } /* Ruta */
  table.tabla-rutas-bm td:nth-child(10) { order: 2; } /* Estado */
  table.tabla-rutas-bm td:nth-child(1) { order: 3; margin-top: 4px; } /* Área */
  table.tabla-rutas-bm td:nth-child(2) { order: 4; } /* Tecnología */
  table.tabla-rutas-bm td:nth-child(12) { order: 5; margin-top: 4px; } /* Próxima fecha */
  table.tabla-rutas-bm td:nth-child(9) { order: 6; } /* Programación */
  table.tabla-rutas-bm td:nth-child(4) { order: 7; } /* Frecuencia */
  table.tabla-rutas-bm td:nth-child(5) { order: 8; } /* N° Equipos */
  table.tabla-rutas-bm td:nth-child(6) { order: 9; } /* N° Componentes/Puntos */
  table.tabla-rutas-bm td:nth-child(7) { order: 10; } /* N° Actividades */
  table.tabla-rutas-bm td:nth-child(8) { order: 11; } /* Fecha Inicialización */
  table.tabla-rutas-bm td:nth-child(11) { order: 12; } /* Origen */
  table.tabla-rutas-bm td:nth-child(13) { order: 13; margin-top: 8px; } /* Acciones */
  table.tabla-rutas-bm td:nth-child(13) button { width: 100%; min-height: 42px; font-size: 13.5px; }

  /* ==================== Base Maestra EQUIPOS: mismo criterio, 10 columnas completas. ==================== */
  table.tabla-equipos-bm { table-layout: auto; }
  table.tabla-equipos-bm thead { display: none; }
  table.tabla-equipos-bm tbody tr {
    display: flex; flex-direction: column; margin: 0 0 12px; padding: 10px 12px 12px;
    border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
    background: var(--surface);
  }
  table.tabla-equipos-bm td {
    display: block; padding: 4px 0; border-bottom: none; white-space: normal; text-align: left;
    overflow-wrap: anywhere;
  }
  table.tabla-equipos-bm td::before {
    content: attr(data-label); display: block; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em; color: var(--text-secondary); margin-bottom: 2px;
  }
  table.tabla-equipos-bm td:nth-child(2) { order: 1; font-weight: 700; font-size: 14px; } /* TAG */
  table.tabla-equipos-bm td:nth-child(3) { order: 2; } /* Descripción */
  table.tabla-equipos-bm td:nth-child(8) { order: 3; } /* Estado */
  table.tabla-equipos-bm td:nth-child(1) { order: 4; margin-top: 4px; } /* Área */
  table.tabla-equipos-bm td:nth-child(7) { order: 5; } /* Técnicas/Tecnologías */
  table.tabla-equipos-bm td:nth-child(4) { order: 6; } /* N° Rutas */
  table.tabla-equipos-bm td:nth-child(5) { order: 7; } /* N° Componentes */
  table.tabla-equipos-bm td:nth-child(6) { order: 8; } /* N° Actividades */
  table.tabla-equipos-bm td:nth-child(9) { order: 9; } /* Origen */
  table.tabla-equipos-bm td:nth-child(10) { order: 10; margin-top: 8px; } /* Acciones */
  table.tabla-equipos-bm td:nth-child(10) button { width: 100%; min-height: 42px; font-size: 13.5px; }

  /* ==================== Administración de Usuarios: tarjeta con las 7 columnas COMPLETAS (nunca se
     oculta nada -- no existe una vista de detalle alternativa para Último acceso/Fecha creación).
     Usuario/Nombre/Rol/Estado arriba, fechas como dato secundario, acciones apiladas y táctiles. ==== */
  table.tabla-usuarios { table-layout: auto; }
  table.tabla-usuarios thead { display: none; }
  table.tabla-usuarios tbody tr {
    display: flex; flex-direction: column; margin: 0 0 12px; padding: 10px 12px 12px;
    border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
    background: var(--surface);
  }
  table.tabla-usuarios td {
    display: block; padding: 4px 0; border-bottom: none; white-space: normal; text-align: left;
    overflow-wrap: anywhere;
  }
  table.tabla-usuarios td::before {
    content: attr(data-label); display: block; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em; color: var(--text-secondary); margin-bottom: 2px;
  }
  table.tabla-usuarios td:nth-child(1) { order: 1; font-weight: 700; font-size: 14px; } /* Usuario */
  table.tabla-usuarios td:nth-child(2) { order: 2; } /* Nombre completo */
  table.tabla-usuarios td:nth-child(3) { order: 3; } /* Rol */
  table.tabla-usuarios td:nth-child(4) { order: 4; } /* Estado */
  table.tabla-usuarios td:nth-child(5) { order: 5; margin-top: 4px; color: var(--text-secondary); font-size: 12px; } /* Último acceso */
  table.tabla-usuarios td:nth-child(6) { order: 6; color: var(--text-secondary); font-size: 12px; } /* Fecha creación */
  table.tabla-usuarios td:nth-child(7) { order: 7; margin-top: 8px; } /* Acciones */
  .btn-usr-accion { display: block; width: 100%; min-height: 44px; font-size: 13.5px; padding: 0 12px; margin-top: 6px; }
  .btn-usr-accion:first-child { margin-top: 0; }

  /* ==================== "Rutas en las que participa" (Detalle de Equipo) y comparación Excel vs.
     BD (Sincronización, Paso 3): técnica 100% genérica por data-label, SIN nth-child -- acá no hay
     ninguna vista alternativa para ningún campo, así que ninguna columna se oculta ni se reordena.
     ==================== */
  table.tabla-rutas-participa, table.tabla-sync-comparacion { table-layout: auto; }
  table.tabla-rutas-participa thead, table.tabla-sync-comparacion thead { display: none; }
  table.tabla-rutas-participa tbody tr, table.tabla-sync-comparacion tbody tr {
    display: block; margin: 0 0 12px; padding: 10px 12px 12px;
    border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
    background: var(--surface);
  }
  table.tabla-rutas-participa td, table.tabla-sync-comparacion td {
    display: block; padding: 4px 0; border-bottom: none; white-space: normal; text-align: left;
    overflow-wrap: anywhere;
  }
  table.tabla-rutas-participa td::before, table.tabla-sync-comparacion td::before {
    content: attr(data-label); display: block; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em; color: var(--text-secondary); margin-bottom: 2px;
  }
  /* Celdas sin data-label (mensajes "Sin resultados"/"SIN RUTA", colspan): sin etiqueta, texto normal. */
}

/* ==================== RONDA "CIERRE RESPONSIVE CELULAR/TABLET": cierra los huecos puntuales que
   quedaron fuera de las rondas anteriores (R1/R2/Auditoría por módulo/Auditoría visual global) --
   nunca un sistema nuevo, reutiliza exactamente las mismas técnicas ya validadas (data-label + tarjeta
   en celular, tabla compacta sin ocultar en tablet, !important solo para pisar un style="" inline
   igual que .btn-ot). Misma regla no negociable de siempre: nada fuera de un @media <=1199px. ==================== */

/* ---- 1. Historial de círculos (Registrar/Editar Inspección) -- CRÍTICO: sin flex-wrap ni @media
   podía desbordar/apretarse con 3-4 círculos + flechas + "Ver más" en un modal de 360-390px de ancho
   útil. Solo presentación -- cero cambio en renderHistorialCircles() ni en el histórico en sí. ---- */
@media (max-width: 767px) {
  .historial-circulos { flex-wrap: wrap; row-gap: 8px; }
  /* "Ver más" pasa a su propia fila, alineado a la derecha -- nunca se aprieta contra el último
     círculo/flecha, siempre queda accesible sin importar cuántos círculos (0-4) haya. */
  .historial-circulos .hc-link { flex: 1 1 100%; text-align: right; margin-left: 0; min-height: 32px; display: flex; align-items: center; justify-content: flex-end; }
}

/* ---- 2. Foto Referencial (Base Maestra + Preparar Reporte de Condición) -- incorporación reciente
   que quedó fuera del sistema responsive porque sus botones viven sueltos, fuera de .filtros/
   .form-actions (los únicos contenedores que hoy dan tamaño táctil a un <button>). !important es la
   única forma de pisar el style="" inline sin reescribir por completo renderFotoReferencialEquipo/
   renderFotoReferencialPreparar -- mismo criterio ya usado en .btn-ot (Programa Semanal celular). ---- */
@media (max-width: 767px) {
  .foto-referencial-caja { flex-direction: column !important; align-items: stretch !important; }
  .foto-referencial-caja > img { width: 100% !important; height: 180px !important; }
  .foto-referencial-acciones { flex-direction: column !important; align-items: stretch !important; }
  .foto-referencial-acciones button { min-height: 44px; width: 100%; font-size: 13.5px; }
}

/* ---- 3. Tablas sueltas (Seguimientos cerrados, Previsualizar Programa x2, Detalle de Ruta del día):
   ninguna tiene una vista de detalle alternativa para ningún campo, así que siguen exactamente el
   mismo criterio ya usado para Usuarios/Rutas-participa/Sync-comparacion -- tabla real compacta en
   tablet (nunca oculta columnas), tarjeta genérica por data-label en celular (sin nth-child, ninguna
   columna se pierde). ---- */
@media (min-width: 768px) and (max-width: 1199px) {
  table.tabla-seguimientos-cerrados, table.tabla-preview-programa, table.tabla-preview-excluidas, table.tabla-ruta-dia {
    display: table; table-layout: auto; overflow: visible;
  }
  table.tabla-seguimientos-cerrados thead, table.tabla-preview-programa thead,
  table.tabla-preview-excluidas thead, table.tabla-ruta-dia thead { display: table-header-group; }
  table.tabla-seguimientos-cerrados tbody tr, table.tabla-preview-programa tbody tr,
  table.tabla-preview-excluidas tbody tr, table.tabla-ruta-dia tbody tr { display: table-row; }
  table.tabla-seguimientos-cerrados td, table.tabla-seguimientos-cerrados th,
  table.tabla-preview-programa td, table.tabla-preview-programa th,
  table.tabla-preview-excluidas td, table.tabla-preview-excluidas th,
  table.tabla-ruta-dia td, table.tabla-ruta-dia th { display: table-cell; }
  #modalSeguimientoCerrados main, #tabProgramaSemanal main, #modalRutaDia .modal { overflow-x: auto; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  table.tabla-seguimientos-cerrados th, table.tabla-seguimientos-cerrados td,
  table.tabla-preview-programa th, table.tabla-preview-programa td,
  table.tabla-preview-excluidas th, table.tabla-preview-excluidas td,
  table.tabla-ruta-dia th, table.tabla-ruta-dia td { font-size: 11.5px; padding: 5px 7px; }
}
@media (max-width: 767px) {
  table.tabla-seguimientos-cerrados, table.tabla-preview-programa, table.tabla-preview-excluidas, table.tabla-ruta-dia {
    table-layout: auto;
  }
  table.tabla-seguimientos-cerrados thead, table.tabla-preview-programa thead,
  table.tabla-preview-excluidas thead, table.tabla-ruta-dia thead { display: none; }
  table.tabla-seguimientos-cerrados tbody tr, table.tabla-preview-programa tbody tr,
  table.tabla-preview-excluidas tbody tr, table.tabla-ruta-dia tbody tr {
    display: block; margin: 0 0 12px; padding: 10px 12px 12px;
    border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 1px 3px rgba(16,24,40,.05);
    background: var(--surface);
  }
  table.tabla-seguimientos-cerrados td, table.tabla-preview-programa td,
  table.tabla-preview-excluidas td, table.tabla-ruta-dia td {
    display: block; padding: 4px 0; border-bottom: none; white-space: normal; text-align: left;
    overflow-wrap: anywhere;
  }
  table.tabla-seguimientos-cerrados td::before, table.tabla-preview-programa td::before,
  table.tabla-preview-excluidas td::before, table.tabla-ruta-dia td::before {
    content: attr(data-label); display: block; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em; color: var(--text-secondary); margin-bottom: 2px;
  }
  /* Celdas sin data-label (mensajes "Sin datos"/"No hay seguimientos...", colspan): sin etiqueta. */
  table.tabla-seguimientos-cerrados td[data-label="Ver"] button { width: 100%; min-height: 40px; }
}

/* ---- 4. Ranking Multi-Semana (Dashboard, "Equipos No Monitoreados"): tenía compactación de
   escritorio pero ninguna regla de celular/tablet -- el contenedor (.db-fila-nomonitoreados-detalle)
   ya colapsa a 1 columna, solo faltaba la tabla en sí. Mismo criterio "sin vista alternativa" que el
   punto 3: tarjeta genérica en celular, tabla compacta sin ocultar en tablet. ---- */
@media (min-width: 768px) and (max-width: 1199px) {
  table.tabla-ranking-noejec th, table.tabla-ranking-noejec td { font-size: 11.5px; padding: 5px 7px; }
}
@media (max-width: 767px) {
  table.tabla-ranking-noejec { table-layout: auto; }
  table.tabla-ranking-noejec thead { display: none; }
  table.tabla-ranking-noejec tbody tr {
    display: block; margin: 0 0 10px; padding: 8px 10px 10px;
    border: 1px solid var(--border); border-radius: 8px; background: var(--surface);
  }
  table.tabla-ranking-noejec td {
    display: block; padding: 3px 0; border-bottom: none; white-space: normal; text-align: left;
    overflow-wrap: anywhere;
  }
  table.tabla-ranking-noejec td::before {
    content: attr(data-label); display: block; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em; color: var(--text-secondary); margin-bottom: 2px;
  }
}
