/* ============================================================================
   Portal Técnico · Sistema de diseño compartido (portal-ui.css)
   ----------------------------------------------------------------------------
   Fuente única de verdad para tokens y componentes base del portal.
   Se sirve en /portal-ui.css. Cada vista lo enlaza con:
     <link rel="stylesheet" href="/portal-ui.css">
   y define arriba SOLO lo propio de esa pantalla.

   Nombres canónicos (los de las views): --bg / --bg-2 / --panel / --panel-2 /
   --txt / --txt-dim / --txt-faint / --accent / --turno / --line / --radius.
   Al migrar, renombrar los locales (--gold→--turno, --navy→--bg, --panel2→
   --panel-2, --text→--txt, --bg2→--bg-2, etc.). Ver docs/PLAN-UNIFICACION-VISUAL.md
   ========================================================================== */

:root {
  /* Superficies */
  --bg: #0e141b;
  --bg-2: #141c26;
  --panel: #1a2430;
  --panel-2: #212e3d;

  /* Líneas / bordes */
  --line: #2b3a4d;
  --line-soft: #243140;
  --line-strong: #3c506a;            /* borde acentuado en hover (input/chip/card/opción) */

  /* Texto */
  --txt: #e6edf3;
  --txt-dim: #95a6b8;
  --txt-faint: #5e7185;

  /* Acento (turquesa) */
  --accent: #2dd4bf;
  --accent-deep: #14b8a6;
  --accent-ink: #06231f;             /* texto sobre relleno acento */
  --accent-glow: rgba(45, 212, 191, .14);
  --accent-soft: rgba(45, 212, 191, .09);  /* relleno tenue de estado "on" */

  /* Semánticos. Regla para no depender solo del color (daltonismo): estos
     tonos son válidos como RELLENO (badge/chip/borde) porque ya traen su
     propia tinta (--accent-ink/--ink-warm) o conviven con un ícono/texto que
     dice el estado (p.ej. ESTSOL en horarios.js ya manda "Pendiente"/
     "Aprobada"/etc, no solo el color). Si vas a agregar un indicador NUEVO
     que sea solo un color plano sin texto/ícono al lado (como era el punto
     de severidad en notificaciones), sumale una forma o un símbolo distinto,
     no otro tono más — ver .notif-item .punto más abajo. */
  --turno: #f0b429;                  /* dorado (turno / atención) */
  --urgente: #f97362;
  --danger: #f87171;
  --ok: #22c55e;
  --warn: #eab308;                   /* pendiente / advertencia */
  --pronto: var(--warn);             /* alias histórico (Mantenimiento) */
  --vencida: #f87171;
  --feriado: #ff8c42;                /* naranja (feriado en Horarios) */
  --ink-warm: #1a1205;               /* texto sobre rellenos cálidos */
  --bg-hi: #17222f;                  /* resalte del gradiente radial del fondo (ver body) */
  /* Acentos de identidad: NO son estados (nada "está" violeta). Sirven para
     distinguir formularios entre sí — ver .form-card en Formularios. */
  --viol: #a78bfa;
  --rose: #e07bab;

  /* Categóricos: SOLO para agrupar datos (ranking de marcas, series de un gráfico),
     nunca un estado. Evitar acá los tonos ya tomados por turno/semánticos (dorado,
     teal de acento, naranja feriado) — en Horarios y el dashboard turno y categoría
     conviven en la misma pantalla y no tienen que poder confundirse. */
  --cat-1: #38bdf8;
  --cat-2: #a78bfa;
  --cat-3: #f472b6;
  --cat-4: #34d399;
  --cat-5: #818cf8;
  --cat-6: #94a3b8;                  /* "Otras": siempre el gris, al final */

  /* Radios / sombras */
  --radius: 12px;
  --radius-sm: 8px;
  --radius-pill: 999px;
  --shadow: 0 12px 40px rgba(0, 0, 0, .45);

  /* Tipografía */
  --font: "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;
  --mono: "Cascadia Code", "Consolas", "SF Mono", ui-monospace, monospace;
  --fs: 14px;
}

/* ============================================================================
   Tema claro
   ----------------------------------------------------------------------------
   Se activa con [data-theme="light"] en <html>. La persistencia (localStorage
   'theme.modo') y el botón del header viven en portal-secciones.js (precarga,
   antes del primer paint — mismo patrón que rail.visible/rail.mini) y
   portal-sesion.js (botón + alternar). login.html no carga esos scripts y
   replica la misma clave a mano, ver su <head>.

   Superficies/texto/líneas se remapean acá. Los semánticos (--accent/--danger/
   --turno/--ok/--warn/--urgente) NO cambian de valor: siguen sirviendo igual
   como RELLENO en los dos temas (badges, botones primary, chips), porque ya
   traen su propia tinta oscura encima. Donde esos mismos tonos se usan como
   TEXTO plano sobre el fondo de página (pensados para leerse sobre fondo
   oscuro) sí perdían contraste contra un fondo blanco — esos selectores
   puntuales se pisan más abajo con una versión más oscura/saturada de la
   misma familia de color, sin tocar la variable global.
   ========================================================================== */
[data-theme="light"] {
  --bg: #f3f5f7;
  --bg-2: #ffffff;
  --bg-hi: #ffffff;
  --panel: #ffffff;
  --panel-2: #eef1f4;

  --line: #d7dee5;
  --line-soft: #e6ebf0;
  --line-strong: #b9c4cf;

  --txt: #1b2430;
  --txt-dim: #55606c;
  --txt-faint: #7c8794;

  --accent-glow: rgba(15, 118, 110, .16);
  --accent-soft: rgba(15, 118, 110, .10);

  --shadow: 0 12px 30px rgba(30, 41, 59, .12);
}
[data-theme="light"] .ok,
[data-theme="light"] .rail-grp.on,
[data-theme="light"] .tab.on,
[data-theme="light"] .btn.acc { color: #0f766e; }
[data-theme="light"] .tab.on,
[data-theme="light"] .btn.acc { border-color: #0f766e; }
[data-theme="light"] .err,
[data-theme="light"] .btn.danger { color: #b91c1c; }
[data-theme="light"] .btn.danger { border-color: #b91c1c; }
[data-theme="light"] .warn,
[data-theme="light"] header .mark b { color: #b45309; }

/* --- reset mínimo --- */
* { box-sizing: border-box; }
html, body { margin: 0; }
body {
  background: radial-gradient(1200px 600px at 50% -10%, var(--bg-hi), var(--bg));
  color: var(--txt);
  font-family: var(--font);
  font-size: var(--fs);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}
button, input, select, textarea { font-family: inherit; }

/* ============================================================================
   Layout
   ========================================================================== */
.wrap { max-width: 1250px; margin: 0 auto; padding: 22px 24px 60px; }
.spacer { flex: 1; }
.hide { display: none !important; }

h1 { font-size: 19px; font-weight: 700; margin: 0 0 2px; }
.lead { color: var(--txt-dim); font-size: 12.5px; margin: 0 0 16px; }

/* ============================================================================
   Header / navbar
   ----------------------------------------------------------------------------
   FORMATO igual en todas las vistas; los BOTONES varían por jerarquía
   (Inicio siempre → "/"; Volver solo en páginas nivel-2 → su submenú).
   ========================================================================== */
header {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 24px; border-bottom: 1px solid var(--line);
}
header .mark { font-size: 17px; font-weight: 700; letter-spacing: -.02em; }
header .mark b { color: var(--turno); }
header .sub {
  font-size: 11.5px; color: var(--txt-faint);
  text-transform: uppercase; letter-spacing: .06em;
}
header .ver { font-size: 11.5px; color: var(--txt-faint); }
header .who { font-size: 12.5px; color: var(--txt-dim); }
/* Los botones de navegación del header (anchors) quedan alineados con ícono */
header .btn { text-decoration: none; display: inline-flex; align-items: center; gap: 7px; }

/* ============================================================================
   Botones
   ----------------------------------------------------------------------------
   .btn            secundario (default)
   .btn.primary    acción primaria (relleno acento)
   .btn.acc        acento en outline (énfasis suave)
   .btn.danger     destructivo
   .btn.mini/.big  tamaños
   ========================================================================== */
.btn {
  border: 1px solid var(--line); background: var(--panel); color: var(--txt);
  padding: 7px 12px; border-radius: var(--radius-sm);
  font-size: 12.5px; font-weight: 600; cursor: pointer; font-family: inherit;
  display: inline-flex; align-items: center; gap: 7px;
  text-decoration: none; user-select: none;
  transition: background .12s, border-color .12s, color .12s;
}
.btn:hover { background: var(--panel-2); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.primary:hover { background: var(--accent-deep); border-color: var(--accent-deep); }
.btn.acc { border-color: var(--accent); color: var(--accent); background: var(--panel); }
.btn.acc:hover { background: var(--panel-2); }
.btn.danger { border-color: var(--danger); color: var(--danger); }
.btn.mini { padding: 3px 8px; font-size: 11px; }
.btn.big { padding: 11px 18px; font-size: 14px; }

/* ============================================================================
   Paneles / avisos
   ========================================================================== */
.panel {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 16px; margin-bottom: 16px;
}
.panel > b { font-size: 14px; }
.panel h2 { font-size: 13.5px; font-weight: 700; margin: 0 0 12px; }
/* Título de panel + link de acción a la derecha ("Ver X →") — dashboard de Inicio
   y secciones de página completa que linkean a otra vista (ej. "La sala" en /equipo). */
.dash-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 12px; }
.dash-head b { font-size: 13px; }
.dash-head a { margin-left: auto; font-size: 11.5px; color: var(--accent); text-decoration: none; }
.dash-head a:hover { text-decoration: underline; }
.aviso {
  font-size: 12px; color: var(--txt-dim); background: var(--bg-2);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 9px 12px; margin: 8px 0;
}
.ok { color: var(--accent); }
.err { color: var(--danger); }
.warn { color: var(--turno); }

/* ============================================================================
   Tarjetas KPI y barras de ranking — compartidas por Métricas operativas y
   Panorama (antes solo en metricas-operativas.css).
   ========================================================================== */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; margin-bottom: 16px; }
.kpi {
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px;
}
.kpi .k-label { font-size: 11px; color: var(--txt-faint); text-transform: uppercase; letter-spacing: .05em; }
.kpi .k-val { font-size: 26px; font-weight: 700; margin: 4px 0 2px; letter-spacing: -.02em; }
.kpi .k-val.acc { color: var(--accent); }
.kpi .k-val.danger { color: var(--danger); }
.kpi .k-val.warn { color: var(--turno); }
.kpi .k-sub { font-size: 11.5px; color: var(--txt-dim); }
/* Bajada pegada al h1 en la cabecera de dashboard (.top): sin el margen inferior
   de una .lead de página, que ahí abriría demasiado. */
.top .lead { margin: 2px 0 0; }

.fila-bar { display: grid; grid-template-columns: minmax(110px, 1fr) 2fr auto; gap: 10px; align-items: center; margin-bottom: 8px; font-size: 12.5px; }
.fila-bar .nom { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fila-bar .track { background: var(--panel-2); border-radius: 4px; height: 8px; position: relative; }
.fila-bar .marca { position: absolute; top: -2px; bottom: -2px; width: 2px; background: var(--urgente); opacity: .85; border-radius: 1px; }
.fila-bar .fill { background: var(--accent); height: 100%; border-radius: 4px; }
.fila-bar .fill.gold { background: var(--turno); }
.fila-bar .num { color: var(--txt-dim); font-size: 12px; white-space: nowrap; }
.fila-bar .num b { color: var(--txt); }

.estado { font-size: 11.5px; color: var(--txt-faint); margin-top: 4px; }
.vacio { color: var(--txt-faint); font-size: 12.5px; padding: 8px 0; }
.chip-reinc { display: inline-block; font-size: 10.5px; font-weight: 600; padding: 1px 8px; border-radius: var(--radius-pill); border: 1px solid var(--danger); color: var(--danger); white-space: nowrap; }
.nota-h2 { font-weight: 400; color: var(--txt-faint); font-size: 11px; }
/* Leyenda de gráfico (svgTendencia): metricas-operativas.html, datos-contables.html, equipo.html. */
.leg { margin-bottom: 8px; }
.leg span { display: inline-flex; align-items: center; margin-right: 16px; font-size: 11.5px; color: var(--txt-dim); }
.leg i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; margin-right: 6px; }

/* Distribución por marca (dona) + top modelos (barras) — panel "Maestro de sala"
   de Inicio y sección "La sala" de /equipo (pintarDistribucionMarca en portal-charts.js). */
.maestro-lay { display: flex; align-items: center; gap: 16px; }
.maestro-donut { position: relative; flex: 0 0 auto; width: 84px; height: 84px; }
.maestro-donut svg { display: block; width: 100%; height: 100%; }
.maestro-total { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; pointer-events: none; }
.maestro-total span { font-size: 18px; font-weight: 700; line-height: 1; }
.maestro-total small { font-size: 9px; color: var(--txt-faint); margin-top: 1px; }
.maestro-leg { display: flex; flex-direction: column; gap: 6px; min-width: 0; flex: 1; }
.maestro-leg span { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--txt-dim); min-width: 0; }
.maestro-leg span b { width: 8px; height: 8px; border-radius: 2px; flex: 0 0 auto; }
.maestro-leg span em { font-style: normal; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.maestro-leg span small { color: var(--txt-faint); flex: 0 0 auto; }
.maestro-bars { margin-top: 14px; display: flex; flex-direction: column; gap: 7px; }
.maestro-bars .mb-row { display: flex; align-items: center; gap: 8px; }
.maestro-bars .mb-k { font-size: 11px; color: var(--txt-dim); flex: 0 0 108px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.maestro-bars .mb-track { flex: 1; min-width: 0; height: 10px; background: var(--panel-2); border-radius: 3px; overflow: hidden; }
.maestro-bars .mb-fill { display: block; height: 100%; background: var(--accent); border-radius: 3px 0 0 3px; }
.maestro-bars .mb-v { font-size: 10.5px; color: var(--txt-faint); flex: 0 0 20px; text-align: right; }

/* ============================================================================
   Tabs (navegación interna de una vista)
   ========================================================================== */
.tabs { display: flex; gap: 8px; margin-bottom: 18px; flex-wrap: wrap; }
.tab {
  border: 1px solid var(--line); background: var(--panel); color: var(--txt-dim);
  padding: 7px 14px; border-radius: var(--radius-sm);
  font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.tab.on { color: var(--accent); border-color: var(--accent); }

/* ============================================================================
   Formularios
   ========================================================================== */
label.f {
  display: block; font-size: 11px; color: var(--txt-dim);
  margin: 10px 0 3px; text-transform: uppercase; letter-spacing: .04em;
}
input:not([type=checkbox]):not([type=radio]), select, textarea {
  background: var(--bg-2); border: 1px solid var(--line); color: var(--txt);
  border-radius: var(--radius-sm); padding: 8px 10px; font-size: 13px;
  width: 100%; transition: border-color .15s ease, box-shadow .15s ease;
}
input:hover:not(:disabled), select:hover:not(:disabled), textarea:hover:not(:disabled) { border-color: var(--line-strong); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow);
}
input::placeholder, textarea::placeholder { color: var(--txt-faint); }
input:disabled, select:disabled, textarea:disabled { opacity: .5; }
input[type=date] { color-scheme: dark; }
select {
  appearance: none; -webkit-appearance: none; padding-right: 28px; cursor: pointer;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none' stroke='%2395a6b8' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><path d='M2.5 4.5 6 8l3.5-3.5'/></svg>");
  background-repeat: no-repeat; background-position: right 10px center;
}
/* fila de campos parejos */
.filtros { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }
.filtros .campo { display: flex; flex-direction: column; gap: 4px; flex: 0 1 150px; }
.filtros .campo label.f { margin: 0; }
/* fila de campos en grid auto-responsive */
.fila { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
/* patrón edit-mode: inputs disabled lucen como texto plano */
input:not([type=checkbox]):not([type=radio]):disabled { border-color: transparent; background: transparent; }

/* ============================================================================
   Formulario en tarjeta (.form-card)
   ----------------------------------------------------------------------------
   Es la "ventana" de edición (el .modal de Horarios) abierta y apoyada en la
   página: cabecera con ícono + título + bajada, cuerpo con los campos y pie con
   las acciones. La idea es que dar de alta y editar se vean igual, en vez de un
   modal cuidado y un formulario suelto de campos apilados.

     <div class="form-card gold">
       <div class="fc-head">
         <span class="fc-ico">🔁</span>
         <div class="fc-t"><b>Título</b><small>De qué se trata</small></div>
       </div>
       <div class="fc-body"><div class="campos">…</div></div>
       <div class="fc-foot"><span class="msg"></span><button class="btn primary">Guardar</button></div>
     </div>

   El COLOR sale de --fc / --fc-soft / --fc-glow, que define la propia tarjeta:
   la barra superior, el ícono, el foco de los campos y los controles marcados
   lo toman de ahí. Así cada formulario se identifica por color sin repetir
   reglas. Variantes: (sin clase)=acento, .gold .viol .rose .fer .danger.
   ========================================================================== */
/* La banda de color va en el borde de la TARJETA, no en el de la cabecera: con
   overflow:hidden un borde del hijo tirado hacia arriba se recorta y queda de
   1px. Acá son 2px siempre. */
.form-card {
  --fc: var(--accent); --fc-soft: var(--accent-soft); --fc-glow: var(--accent-glow);
  background: var(--panel); border: 1px solid var(--line); border-top: 2px solid var(--fc);
  border-radius: var(--radius); margin-bottom: 16px; overflow: hidden;
}
/* El tono lo definen las clases .t-* — están al final del archivo, después de
   .modal y .lanzador: misma especificidad, gana el último. */

/* el degradé bajo la banda: es lo que hace que la tarjeta se lea como una
   ventana con identidad y no como un panel más */
.fc-head {
  display: flex; align-items: center; gap: 12px; padding: 14px 18px;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, var(--fc-soft), rgba(0, 0, 0, 0));
}
.fc-ico {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center; font-size: 17px; line-height: 1;
  background: var(--fc-soft); box-shadow: inset 0 0 0 1px var(--fc-glow);
}
.fc-t { min-width: 0; }
.fc-t b { display: block; font-size: 14px; font-weight: 700; }
.fc-t small { display: block; font-size: 11.5px; color: var(--txt-dim); margin-top: 1px; }
/* acción secundaria en la cabecera (un ✎, un contador) */
.fc-head .fc-acc { margin-left: auto; display: flex; align-items: center; gap: 8px; }

.fc-body { padding: 16px 18px; }
.fc-body > .lead:last-child, .fc-body > p:last-child { margin-bottom: 0; }
.fc-foot {
  display: flex; align-items: center; gap: 10px; justify-content: flex-end;
  padding: 12px 18px; border-top: 1px solid var(--line); background: var(--bg-2);
}
.fc-foot .msg { margin-right: auto; font-size: 12.5px; min-width: 0; }
/* dentro de la tarjeta el foco y los controles marcados usan SU color */
.form-card input:focus, .form-card select:focus, .form-card textarea:focus {
  border-color: var(--fc); box-shadow: 0 0 0 3px var(--fc-glow);
}
.form-card input[type=checkbox], .form-card input[type=radio] { accent-color: var(--fc); }

/* --- grilla de campos ---------------------------------------------------- */
.campos {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  gap: 14px 12px; align-items: end;
}
.campos .campo { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.campos .campo label.f { margin: 0; }
.campos .campo .hint { font-size: 11.5px; color: var(--txt-faint); }
.campo.ancho { grid-column: span 2; }
.campo.full { grid-column: 1 / -1; }
/* separador con rótulo, para agrupar campos dentro de un mismo cuerpo */
.campos-sep {
  grid-column: 1 / -1; display: flex; align-items: center; gap: 10px;
  font-size: 10.5px; font-weight: 700; color: var(--txt-faint);
  text-transform: uppercase; letter-spacing: .05em; margin-top: 2px;
}
.campos-sep::after { content: ''; flex: 1; height: 1px; background: var(--line); }

/* --- opciones en tarjeta (radio / checkbox) ------------------------------
   Mismo lenguaje que .seg pero con el control real adentro, así el JS que lee
   `input[name=x]:checked` sigue funcionando igual. */
.opciones { display: flex; flex-wrap: wrap; gap: 10px; }
.opt-card {
  flex: 1 1 220px; display: flex; align-items: flex-start; gap: 10px; cursor: pointer;
  border: 1px solid var(--line); background: var(--bg-2); border-radius: 10px;
  padding: 10px 12px; font-size: 13px; font-weight: 600; color: var(--txt-dim);
  transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease;
}
.opt-card:hover { border-color: var(--line-strong); color: var(--txt); }
.opt-card input { flex: 0 0 auto; margin: 2px 0 0; }
.opt-card small { display: block; font-weight: 600; font-size: 10.5px; color: var(--txt-faint); margin-top: 2px; }
.opt-card:has(input:checked) {
  color: var(--txt); border-color: var(--fc, var(--accent));
  background: var(--fc-soft, var(--accent-soft)); box-shadow: 0 0 0 1px var(--fc, var(--accent)) inset;
}

/* --- interruptor ---------------------------------------------------------
   El checkbox real queda oculto (no `display:none`: tiene que seguir siendo
   enfocable y llegarle el click desde el <label>). */
.switch { position: relative; display: inline-flex; align-items: center; gap: 10px; cursor: pointer; font-size: 13px; user-select: none; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
  flex: 0 0 auto; position: relative; width: 38px; height: 22px; border-radius: var(--radius-pill);
  background: var(--panel-2); border: 1px solid var(--line);
  transition: background .15s ease, border-color .15s ease;
}
.switch .track::after {
  content: ''; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: 50%; background: var(--txt-faint);
  transition: transform .15s ease, background .15s ease;
}
.switch input:checked + .track { background: var(--fc-soft, var(--accent-soft)); border-color: var(--fc, var(--accent)); }
.switch input:checked + .track::after { transform: translateX(16px); background: var(--fc, var(--accent)); }
.switch input:focus-visible + .track { box-shadow: 0 0 0 3px var(--fc-glow, var(--accent-glow)); }
.switch .sw-t small { display: block; font-size: 11px; color: var(--txt-faint); }

/* --- zona de archivo (drag & drop) ---------------------------------------
   El <input type=file> nativo es el control más feo del portal. Queda adentro,
   estirado e invisible: sigue siendo él el que abre el diálogo y el que el JS
   lee con .files[0], pero lo que se ve es la zona. */
.dropzone {
  position: relative; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 7px; text-align: center; padding: 26px 18px;
  border: 1.5px dashed var(--line); border-radius: var(--radius);
  background: var(--bg-2); cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.dropzone:hover { border-color: var(--fc, var(--accent)); background: var(--panel-2); }
/* el input real es invisible: el foco de teclado tiene que verse en la zona */
.dropzone:focus-within { border-color: var(--fc, var(--accent)); box-shadow: 0 0 0 3px var(--fc-glow, var(--accent-glow)); }
.dropzone.over { border-style: solid; border-color: var(--fc, var(--accent)); background: var(--fc-soft, var(--accent-soft)); }
/* el verde de "archivo cargado" manda también con el mouse encima: si no, pasar
   por arriba lo devuelve al color de la zona vacía y parece que se perdió */
.dropzone.cargado, .dropzone.cargado:hover { border-style: solid; border-color: var(--ok); background: rgba(34, 197, 94, .06); }
.dropzone input[type=file] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer; padding: 0; border: 0; background: none;
}
.dropzone .dz-ico { font-size: 26px; line-height: 1; }
.dropzone .dz-t { font-size: 13.5px; font-weight: 600; }
.dropzone .dz-t u { color: var(--fc, var(--accent)); text-underline-offset: 2px; }
.dropzone .dz-h { font-size: 11.5px; color: var(--txt-faint); }
.dropzone.cargado .dz-ico { color: var(--ok); }

/* ============================================================================
   Ventana (.modal) y lanzadores (.lanzador)
   ----------------------------------------------------------------------------
   Los formularios NO van sueltos en la página: cada alta o edición es un botón
   que abre su ventana. La página queda con lo que se lee (tablas, calendarios)
   y el trabajo de cargar pasa por acá.

     <button class="lanzador t-gold" onclick="abrirModal('mod-x')">
       <span class="lz-ico">🔁</span>
       <span class="lz-t"><b>Título</b><small>Qué hace</small></span>
       <span class="lz-go">+</span>
     </button>

     <div class="modal-bg" id="mod-x"><div class="modal ancho">
       <div class="mhead">…</div><div class="mbody">…</div><div class="mfoot">…</div>
     </div></div>

   Comparten --fc con .form-card: el lanzador y la ventana que abre llevan el
   mismo tono y se leen como la misma cosa.
   ========================================================================== */
.lanzadores {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 270px), 1fr));
  gap: 12px; margin-bottom: 16px;
}
/* si están todos ocultos por permisos, la grilla no deja su margen colgando */
.lanzadores:not(:has(> :not(.hide))) { display: none; }
.lanzador {
  --fc: var(--accent); --fc-soft: var(--accent-soft); --fc-glow: var(--accent-glow);
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  background: var(--panel); border: 1px solid var(--line); border-left: 3px solid var(--fc);
  border-radius: var(--radius); padding: 13px 15px; cursor: pointer;
  font-family: inherit; color: var(--txt);
  transition: background .15s ease, border-color .15s ease, transform .08s ease;
}
.lanzador:hover { background: var(--panel-2); border-color: var(--fc); border-left-color: var(--fc); }
.lanzador:active { transform: translateY(1px); }
.lanzador:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--fc-glow); }
.lanzador .lz-ico {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 11px;
  display: grid; place-items: center; font-size: 18px; line-height: 1;
  background: var(--fc-soft); box-shadow: inset 0 0 0 1px var(--fc-glow);
}
.lanzador .lz-t { flex: 1; min-width: 0; }
.lanzador .lz-t b { display: block; font-size: 13.5px; font-weight: 700; }
.lanzador .lz-t small { display: block; font-size: 11.5px; color: var(--txt-dim); margin-top: 2px; }
.lanzador .lz-go {
  flex: 0 0 auto; color: var(--fc); font-size: 17px; font-weight: 700; opacity: .55;
  transition: opacity .15s ease, transform .15s ease;
}
.lanzador:hover .lz-go { opacity: 1; transform: translateX(2px); }

.modal-bg {
  position: fixed; inset: 0; z-index: 50; display: none;
  align-items: flex-start; justify-content: center; padding: 40px 16px;
  background: rgba(6, 10, 14, .66); overflow-y: auto;
}
.modal-bg.show { display: flex; }
/* Columna con tope de alto: la cabecera y el pie quedan fijos y lo que scrollea
   es el cuerpo. Con overflow en el fondo, un formulario largo se llevaba los
   botones de Guardar fuera de la pantalla. */
.modal {
  --fc: var(--accent); --fc-soft: var(--accent-soft); --fc-glow: var(--accent-glow);
  display: flex; flex-direction: column; max-height: calc(100vh - 80px);
  width: 100%; max-width: 480px;
  background: var(--panel); border: 1px solid var(--line); border-top: 2px solid var(--fc);
  border-radius: 14px; box-shadow: var(--shadow); overflow: hidden;
}
.modal.ancho { max-width: 640px; }
.modal.xl { max-width: 900px; }
.modal .mhead {
  flex: 0 0 auto; display: flex; align-items: center; gap: 12px; padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, var(--fc-soft), rgba(0, 0, 0, 0));
}
.modal .mhead h2 { margin: 0; font-size: 15px; font-weight: 700; }
.modal .mhead .mh-sub { display: block; font-size: 11.5px; font-weight: 400; color: var(--txt-dim); margin-top: 1px; }
.modal .mhead .x {
  margin-left: auto; align-self: flex-start; background: transparent; border: none;
  color: var(--txt-dim); font-size: 22px; line-height: 1; cursor: pointer; padding: 0 2px;
}
.modal .mhead .x:hover { color: var(--txt); }
.modal .mbody { flex: 1 1 auto; overflow-y: auto; padding: 18px 20px; background: var(--bg-2); }
.modal .mbody > .lead:first-child { margin-top: 0; }
.modal .mfoot {
  flex: 0 0 auto; display: flex; align-items: center; gap: 10px; justify-content: flex-end;
  padding: 12px 20px; border-top: 1px solid var(--line); background: var(--panel);
}
.modal .mfoot .msg { margin-right: auto; font-size: 12.5px; min-width: 0; }
.modal input:focus, .modal select:focus, .modal textarea:focus {
  border-color: var(--fc); box-shadow: 0 0 0 3px var(--fc-glow);
}
.modal input[type=checkbox], .modal input[type=radio] { accent-color: var(--fc); }

/* ============================================================================
   Tonos de identidad
   ----------------------------------------------------------------------------
   Lo lee cualquier componente que use --fc: .form-card, .lanzador, .modal.
   Sin clase, acento. Este bloque tiene que quedar DESPUÉS de esos componentes:
   todos son un selector de clase, así que a igual especificidad gana el último
   — si se sube antes, cada componente se repinta con su propio --fc y todo
   vuelve a verse turquesa.
   ========================================================================== */
.t-gold { --fc: var(--turno);   --fc-soft: rgba(240, 180, 41, .10); --fc-glow: rgba(240, 180, 41, .17); }
.t-viol { --fc: var(--viol);    --fc-soft: rgba(167, 139, 250, .11); --fc-glow: rgba(167, 139, 250, .18); }
.t-rose { --fc: var(--rose);    --fc-soft: rgba(224, 123, 171, .11); --fc-glow: rgba(224, 123, 171, .18); }
.t-fer  { --fc: var(--feriado); --fc-soft: rgba(255, 140, 66, .10);  --fc-glow: rgba(255, 140, 66, .17); }
.t-dngr { --fc: var(--danger);  --fc-soft: rgba(248, 113, 113, .10); --fc-glow: rgba(248, 113, 113, .17); }

/* ============================================================================
   Chips / tags
   ========================================================================== */
.chip {
  border: 1px solid var(--line); background: var(--bg-2); color: var(--txt-dim);
  border-radius: var(--radius-pill); padding: 8px 14px; font-size: 13px;
  font-weight: 600; cursor: pointer; font-family: inherit; user-select: none;
  transition: border-color .12s, color .12s, background .12s;
}
.chip:hover { border-color: var(--line-strong); color: var(--txt); }
.chip.on { color: var(--txt); background: rgba(45, 212, 191, .12); border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
/* Selector compacto de rango (7/15/30 d) dentro de un .dash-head: menu.html
   "Máquinas más conflictivas" y equipo.html "Máquinas sin movimiento". */
.conf-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.conf-right a { margin-left: 0; }
.conf-seg { display: inline-flex; gap: 4px; }
.conf-seg .chip { padding: 2px 9px; font-size: 10.5px; }
.tag {
  display: inline-block; font-size: 10.5px; border-radius: 5px;
  padding: 1px 7px; border: 1px solid var(--line); color: var(--txt-dim);
}

/* ============================================================================
   Popovers
   ----------------------------------------------------------------------------
   Panel flotante anclado a un botón (filtros del relevo, la campanita). El
   patrón nació duplicado dentro de relevo-tecnico.html; acá queda la versión
   genérica. Se abre agregando .show — sin JS de posicionamiento.
   El wrapper DEBE ser .pop-wrap: el popover se ancla a él, no a la página.
   ========================================================================== */
.pop-wrap { position: relative; }
.pop {
  display: none; position: absolute; right: 0; top: calc(100% + 6px);
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); z-index: 40;
}
.pop.show { display: block; }
.pop-list { max-height: 260px; overflow-y: auto; }
.pop-foot { display: flex; gap: 8px; justify-content: flex-end; margin-top: 10px; }
.pop-hint { font-size: 11px; color: var(--txt-faint); }
.pop-sec {
  font-size: 10px; font-weight: 700; color: var(--txt-faint);
  text-transform: uppercase; letter-spacing: .04em;
}

/* Contador sobre un elemento (pendientes, no leídas). Generaliza el .pend del menú. */
.badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: var(--radius-pill); background: var(--warn); color: var(--ink-warm);
  font-size: 10.5px; font-weight: 700; line-height: 1;
}

/* ============================================================================
   Campanita de notificaciones (public/portal-notificaciones.js)
   ----------------------------------------------------------------------------
   Se inyecta por JS en el header de todas las vistas. El markup no está en
   ningún HTML: el navbar está duplicado en 10 archivos.
   ========================================================================== */
.notif-btn { position: relative; padding: 7px 9px; }   /* relative: ancla el contador */
.notif-btn svg { display: block; }
/* Botón de tema claro/oscuro, inyectado por portal-sesion.js junto a la campanita. */
.tema-btn { padding: 7px 9px; }
.tema-btn svg { display: block; }
.notif-btn .badge {
  position: absolute; top: -5px; right: -5px;
  /* El borde recorta el contador contra el fondo del header: sin esto se pega
     al ícono y se lee como parte del dibujo. */
  border: 2px solid var(--bg);
}
/* Severidad: define el color del contador y del punto de cada ítem. Es la
   jerarquía visual del feed — accionable y urgente no pueden leerse igual.
   El punto (.notif-item .punto) no tiene texto al lado, así que además del
   color cambia de FORMA — círculo/cuadrado/triángulo — para no depender
   solo del color (daltonismo, ver nota en :root de este archivo). */
.sev-info    { background: var(--txt-faint); }
.sev-accion  { background: var(--warn); }
.sev-urgente { background: var(--urgente); }
.notif-item .punto.sev-accion  { border-radius: 3px; }
.notif-item .punto.sev-urgente { border-radius: 0; clip-path: polygon(50% 0%, 0% 100%, 100% 100%); }

/* ============================================================================
   Rail lateral (public/portal-rail.js)
   ----------------------------------------------------------------------------
   Barra de navegación vertical, inyectada por JS en cualquier vista que enlace
   portal-rail.js. No hay markup en ningún HTML: el árbol lo arma el script y lo
   filtra por /api/me (herramientas + capacidades). Reemplaza a los botones de
   navegación del header; el header queda solo con marca, campanita, usuario y
   Salir.

   Montaje sin tocar el layout de cada vista: el rail es position:fixed y el
   corrimiento del contenido lo hace html.has-rail body (padding-left). Así una vista
   se suma al rail con SOLO enlazar el script, sin envolver su HTML en columnas.
   ========================================================================== */
/* La clase va en <html>, no en <body>: portal-secciones.js la anticipa desde
   localStorage ANTES de que <body> exista (evita el salto de layout que se veía
   en cada navegación, mientras portal-rail.js espera el fetch a /api/me). */
html.has-rail body { padding-left: var(--rail-w, 208px); transition: padding-left .16s ease; }
html.has-rail.rail-mini body { --rail-w: 56px; }

.rail {
  position: fixed; top: 0; left: 0; bottom: 0; width: var(--rail-w, 208px);
  background: var(--bg-2); border-right: 1px solid var(--line);
  display: flex; flex-direction: column; z-index: 50;
  transition: width .16s ease, transform .16s ease;
}
/* Cabecera del rail: solo el control de colapsar (la marca vive en el header
   de la página, a la derecha del rail). En mini queda centrado. */
.rail-top { display: flex; align-items: center; padding: 11px 10px; min-height: 51px; }
.rail-mini .rail-top { justify-content: center; }
.rail-collapse {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--txt-dim); cursor: pointer;
}
.rail-collapse:hover { background: var(--panel); color: var(--txt); }
.rail-collapse svg { display: block; }

.rail-nav { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 4px 8px 14px; }
.rail-nav::-webkit-scrollbar { width: 8px; }
.rail-nav::-webkit-scrollbar-thumb { background: var(--line); border-radius: 8px; }

/* Fila de grupo (o link suelto): ícono + etiqueta + chevron. <a> o <button>. */
.rail-grp {
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 9px 10px; margin-top: 1px; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--txt-dim); font: inherit; font-size: 13px;
  text-align: left; text-decoration: none; cursor: pointer; transition: background .12s, color .12s;
}
.rail-grp:hover { background: var(--panel); color: var(--txt); }
.rail-grp.on { color: var(--accent); background: var(--accent-soft); box-shadow: inset 2px 0 0 var(--accent); }
.rail-grp.soon { color: var(--txt-faint); }
.rail-grp .ic { flex: 0 0 auto; width: 20px; height: 20px; }
.rail-grp .ic svg { display: block; width: 20px; height: 20px; }
.rail-grp .tx { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail-grp .chev { flex: 0 0 auto; color: var(--txt-faint); transition: transform .16s ease; }
.rail-grp[aria-expanded="true"] .chev { transform: rotate(180deg); }
.rail-grp .soon-tag {
  flex: 0 0 auto; font-size: 9px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--txt-faint); border: 1px solid var(--line); border-radius: 4px; padding: 0 4px;
}

/* Sub-lista de una herramienta. Se pliega con [hidden] (una sola abierta). */
.rail-sub { margin: 1px 0 3px 20px; padding-left: 10px; border-left: 1px solid var(--line-soft); }
.rail-it {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 9px; margin-top: 1px; border-radius: var(--radius-sm);
  color: var(--txt-dim); font-size: 12px; text-decoration: none; transition: background .12s, color .12s;
}
.rail-it:hover { background: var(--panel); color: var(--txt); }
.rail-it.on { background: var(--panel-2); color: var(--txt); }
.rail-it .tx { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail-it .badge { flex: 0 0 auto; height: 16px; min-width: 16px; font-size: 9.5px; }

/* Modo mini (colapsado a íconos): se ocultan etiquetas, chevrons y sub-listas. */
.rail-mini .rail-grp { justify-content: center; padding: 9px 0; }
.rail-mini .rail-grp .tx,
.rail-mini .rail-grp .chev,
.rail-mini .rail-grp .soon-tag,
.rail-mini .rail-sub { display: none; }

/* Modo degradado (SlotAdmin caído): aviso arriba del rail + marca en las herramientas
   cuyas acciones activas quedaron fuera de servicio. Ver docs/ACCESO-DEGRADADO.md. */
.rail-aviso {
  display: flex; gap: 8px; align-items: flex-start;
  margin: 2px 2px 8px; padding: 8px 10px;
  background: rgba(234, 179, 8, .13);                 /* --warn suave */
  border: 1px solid rgba(234, 179, 8, .42);
  border-radius: var(--radius-sm);
  color: var(--txt-dim); font-size: 11px; line-height: 1.35;
}
.rail-aviso-ic { flex: 0 0 auto; color: var(--warn); }
.rail-aviso-ic svg { display: block; width: 16px; height: 16px; }
.rail-aviso-tx b { display: block; color: var(--txt); font-size: 12px; margin-bottom: 2px; }
.rail-degradada { opacity: .72; }
.rail-tag {
  flex: 0 0 auto; font-size: 9px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--warn); border: 1px solid rgba(234, 179, 8, .42);
  border-radius: 4px; padding: 0 4px; white-space: nowrap;
}
/* En mini se ocultan los textos: el aviso queda como ícono y las tags desaparecen. */
.rail-mini .rail-aviso-tx, .rail-mini .rail-tag { display: none; }
.rail-mini .rail-aviso { justify-content: center; padding: 8px 0; }

/* Flyout: en mini, clickear un grupo con hijos no navega ni expande en la fila
   (no hay lugar) — abre este mismo .rail-sub como panel flotante al lado del
   ícono (portal-rail.js calcula top/left con getBoundingClientRect). Sin esto,
   un grupo cuyos hijos son páginas sueltas (p. ej. "Herramientas") no tenía forma
   de ir directo a una en mini, solo al hub de tarjetas. Selector con .rail-mini
   + dos clases para ganarle a la regla de arriba sin depender del orden. */
.rail-mini .rail-sub.rail-flyout {
  display: block; position: fixed; margin: 0; padding: 6px; border-left: 0;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); min-width: 190px; z-index: 55;
}
.rail-mini .rail-sub.rail-flyout .rail-it { font-size: 13px; }

/* Botón hamburguesa: solo en móvil, inyectado al inicio del header. Abre el
   cajón. En escritorio el rail está siempre visible y sobra. */
.rail-burger {
  display: none; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0; border: 1px solid var(--line);
  border-radius: var(--radius-sm); background: var(--panel); color: var(--txt); cursor: pointer;
}
.rail-burger svg { display: block; }
.rail-bd {
  display: none; position: fixed; inset: 0; background: rgba(0, 0, 0, .5); z-index: 49;
}

@media (max-width: 860px) {
  /* El rail fijo se lleva demasiado ancho en pantallas chicas: pasa a cajón. */
  html.has-rail body { padding-left: 0; }
  .rail { transform: translateX(-100%); width: 232px; }
  .rail.open { transform: translateX(0); box-shadow: var(--shadow); }
  .rail.open + .rail-bd, .rail-bd.show { display: block; }
  .rail-burger { display: inline-flex; }
  /* En cajón nunca se muestra en mini: se abre completo o no se abre. */
  .rail-mini .rail-grp { justify-content: flex-start; padding: 9px 10px; }
  .rail-mini .rail-grp .tx, .rail-mini .rail-grp .chev, .rail-mini .rail-sub { display: flex; }
  .rail-mini .rail-grp .chev { display: inline-flex; }
}
@media (prefers-reduced-motion: reduce) {
  html.has-rail body, .rail, .rail-grp .chev { transition: none; }
}

/* El display va en el estado ABIERTO, no acá: si .notif-pop fijara display:flex suelto,
   ganaría sobre el `.pop { display:none }` de arriba (misma especificidad, viene después)
   y el popover quedaría siempre expandido. La columna la necesita el layout sticky. */
.notif-pop { width: 360px; max-width: calc(100vw - 24px); }
.notif-pop.show { display: flex; flex-direction: column; }
.notif-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 11px 13px; border-bottom: 1px solid var(--line-soft);
}
.notif-head b { font-size: 13px; }
.notif-list { max-height: min(60vh, 420px); overflow-y: auto; }

.notif-item {
  display: grid; grid-template-columns: 8px 1fr; gap: 10px; align-items: start;
  width: 100%; text-align: left; padding: 10px 13px;
  background: none; border: 0; border-bottom: 1px solid var(--line-soft);
  border-left: 2px solid transparent;   /* reservado: lo pinta .no-leida, así el texto no se corre */
  color: var(--txt); font: inherit; cursor: pointer;
}
.notif-item:hover { background: var(--panel-2); }
.notif-item:last-child { border-bottom: 0; }
.notif-item.no-leida { border-left-color: var(--accent); background: var(--accent-soft); }
.notif-item.no-leida:hover { background: var(--panel-2); }
.notif-item .punto { width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; }
.notif-item .t { font-size: 12.5px; font-weight: 600; }
.notif-item .m { font-size: 11.5px; color: var(--txt-dim); margin-top: 2px; }
.notif-item .cuando { font-size: 10.5px; color: var(--txt-faint); margin-top: 3px; }

/* Separador de día. Sticky: al scrollear una lista larga siempre se sabe de cuándo
   es lo que se está mirando. */
.notif-dia {
  position: sticky; top: 0; z-index: 1;
  padding: 7px 13px; background: var(--bg-2);
  border-bottom: 1px solid var(--line-soft);
}
.notif-vacio { padding: 26px 16px; text-align: center; font-size: 12.5px; }
.notif-cargando { padding: 14px 13px; display: grid; gap: 12px; }
.notif-cargando i {
  display: block; height: 9px; border-radius: 5px; background: var(--panel-2);
  animation: notif-late 1.1s ease-in-out infinite;
}
.notif-cargando i:nth-child(2) { width: 75%; }
.notif-cargando i:nth-child(3) { width: 55%; }
@keyframes notif-late { 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) { .notif-cargando i { animation: none; } }

/* ============================================================================
   Tablas de lectura (.lista)
   ----------------------------------------------------------------------------
   Componente único para las tablas de lectura del portal (admin, mantenimiento,
   horarios, datos-contables, metricas). Antes cada vista repetía casi el mismo
   bloque `.lista`/`table` con micro-diferencias de padding y tamaño. Acá vive
   la base; las vistas solo agregan sus modificadores propios (.yes/.no en admin,
   sticky de columna en #p-tabla, etc.).

   NO aplica a las grillas densas especializadas: maestro (`table` a secas, con
   min-width y zebra propios) y horarios `.equipo` (columnas/headers sticky y
   semántica de turnos). Esas siguen con su hoja de vista.

   Muchas `.lista` ponen el `<th>` en el primer `<tr>` sin `<thead>` (se arman
   en JS), por eso los selectores van sobre `.lista th`/`td`, no `thead th`. */
table.lista { border-collapse: collapse; width: 100%; font-size: 12.5px; }

/* Contenedor redondeado: solo cuando la .lista va dentro de un .scroll (las
   listas de gestión). border-radius + overflow del .scroll recortan el header
   a las esquinas. Los dashboards (datos-contables/metricas) envuelven en
   `<div style="overflow-x:auto">` a propósito y quedan sin marco, ya viven
   dentro de un .panel. */
.scroll:has(> table.lista) {
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel);
}

.lista th {
  position: sticky; top: 0; z-index: 1;
  background: var(--bg-2); color: var(--txt-dim);
  font-weight: 600; font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em;
  text-align: left; padding: 10px 13px; border-bottom: 1px solid var(--line);
  white-space: nowrap; cursor: default;
}
.lista td {
  padding: 9px 13px; border-bottom: 1px solid var(--line-soft);
  vertical-align: middle; line-height: 1.45;
}
.lista tr:last-child td { border-bottom: none; }

/* Hover: tiñe la fila. Solo el td se tiñe, así el header (que trae th) queda
   quieto. Las filas clicables suman barra de acento a la izquierda. */
.lista tr:hover td { background: var(--bg-2); }
.lista tr.click { cursor: pointer; }
.lista tr.click:hover td:first-child { box-shadow: inset 3px 0 0 var(--accent); }

.lista th.num { text-align: right; }
.lista td.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.lista td.dim { color: var(--txt-dim); }
.lista td.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.lista td.center { text-align: center; }
.lista tr.anulada { opacity: .4; text-decoration: line-through; }

/* Pill de estado: forma (punto) + color, no solo color — cumple la regla
   anti-daltonismo (ver nota de los semánticos arriba). Variantes semánticas;
   los alias mapean los nombres históricos de cada vista. */
.est-pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 600; line-height: 1.4;
  padding: 2px 9px 2px 8px; border-radius: var(--radius-pill, 999px); white-space: nowrap;
}
.est-pill::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: 0 0 auto; }
.est-pill.ok { color: var(--ok); background: rgba(34, 197, 94, .12); }
.est-pill.warn { color: var(--warn); background: rgba(234, 179, 8, .12); }
.est-pill.danger { color: var(--danger); background: rgba(248, 113, 113, .12); }
.est-pill.neutral { color: var(--txt-faint); background: rgba(148, 166, 184, .1); }

/* ============================================================================
   Listas de acción — celda de botones por fila (.acciones)
   ----------------------------------------------------------------------------
   Contraparte de las tablas de lectura: las mismas .lista pero con acciones por
   fila (planos, admin, mantenimiento, horarios). Antes cada vista repetía el
   `style="text-align:right;white-space:nowrap"` en la celda y amontonaba
   .btn.mini con caja, separados por espacios sueltos. Acá viven el contenedor
   (gap y alineado consistentes) y la jerarquía.

   Idea: en una .lista los botones quedan QUIETOS (sin caja) mientras leés la
   fila, y arman el marco al pasar el mouse — así mandan los datos, no la
   botonera. Cada variante conserva su color, para que la jerarquía se lea
   siempre sin necesidad de hover: primaria .acc (acento), destructiva .danger
   (rojo), el resto texto normal. En touch (sin hover) los botones quedan con su
   caja de siempre, bien visibles. */
.acciones { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
/* height:100% — un <td> con display:flex deja de generar caja de celda; el
   navegador lo envuelve en una celda anónima que sí estira a la altura de la
   fila, pero la caja flex real (la que pintamos) queda del alto de su
   contenido. Con una fila más alta que una línea (nombre largo que envuelve)
   la botonera queda chica dentro de un contenedor más grande. Forzar 100% la
   estira a la altura real de la celda anónima. */
.lista td.acciones { justify-content: flex-end; flex-wrap: nowrap; white-space: nowrap; height: 100%; }

@media (hover: hover) {
  /* Quieto: sin caja, para que la fila respire. El borde sigue ocupando su 1px
     (transparente), así aparecer/desaparecer no mueve el layout. */
  .lista td.acciones .btn { background: transparent; border-color: transparent; }
  /* Los secundarios (sin color propio) se atenúan en reposo para no competir con
     los datos, y recuperan tinta plena cuando te acercás. Los .acc/.danger/.primary
     conservan su color siempre: así la jerarquía se lee sin necesidad de hover. */
  .lista td.acciones .btn:not(.acc):not(.danger):not(.primary) { color: var(--txt-dim); }
  .lista tr:hover td.acciones .btn:not(.acc):not(.danger):not(.primary),
  .lista tr:focus-within td.acciones .btn:not(.acc):not(.danger):not(.primary) { color: var(--txt); }
  /* Al pasar por la fila —o cuando estás editándola (un input/select con foco,
     patrón ✎ → Guardar/✕)— se insinúa el marco de toda la botonera. */
  .lista tr:hover td.acciones .btn,
  .lista tr:focus-within td.acciones .btn { border-color: var(--line-soft); }
  /* Al ir a tocar un botón puntual, se arma del todo con su color. */
  .lista td.acciones .btn:hover { background: var(--panel-2); border-color: var(--line); }
  .lista td.acciones .btn.acc:hover { border-color: var(--accent); }
  .lista td.acciones .btn.danger:hover { border-color: var(--danger); }
}

/* ============================================================================
   Utilidades
   ========================================================================== */
.mono { font-family: var(--mono); }
/* overscroll-behavior-x: sin esto el swipe horizontal sobre una tabla
   dispara el "volver atrás" del navegador en móvil */
.scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain; }
.faint { color: var(--txt-faint); }
.mt { margin-top: 10px; }
.self-end { align-self: end; }   /* campo alineado al piso de una .fila */
.w-auto { width: auto; }         /* select/input que no debe estirarse */
/* .hide vive en Layout; .ok/.err/.warn en Paneles y avisos */

/* ============================================================================
   Mobile
   ----------------------------------------------------------------------------
   Primera media query del portal. Nace por Horarios (ahí el celular es el
   dispositivo principal, reemplaza la hoja de papel de la oficina), pero el
   chrome es compartido, así que aplica a todas las vistas.
   NO se oculta header .sub: relevo-tecnico y proximamente no tienen <h1> y
   se quedarían sin título; en menu y login el .sub dice algo distinto.
   ========================================================================== */
@media (max-width: 640px) {
  .wrap { padding: 16px 14px 48px; }
  h1 { font-size: 17px; }
  header { padding: 12px 14px; gap: 10px; flex-wrap: wrap; }
  header .who { max-width: 45vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .panel { padding: 12px; }

  /* --- formulario en tarjeta ---
     Menos aire en cabecera/cuerpo/pie, y las acciones del pie a ancho completo
     con target cómodo. `.ancho` pasa a fila entera: con una sola columna, un
     `span 2` crearía una segunda columna implícita y desbordaría. */
  .fc-head { padding: 12px 14px; gap: 10px; }
  .fc-body { padding: 14px; }
  .fc-foot { padding: 11px 14px; flex-wrap: wrap; }
  .fc-foot .msg { flex-basis: 100%; margin: 0 0 4px; }
  .fc-foot .btn { flex: 1 1 45%; min-height: 44px; justify-content: center; }
  .campo.ancho { grid-column: 1 / -1; }
  .opt-card { flex-basis: 100%; }
  .dropzone { padding: 22px 14px; }

  /* --- ventana y lanzadores ---
     La ventana ocupa la pantalla de punta a punta y se pega arriba; el pie no
     scrollea con el cuerpo, así que Guardar siempre está donde el pulgar. */
  .modal-bg { padding: 10px; }
  .modal, .modal.ancho, .modal.xl { max-width: 100%; max-height: calc(100vh - 20px); }
  .modal .mhead, .modal .mbody, .modal .mfoot { padding-left: 14px; padding-right: 14px; }
  .modal .mfoot { flex-wrap: wrap; }
  .modal .mfoot .msg { flex-basis: 100%; margin: 0 0 4px; }
  .modal .mfoot .btn { flex: 1 1 45%; min-height: 44px; justify-content: center; }
  .lanzador { padding: 12px 13px; }

  /* Las pestañas no se apilan: una sola fila que se arrastra con el dedo.
     Horarios tiene 9 y en 375px ocuparían cuatro renglones. */
  .tabs {
    flex-wrap: nowrap; overflow-x: auto; padding-bottom: 2px;
    scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .tabs::-webkit-scrollbar { display: none; }
  .tab { flex: 0 0 auto; scroll-snap-align: start; }

  /* El header hace flex-wrap acá arriba, así que un popover de 360px anclado al
     botón se sale de la pantalla (y si la campanita cayó al segundo renglón,
     encima aparece a mitad de página). Pasa a ocupar el ancho, fijo bajo el header. */
  .notif-pop {
    position: fixed; left: 8px; right: 8px; top: 58px;
    width: auto; max-width: none;
  }
  .notif-list { max-height: 65vh; }
}

/* -- Componentes compartidos (hoisted en Fase 2b desde los CSS de página; ver
   docs/REDUCCION-EMBEBIDO.md). Eran reglas IDENTICAS duplicadas en varias vistas;
   movidas acá sin cambios. Selectores únicos: no colisionan con nada previo. ---- */

/* Breadcrumb (herramientas, maestro, métricas, optimización, próximamente) */
.crumb { font-size: 12px; color: var(--txt-faint); margin: 0 0 10px; }
.crumb a { color: var(--txt-dim); text-decoration: none; }
.crumb a:hover { color: var(--accent); }

/* Grilla de tarjetas-herramienta (herramientas, optimización) */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
.tool { display: block; text-decoration: none; color: inherit; background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px; transition: .12s; }
.tool:hover { border-color: var(--accent); transform: translateY(-2px); }
.tool.soon { opacity: .5; pointer-events: none; }
.tool .t { font-size: 15px; font-weight: 700; margin-bottom: 4px; }
.tool .d { font-size: 12.5px; color: var(--txt-dim); }
.tool .tag { display: inline-block; margin-top: 10px; font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--accent); border: 1px solid var(--accent); border-radius: 5px; padding: 1px 6px; }
.tool.soon .tag { color: var(--txt-faint); border-color: var(--txt-faint); }

/* Modal "Detalle de máquina" -- filas del detalle (menu, relevo). Las clases de la
   ventana (.modal-bg/.modal/.mhead/.tabs) ya son globales más arriba en este archivo. */
.maq-num.link { cursor: pointer; color: var(--accent); text-decoration: none; }
.maq-num.link:hover { text-decoration: underline; }
.mhint { font-size: 12.5px; color: var(--txt-dim); margin-bottom: 12px; }
.slot-cab { font-size: 14px; margin-bottom: 14px; }
.slot-grupo { margin-bottom: 14px; }
.slot-grupo h4 { margin: 0 0 6px; font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--txt-dim); }
.slot-campo { display: flex; justify-content: space-between; gap: 10px; padding: 4px 0; border-bottom: 1px solid var(--line-soft); font-size: 13px; }
.slot-campo .lbl { color: var(--txt-dim); }
.slot-campo .val { font-weight: 600; text-align: right; }
