/* Panel de monitoreo · 96 Kronos Broadcast
   ---------------------------------------------------------------------------
   Hereda la identidad del sitio: negro neutro, acento dorado #DAA521, Inter.

   Regla de color que se respeta en todo el panel: el dorado es la marca y lo
   accionable; el estado de la señal NUNCA se comunica solo con color, siempre
   va punto + etiqueta de texto. En una sala de control con monitores mal
   calibrados, y para quien no distingue verde de rojo, el texto es lo único
   que se lee con seguridad. */

*, *::before, *::after { box-sizing: border-box; }

/* El atributo `hidden` del navegador es solo `display: none` de baja
   prioridad: cualquier `display` explícito en una clase lo pisa y el elemento
   se queda a la vista. Pasó tres veces en este panel —el contador de las
   pestañas, el aviso de "conectando" y el bloque de métricas encima del
   video—, así que se le devuelve autoridad de una vez para todo el documento. */
[hidden] { display: none !important; }

:root {
  color-scheme: dark;

  --plane:      #0a0a0a;   /* fondo, igual que el neutral-950 del sitio */
  --surface:    #131313;
  --surface-2:  #1a1a1a;
  --border:     #262626;
  --border-soft: rgba(255,255,255,.07);

  --ink:        #ededed;
  --ink-2:      #b4b4b4;
  --muted:      #7d7d7d;

  --brand:      #DAA521;
  --brand-soft: #F5D87A;
  --brand-dim:  rgba(218,165,33,.12);

  /* Estados. Deliberadamente separados del dorado de marca para que
     "atención" no se confunda con "botón". */
  --good:     #34a853;
  --warning:  #e2802f;
  --serious:  #dd6a3e;
  --critical: #dc4c4c;
  --idle:     #5c5c5c;

  /* Series de las gráficas */
  --s1: #4b9fea;
  --s2: #DAA521;
  --s3: #37b98a;

  --grid: #232323;
  --axis: #303030;

  --sans: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  --radius: 10px;
}

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

body {
  background: var(--plane);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-soft); }

:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

.tabular { font-variant-numeric: tabular-nums; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ══════════════════════════════════════════════ ingreso */

.login-page {
  min-height: 100%;
  display: grid; place-items: center;
  padding: 24px;
  background:
    radial-gradient(700px 420px at 50% -10%, rgba(218,165,33,.14), transparent 65%),
    var(--plane);
}
.login-card {
  width: 100%; max-width: 380px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 30px 28px 26px;
}
.login-mark { display: flex; align-items: center; gap: 11px; margin-bottom: 22px; }
.login-mark img { width: 38px; height: 38px; object-fit: contain; }
.login-mark .name { font-size: 15px; font-weight: 600; letter-spacing: .01em; }
.login-mark .sub { font-size: 11.5px; color: var(--muted); letter-spacing: .06em; text-transform: uppercase; }

.field { margin-bottom: 13px; }
.field label {
  display: block; font-size: 12px; color: var(--ink-2);
  margin-bottom: 6px; font-weight: 500;
}
.field input, .field select, .field textarea {
  width: 100%; height: 42px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0 12px;
  transition: border-color .15s, box-shadow .15s;
}
.field textarea { height: auto; padding: 10px 12px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(218,165,33,.16);
}
.field .hint { font-size: 11.5px; color: var(--muted); margin-top: 5px; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 40px; padding: 0 16px;
  border-radius: 8px; border: 1px solid var(--border);
  background: var(--surface-2); color: var(--ink);
  font-size: 13px; font-weight: 500; cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.btn:hover:not(:disabled) { border-color: #3a3a3a; background: #202020; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-primary {
  background: var(--brand); border-color: var(--brand);
  color: #1a1400; font-weight: 600;
}
.btn-primary:hover:not(:disabled) { background: var(--brand-soft); border-color: var(--brand-soft); }
.btn-danger { color: var(--critical); border-color: rgba(220,76,76,.35); background: rgba(220,76,76,.07); }
.btn-danger:hover:not(:disabled) { background: rgba(220,76,76,.14); border-color: var(--critical); }
.btn-sm { height: 30px; padding: 0 10px; font-size: 12px; border-radius: 7px; }
.btn-block { width: 100%; }

.alert {
  display: none; margin-bottom: 14px; padding: 10px 12px;
  border-radius: 8px; font-size: 13px;
  border: 1px solid rgba(220,76,76,.3);
  background: rgba(220,76,76,.08); color: #f0a5a5;
}
.alert.show { display: block; }
.alert.ok { border-color: rgba(52,168,83,.3); background: rgba(52,168,83,.08); color: #93d7a8; }

/* ══════════════════════════════════════════════ estructura de la app */

.app { display: flex; flex-direction: column; min-height: 100%; }

.topbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 18px;
  padding: 0 18px; height: 56px;
  background: rgba(10,10,10,.88);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
/* El logotipo puede ceder ancho. Con `flex: none` era el único que no cedía,
   así que toda la compresión de la barra caía sobre las pestañas. */
.topbar .mark { display: flex; align-items: center; gap: 9px; flex: 0 1 auto; min-width: 0; }
.topbar .mark img { width: 26px; height: 26px; object-fit: contain; flex: none; }
.topbar .mark span {
  font-size: 13.5px; font-weight: 600; letter-spacing: .01em;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.topbar .mark small { color: var(--muted); font-weight: 400; }

/* La barra de desplazamiento está oculta a propósito, pero sin ninguna pista
   de que hay más pestañas a la derecha el recorte parece el final de la lista.
   El degradado del borde lo insinúa sin ocupar sitio. */
.tabs {
  display: flex; gap: 2px; overflow-x: auto; scrollbar-width: none;
  min-width: 0; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs:not(.sin-resto) { mask-image: linear-gradient(90deg, #000 calc(100% - 26px), transparent); }
.tab { scroll-snap-align: start; }
.tab {
  position: relative; flex: none;
  background: none; border: 0; cursor: pointer;
  padding: 0 12px; height: 56px;
  font-size: 13px; color: var(--muted);
  border-bottom: 2px solid transparent;
  transition: color .15s, border-color .15s;
}
.tab:hover { color: var(--ink-2); }
.tab[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--brand); }
.tab .count {
  display: inline-block; margin-left: 6px; padding: 1px 6px;
  border-radius: 999px; font-size: 10.5px; font-weight: 600;
  background: var(--brand-dim); color: var(--brand-soft);
}
/* Un envío encendido que no está emitiendo es una caída que nadie está
   mirando: la pestaña tiene que delatarlo aunque estés en otra vista. */
.tab .count.warn { background: rgba(220,76,76,.14); color: #f0a5a5; }

.topbar .right { margin-left: auto; display: flex; align-items: center; gap: 14px; }

.pill {
  display: inline-flex; align-items: center; gap: 7px;
  height: 28px; padding: 0 11px;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface);
  font-size: 12px; font-weight: 600; letter-spacing: .03em;
  /* La cápsula tiene altura fija: si la etiqueta se parte en dos líneas el
     texto se sale por arriba y por abajo del borde redondeado. */
  white-space: nowrap; flex: none;
}
.pill .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--idle); }
.pill.is-good { color: var(--good); }      .pill.is-good .dot { background: var(--good); }
.pill.is-warning { color: var(--warning); } .pill.is-warning .dot { background: var(--warning); }
.pill.is-bad { color: var(--critical); }    .pill.is-bad .dot { background: var(--critical); }
.pill.is-idle { color: var(--muted); }
.pill.live .dot { animation: pulse 2s ease-in-out infinite; }
@keyframes pulse { 0%,100% { opacity: 1 } 50% { opacity: .3 } }
@media (prefers-reduced-motion: reduce) { .pill.live .dot { animation: none } }

.usermenu { position: relative; }
.usermenu > button {
  display: flex; align-items: center; gap: 8px;
  background: none; border: 0; cursor: pointer; padding: 4px 6px; border-radius: 8px;
}
.usermenu > button:hover { background: var(--surface-2); }
.avatar {
  width: 28px; height: 28px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--brand-dim); color: var(--brand-soft);
  font-size: 11.5px; font-weight: 700; border: 1px solid rgba(218,165,33,.28);
}
.usermenu .who { text-align: left; line-height: 1.15; }
.usermenu .who b { display: block; font-size: 12.5px; font-weight: 500; }
.usermenu .who small { color: var(--muted); font-size: 11px; }
.menu {
  display: none; position: absolute; right: 0; top: calc(100% + 8px);
  min-width: 200px; padding: 5px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.6);
}
.menu.open { display: block; }
.menu button {
  display: block; width: 100%; text-align: left;
  background: none; border: 0; cursor: pointer;
  padding: 8px 10px; border-radius: 7px; font-size: 13px; color: var(--ink-2);
}
.menu button:hover { background: var(--surface-2); color: var(--ink); }
.menu .sep { height: 1px; background: var(--border); margin: 5px 0; }

/* Por debajo de escritorio las siete pestañas más el logotipo más el bloque de
   sesión no caben en 56 px de una sola fila. Antes no había ninguna regla y el
   resultado era el peor posible: las pestañas, único elemento que podía
   encogerse, quedaban en cero y el panel se quedaba sin navegación. Bajan a su
   propia fila y la derecha suelta lo prescindible. */
@media (max-width: 1023px) {
  .topbar { height: auto; padding: 8px 12px; gap: 10px; row-gap: 2px; flex-wrap: wrap; }
  .topbar .tabs { order: 3; flex: 1 0 100%; }
  .tab { height: 44px; }
  .usermenu .who { display: none; }
}
@media (max-width: 560px) {
  .topbar .mark small { display: none; }
}

main { flex: 1; padding: 18px; }
/* 36 px de margen lateral es el 10 % de un teléfono, y ese ancho perdido es
   parte de la aritmética que hacía desbordar las rejillas. */
@media (max-width: 560px) { main { padding: 12px; } }
.view { display: none; }
.view.active { display: block; }

.notice {
  display: none; margin-bottom: 14px; padding: 10px 13px;
  border-radius: 8px; font-size: 13px; color: #f0b0b0;
  border: 1px solid rgba(220,76,76,.3); border-left: 3px solid var(--critical);
  background: rgba(220,76,76,.07);
}
.notice.show { display: block; }

.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px 16px 13px;
}
/* Los encabezados de tarjeta son etiquetas, no titulares: el dato es lo que
   debe pesar en la jerarquía. Incluye los que van anidados en .chart-head,
   que de otro modo caerían al h2 por defecto del navegador. */
.card > h2, .chart-head h2 {
  margin: 0 0 3px; font-size: 12px; font-weight: 500;
  color: var(--muted); letter-spacing: .02em;
}
.card .sub { font-size: 11.5px; color: var(--muted); line-height: 1.5; }
@media (max-width: 560px) { .card { padding: 12px 12px 11px; } }

.section-head {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin: 0 0 11px;
}
.section-head h1 { margin: 0; font-size: 15px; font-weight: 600; }
.section-head p { margin: 0; font-size: 12px; color: var(--muted); }
.section-head .tools { margin-left: auto; display: flex; align-items: center; gap: 8px; }

.empty {
  padding: 44px 20px; text-align: center;
  color: var(--muted); font-size: 13px;
  border: 1px dashed var(--border); border-radius: var(--radius);
}

/* estados: punto + etiqueta, nunca color solo */
.state { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; }
.state .dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.s-good    { color: var(--good) }     .s-good .dot    { background: var(--good) }
.s-warning { color: var(--warning) }  .s-warning .dot { background: var(--warning) }
.s-serious { color: var(--serious) }  .s-serious .dot { background: var(--serious) }
.s-bad     { color: var(--critical) } .s-bad .dot     { background: var(--critical) }
.s-idle    { color: var(--muted) }    .s-idle .dot    { background: var(--idle) }

/* ══════════════════════════════════════════════ multiview */

.mv-toolbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 12px;
}
.seg { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.seg button {
  background: var(--surface); border: 0; cursor: pointer;
  padding: 0 11px; height: 30px; font-size: 12px; color: var(--muted);
  border-right: 1px solid var(--border);
}
.seg button:last-child { border-right: 0; }
.seg button:hover { color: var(--ink-2); background: var(--surface-2); }
.seg button[aria-pressed="true"] { background: var(--brand-dim); color: var(--brand-soft); }

.grid { display: grid; gap: 12px; }
.grid[data-cols="1"] { grid-template-columns: 1fr; }
.grid[data-cols="2"] { grid-template-columns: repeat(2, 1fr); }
.grid[data-cols="3"] { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 1100px) { .grid[data-cols="3"] { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 720px)  { .grid[data-cols="2"], .grid[data-cols="3"] { grid-template-columns: 1fr; } }
/* A una columna forzada, el selector 1 / 2×2 / 3×3 seguía marcando "3×3" y
   guardando esa elección: tres botones que no producen ningún cambio y un
   `aria-pressed` que anuncia un estado falso. Mejor no ofrecerlo. */
@media (max-width: 720px)  { .section-head .tools .seg, .mv-toolbar .seg { display: none; } }

.tile {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden;
  display: flex; flex-direction: column;
}
.tile.is-offline { border-color: rgba(220,76,76,.35); }
.tile-head {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 11px; border-bottom: 1px solid var(--border);
}
.tile-head .name { font-size: 13px; font-weight: 600; }
.tile-head .name small { color: var(--muted); font-weight: 400; margin-left: 5px; }
.tile-head .acts { margin-left: auto; display: flex; gap: 4px; }
.iconbtn {
  width: 28px; height: 28px; display: grid; place-items: center;
  background: none; border: 1px solid transparent; border-radius: 7px;
  color: var(--muted); cursor: pointer; transition: color .15s, background .15s;
}
.iconbtn:hover { color: var(--ink); background: var(--surface-2); }
.iconbtn[aria-pressed="true"] { color: var(--brand); background: var(--brand-dim); border-color: rgba(218,165,33,.3); }
.iconbtn svg { width: 15px; height: 15px; }

.tile-video {
  position: relative; background: #000;
  aspect-ratio: 16 / 9; overflow: hidden;
  transition: height .2s ease;
}
/* Sin video, reservar 16:9 sería regalar media pantalla a un rectángulo
   negro. El bloque se encoge a la altura del dato y la cuadrícula deja ver
   muchos más streams de un vistazo. */
.tile-video.sin-video { aspect-ratio: auto; height: 128px; }
.tile-video video { width: 100%; height: 100%; object-fit: contain; display: block; background: #000; }
/* El <video> del transporte que se está probando antes de relevar al que está
   en pantalla: mismo hueco, encima, pero invisible hasta que reproduce. No se
   oculta con display:none ni con hidden porque un elemento sin caja puede no
   decodificar nada, y entonces nunca llegaría a reproducir ni habría relevo. */
.tile-video video.calentando {
  position: absolute; inset: 0; opacity: 0; pointer-events: none;
}
.tile-video .placeholder {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 9px;
  color: var(--muted); font-size: 12px; text-align: center; padding: 14px;
}
.tile-video .placeholder .big {
  font-size: 34px; font-weight: 600; color: var(--ink); letter-spacing: -.01em;
}
.tile-video .placeholder .big .u { font-size: .4em; color: var(--muted); margin-left: 3px; font-weight: 500; }
.tile-video .vstate {
  position: absolute; left: 9px; top: 9px;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px; border-radius: 999px;
  background: rgba(0,0,0,.6); backdrop-filter: blur(4px);
  font-size: 10.5px; font-weight: 600; letter-spacing: .04em;
}
.tile-video .vmode {
  position: absolute; right: 9px; top: 9px;
  padding: 3px 8px; border-radius: 999px;
  background: rgba(0,0,0,.6); backdrop-filter: blur(4px);
  font-size: 10.5px; color: var(--ink-2); letter-spacing: .04em;
}
.tile-video .spinner {
  width: 22px; height: 22px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,.15); border-top-color: var(--brand);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.tile-kpis {
  display: grid; grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--border);
}
.tile-kpis > div { padding: 8px 10px; border-right: 1px solid var(--border); min-width: 0; }
.tile-kpis > div:last-child { border-right: 0; }
.tile-kpis .k { font-size: 10px; color: var(--muted); letter-spacing: .02em; white-space: nowrap;
                overflow: hidden; text-overflow: ellipsis; }
.tile-kpis .v { font-size: 15px; font-weight: 600; letter-spacing: -.01em; }
.tile-kpis .v .u { font-size: .62em; color: var(--muted); font-weight: 500; margin-left: 2px; }
/* A una columna, cuatro celdas dejan ~60 px útiles por dato: "Pérdida 60 s" se
   recortaba a "Pérdid…". El dato importa más que la fila. */
@media (max-width: 560px) {
  .tile-kpis { grid-template-columns: repeat(2, 1fr); }
  .tile-kpis > div:nth-child(2n) { border-right: 0; }
  .tile-kpis > div:nth-child(-n+2) { border-bottom: 1px solid var(--border); }
  .tile-kpis .k { font-size: 11px; }
}

.mv-outputs { margin-top: 18px; }
/* El `min(…, 100%)` de todas las rejillas de esta hoja no es adorno: sin él,
   `auto-fit`/`auto-fill` nunca encogen la pista por debajo del mínimo fijo y
   la cuadrícula desborda el contenedor en cuanto la pantalla es más estrecha
   que ese número. */
.out-strip { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(min(250px, 100%), 1fr)); }
.out-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 11px 13px;
}
.out-card .top { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.out-card .who { font-size: 13px; font-weight: 600; }
.out-card .who small { display: block; font-size: 11px; color: var(--muted); font-weight: 400; }
.out-card .nums { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(90px, 100%), 1fr)); gap: 8px; }
.out-card .nums div { min-width: 0; }
.out-card .nums .k { font-size: 10px; color: var(--muted); }
.out-card .nums .v { font-size: 13.5px; font-weight: 600; }
.out-card .nums .v .u { font-size: .68em; color: var(--muted); font-weight: 500; margin-left: 2px; }

/* ══════════════════════════════════════════════ envíos a RTMP

   Una tarjeta por destino en vez de una fila de tabla: cada destino lleva un
   interruptor, un estado que cambia solo y a veces un renglón de error de la
   plataforma. Todo eso apretado en celdas se vuelve ilegible justo cuando
   más urge leerlo, que es cuando algo se cayó en mitad del partido. */

.env-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr)); }

.env-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 13px 15px 12px;
  display: flex; flex-direction: column; gap: 10px;
}
/* El borde de la izquierda es redundante con el estado escrito, a propósito:
   de reojo, desde lejos, la franja dice si algo está mal antes de leer. */
.env-card.al-aire { border-left: 2px solid var(--good); }
.env-card.con-fallo { border-left: 2px solid var(--critical); }

.env-card .top { display: flex; align-items: flex-start; gap: 9px; }
.env-card .who { min-width: 0; flex: 1; }
.env-card .who b { display: block; font-size: 13.5px; font-weight: 600; }
.env-card .who small {
  display: block; font-size: 11px; color: var(--muted); font-weight: 400;
  margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.env-card .nums { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(90px, 100%), 1fr)); gap: 8px; }
.env-card .nums div { min-width: 0; }
.env-card .nums .k { font-size: 10px; color: var(--muted); }
.env-card .nums .v { font-size: 14px; font-weight: 600; }
.env-card .nums .v .u { font-size: .68em; color: var(--muted); font-weight: 500; margin-left: 2px; }

.env-card .motivo {
  font-size: 11.5px; line-height: 1.45; color: var(--ink-2);
  background: var(--surface-2); border-radius: 7px;
  border-left: 2px solid var(--critical);
  padding: 7px 9px; margin: 0;
  word-break: break-word;
}
/* Emitiendo, el renglón no es un fallo sino una advertencia: la señal salió,
   pero no idéntica a como entró. Rojo aquí sería mentir. */
.env-card .motivo.aviso { border-left-color: var(--warning); color: var(--muted); }
.env-card .acts { display: flex; gap: 6px; align-items: center; }
.env-card .acts .sep { margin-left: auto; }

.env-log summary {
  cursor: pointer; font-size: 11.5px; color: var(--muted);
  list-style: none; user-select: none;
}
.env-log summary::-webkit-details-marker { display: none; }
.env-log summary::before { content: "▸ "; }
.env-log[open] summary::before { content: "▾ "; }
.env-log summary:hover { color: var(--ink-2); }
.env-log pre {
  margin: 8px 0 0; padding: 9px 10px;
  background: var(--plane); border: 1px solid var(--border); border-radius: 7px;
  font-size: 11px; line-height: 1.5; color: var(--ink-2);
  /* El registro de ffmpeg trae líneas larguísimas. Que se desplace dentro de
     su caja en vez de ensanchar la tarjeta y descuadrar toda la cuadrícula. */
  max-height: 190px; overflow: auto;
  white-space: pre; tab-size: 2;
}

/* Marca de plataforma. Sin logotipos: son marcas registradas y en un panel
   interno no aportan nada que el nombre no diga. */
.env-plat {
  display: inline-flex; align-items: center; height: 20px; padding: 0 8px;
  border-radius: 999px; font-size: 10.5px; font-weight: 600; letter-spacing: .03em;
  text-transform: uppercase; border: 1px solid var(--border); color: var(--muted);
  flex: none;
}
.env-plat.p-facebook { color: #8fb4f0; background: rgba(75,125,234,.1); border-color: rgba(75,125,234,.3); }
.env-plat.p-youtube  { color: #f09a9a; background: rgba(220,76,76,.09); border-color: rgba(220,76,76,.3); }
.env-plat.p-twitch   { color: #bfa3f0; background: rgba(145,110,230,.1); border-color: rgba(145,110,230,.3); }

/* ══════════════════════════════════════════════ monitor (gráficas) */

.kpis {
  display: grid; gap: 12px; margin-bottom: 12px;
  grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
}
.kpi .row { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; }
.kpi .val { font-size: 27px; font-weight: 600; line-height: 1.05; letter-spacing: -.015em; }
.kpi.hero .val { font-size: 44px; }
.kpi .val .u { font-size: .46em; font-weight: 500; color: var(--muted); margin-left: 3px; }
.kpi .state { margin-top: 5px; }
svg.spark { display: block; width: 92px; height: 32px; flex: none; overflow: hidden; }

.meter-card { margin-bottom: 12px; }
.meter-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-top: 10px; }
.meter-head .num { font-size: 21px; font-weight: 600; }
.meter-head .num .u { font-size: .55em; color: var(--muted); font-weight: 500; margin-left: 2px; }
.meter-head .lim { font-size: 12px; color: var(--muted); margin-left: auto; }
.track {
  position: relative; height: 9px; border-radius: 5px; margin-top: 10px;
  background: #17181c; box-shadow: inset 0 0 0 1px var(--border-soft); overflow: hidden;
}
.track .fill {
  height: 100%; width: 0; border-radius: 5px 0 0 5px; background: var(--s1);
  transition: width .35s ease, background .35s ease;
}
.track .fill.r-warning { background: var(--warning); }
.track .fill.r-bad { background: var(--critical); }
.scale { display: flex; justify-content: space-between; margin-top: 5px; font-size: 11px; color: var(--muted); }

.charts { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr)); }
.chart-card { position: relative; }
.chart-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 6px; }
.legend { display: flex; gap: 12px; flex-wrap: wrap; margin-left: auto; font-size: 11px; color: var(--ink-2); }
.legend span { display: inline-flex; align-items: center; gap: 5px; }
.legend i { width: 10px; height: 2px; border-radius: 1px; flex: none; }
.chart-card svg { display: block; width: 100%; height: auto; overflow: hidden; }
.tip {
  position: absolute; pointer-events: none; opacity: 0; transition: opacity .12s;
  background: var(--plane); border: 1px solid var(--border); border-radius: 6px;
  padding: 6px 9px; font-size: 11.5px; color: var(--ink-2);
  white-space: nowrap; z-index: 5; box-shadow: 0 4px 14px rgba(0,0,0,.6);
}
.tip.show { opacity: 1; }
.tip .t { color: var(--muted); }
.tip .k { display: flex; align-items: center; gap: 6px; }
.tip .k i { width: 8px; height: 8px; border-radius: 2px; flex: none; }
.tip b { color: var(--ink); font-weight: 600; }

.facts-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); margin-top: 12px; }
dl.facts { margin: 7px 0 0; display: grid; grid-template-columns: auto 1fr; gap: 5px 14px; font-size: 12.5px; }
dl.facts dt { color: var(--muted); }
dl.facts dd { margin: 0; color: var(--ink-2); }

/* ══════════════════════════════════════════════ tablas */

.scroller { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
table { border-collapse: collapse; width: 100%; font-size: 12.5px; }
th, td { padding: 9px 13px; text-align: right; white-space: nowrap; }
th:first-child, td:first-child { text-align: left; }
thead th {
  color: var(--muted); font-weight: 500; font-size: 11.5px;
  border-bottom: 1px solid var(--axis); position: sticky; top: 0;
  background: var(--surface); z-index: 1;
}
tbody tr + tr td { border-top: 1px solid var(--grid); }
tbody td { color: var(--ink-2); }
tbody tr:hover td { background: rgba(255,255,255,.02); }
td .who b { color: var(--ink); font-weight: 600; display: block; }
td .who small { display: block; font-size: 11px; }
td .actions { display: flex; gap: 6px; justify-content: flex-end; }

.chip {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 500;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--ink-2);
}
.chip.role-admin { color: var(--brand-soft); background: var(--brand-dim); border-color: rgba(218,165,33,.3); }
.chip.role-operador { color: #8fc0f0; background: rgba(75,159,234,.1); border-color: rgba(75,159,234,.3); }
.chip.role-cliente { color: #86ceb0; background: rgba(55,185,138,.1); border-color: rgba(55,185,138,.3); }
.chip.role-invitado { color: var(--muted); }
.chip.off { color: var(--critical); background: rgba(220,76,76,.09); border-color: rgba(220,76,76,.3); }

/* ══════════════════════════════════════════════ modal */

.modal-bg {
  display: none; position: fixed; inset: 0; z-index: 60;
  background: rgba(0,0,0,.65); backdrop-filter: blur(3px);
  padding: 22px; overflow-y: auto;
}
.modal-bg.open { display: grid; place-items: start center; }
.modal {
  width: 100%; max-width: 470px; margin-top: 6vh;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 13px; padding: 20px 22px 18px;
  box-shadow: 0 24px 60px rgba(0,0,0,.7);
}
.modal h2 { margin: 0 0 3px; font-size: 15px; font-weight: 600; }
.modal .sub { margin: 0 0 16px; font-size: 12px; color: var(--muted); }
.modal .row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.modal .foot { display: flex; gap: 9px; justify-content: flex-end; margin-top: 18px; }
@media (max-width: 560px) {
  .modal .row { grid-template-columns: 1fr; }
  .modal-bg { padding: 12px; }
  .modal { margin-top: 3vh; padding: 18px 16px 16px; }
}
/* En un teléfono, dos botones en fila dejan el primario pegado al borde y con
   la mitad del ancho de golpe. Apilados, el primario queda arriba y a lo ancho. */
@media (max-width: 420px) {
  .modal .foot { flex-direction: column-reverse; }
  .modal .foot .btn { width: 100%; }
}

.checks { display: flex; flex-wrap: wrap; gap: 7px; }
.checks label {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 11px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface-2); font-size: 12.5px; cursor: pointer;
}
.checks label:hover { border-color: #3a3a3a; }
.checks input { accent-color: var(--brand); margin: 0; }
.checks label:has(input:checked) {
  border-color: rgba(218,165,33,.45); background: var(--brand-dim); color: var(--brand-soft);
}

/* ══════════════════════════════════════════════ pantalla completa */

.tile:fullscreen { border-radius: 0; border: 0; }
.tile:fullscreen .tile-video { aspect-ratio: auto; flex: 1; }
.tile:fullscreen .tile-video video { object-fit: contain; }

/* ══════════════════════════════════════════════ cabina de comentaristas */

.cab-layout {
  display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 14px;
  align-items: start;
}
/* Al colapsar a una columna, el panel caía debajo del video: en un teléfono
   eso deja "Salir al aire" —el control de la vista— bajo el pliegue. Sube. */
@media (max-width: 860px) {
  .cab-layout { display: flex; flex-direction: column; }
  .cab-panel { order: -1; }
}

.cab-video {
  position: relative; background: #000; border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden; aspect-ratio: 16 / 9;
}
.cab-video video { width: 100%; height: 100%; object-fit: contain; display: block; background: #000; }
.cab-video .placeholder {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 8px;
  font-size: 12.5px; color: var(--muted); text-align: center; padding: 0 18px;
}
.cab-video .vstate {
  position: absolute; left: 10px; bottom: 10px; font-size: 11px;
  font-weight: 600; letter-spacing: .04em; background: rgba(0,0,0,.65);
  padding: 4px 9px; border-radius: 7px;
}

.cab-panel { display: flex; flex-direction: column; gap: 12px; }
.cab-panel .card h2 { margin: 0 0 10px; font-size: 12.5px; font-weight: 600; }
.cab-hint { margin: 10px 0 0; font-size: 12px; color: var(--muted); line-height: 1.5; }
.cab-hint b { color: var(--ink-2); }

/* El medidor del micrófono: la voz ANTES de salir a la red. */
.vu {
  height: 10px; border-radius: 6px; background: var(--surface-2);
  border: 1px solid var(--border); overflow: hidden; margin-bottom: 12px;
}
.vu-fill {
  height: 100%; width: 0%; border-radius: 6px;
  background: linear-gradient(90deg, var(--good), #9ec93a 70%, var(--warning));
  transition: width 60ms linear;
}
.vu-fill.alto { background: var(--critical); }

/* Los faders de monitoreo de la cabina. Van en columna —no en la rejilla de
   tres columnas de la mezcla— porque el panel mide 300 px: con el nombre al
   lado, al deslizador le quedarían cuarenta píxeles útiles. */
.cab-fila {
  display: grid; grid-template-columns: minmax(0, 1fr) 46px;
  column-gap: 10px; align-items: center; padding: 4px 0 10px;
}
.cab-fila + .cab-fila { border-top: 1px solid var(--border-soft); padding-top: 10px; }
.cab-fila label {
  grid-column: 1 / -1; font-size: 12.5px; font-weight: 600; margin-bottom: 7px;
}
.cab-fila label small { font-weight: 400; font-size: 10.5px; color: var(--muted); }
.cab-fila input[type="range"] { width: 100%; accent-color: var(--brand); }
.cab-pct { font-size: 12px; color: var(--ink-2); text-align: right; }

/* El botón de la cabina es EL control: grande, inequívoco y con el estado
   escrito, nunca solo con color. */
.btn-aire {
  width: 100%; padding: 14px 12px; border-radius: 10px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface-2);
  color: var(--ink); font-weight: 700; font-size: 14px; letter-spacing: .02em;
  margin-bottom: 10px;
}
.btn-aire:hover { border-color: #3a3a3a; }
.btn-aire.conectando { color: var(--warning); border-color: rgba(226,128,47,.4); }
.btn-aire.en-aire {
  background: rgba(220,76,76,.12); border-color: var(--critical);
  color: #f09a9a;
}
@keyframes aire-pulso { 50% { box-shadow: 0 0 0 5px rgba(220,76,76,.10); } }
.btn-aire.en-aire { animation: aire-pulso 2s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .btn-aire.en-aire { animation: none; } }

/* ══════════════════════════════════════════════ programa (mezcla) */

.env-plat.p-programa { color: var(--brand-soft); background: var(--brand-dim); border-color: rgba(218,165,33,.35); }
.env-plat.p-cabina   { color: #86ceb0; background: rgba(55,185,138,.1); border-color: rgba(55,185,138,.3); }

.mez-voces { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.chip.conectado { color: #8fc0f0; background: rgba(75,159,234,.1); border-color: rgba(75,159,234,.3); }
.chip.en-mezcla { color: #86ceb0; background: rgba(55,185,138,.1); border-color: rgba(55,185,138,.35); }

.mez-fila {
  display: grid; grid-template-columns: 200px minmax(0, 1fr) 52px;
  gap: 12px; align-items: center; padding: 7px 0;
  border-bottom: 1px solid var(--border-soft);
}
.mez-fila:last-of-type { border-bottom: 0; }
.mez-nombre { font-size: 12.5px; font-weight: 600; min-width: 0; }
.mez-nombre small { display: block; font-size: 10.5px; color: var(--muted); font-weight: 400; }
.mez-fila input[type="range"] { width: 100%; accent-color: var(--brand); }
.mez-pct { font-size: 12px; color: var(--ink-2); text-align: right; }
@media (max-width: 560px) { .mez-fila { grid-template-columns: 110px 1fr 44px; } }

.mez-aplicar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-top: 12px; justify-content: flex-end;
}
.mez-retraso { font-size: 12px; color: var(--muted); display: inline-flex; align-items: center; gap: 7px; }
.mez-retraso input {
  width: 76px; height: 28px; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 7px; padding: 0 8px;
  font-size: 12px; text-align: right;
}

/* ══════════════════════════════════════════════ adaptación transversal

   Tres ejes que no dependen del ancho de la ventana y por eso van aparte:
   el zoom forzado de Safari, el tamaño del dedo y la preferencia de
   movimiento. Una tablet de 1024 px que se toca necesita lo mismo que un
   teléfono, así que colgar esto de un punto de corte de ancho sería un error. */

/* Safari en iOS amplía la página al enfocar cualquier campo de menos de 16 px,
   y como el viewport no lleva `maximum-scale` —correctamente—, se queda
   ampliada hasta que el usuario vuelve a pellizcar. */
@media (max-width: 860px) {
  .field input, .field select, .field textarea,
  input[type="text"], input[type="password"], input[type="number"],
  input[type="date"], input[type="email"], select, textarea { font-size: 16px; }
}

/* Se agranda el área de golpe sin tocar el escritorio: la densidad alta del
   panel es una decisión deliberada de sala de control, no un descuido. */
@media (pointer: coarse) {
  .iconbtn { width: 44px; height: 44px; }
  .iconbtn svg { width: 18px; height: 18px; }
  .btn { min-height: 44px; }
  .btn-sm, .seg button { min-height: 40px; padding-inline: 15px; }
  .usermenu > button { min-height: 44px; }
  .menu button { padding: 12px 11px; }
  .checks label { padding: 10px 13px; }
  .mez-retraso input { height: 40px; }
  .env-log summary { padding: 10px 0; }
}

img, video { max-width: 100%; }

@media (prefers-reduced-motion: reduce) {
  .tile-video .spinner { animation: none; }
  .track .fill { transition: none; }
}
