/* ============================================================
   ControlCenter · Cuberis — Analíticas
   Diseño «Bento compacto» — variante «Más legible».
   Ported verbatim from docs/mockups/analytics-2026-07-19/definitivo.html,
   split from its :root (see tokens.css). The only substantive change is
   that the sticky topbar/subnav and the ⌘K backdrop no longer use any CSS
   blur/glass effect — the panel is flat and bordered, not glassmorphism
   (WebAssetsTest enforces this). Currency-compat + loading/error styles
   are appended at the end.
   ============================================================ */
*,*::before,*::after{ box-sizing:border-box; }
/* El atributo hidden SIEMPRE gana: cualquier regla de display de una clase (flex/inline-flex/grid)
   pisaría el [hidden] del navegador y el elemento «oculto» seguiría visible (pasó con .zreset y con
   los fgroup de filtros al compartir la subnav entre módulos). */
[hidden]{ display:none !important; }
html,body{ height:100%; }
/* La página del panel no desplaza nunca el documento: .main tiene su propio scroll. Sin esto, la rueda al
   final de una vista larga arrastraba también la barra lateral hacia arriba. */
body:has(> .app){ overflow:hidden; }
/* Escala del panel. Todo se mide en rem, así que el tamaño de la raíz escala el panel entero (texto,
   márgenes, tarjetas y gráficas) a la vez: una pantalla de 2560 o 4K al 100 % ve el panel a un tamaño
   legible y lleno, en vez de diminuto y con huecos. Por tramos, no fluido: dentro de un tramo nada cambia
   al redimensionar. Las líneas finas (1–2 px) se quedan en px. */
html{ font-size:16px; }
@media (min-width:1800px){ html{ font-size:17px; } }
@media (min-width:2200px){ html{ font-size:19px; } }
@media (min-width:2500px){ html{ font-size:21px; } }
@media (min-width:3000px){ html{ font-size:23px; } }
@media (min-width:3600px){ html{ font-size:25px; } }
body{ margin:0; background:var(--bg); color:var(--ink-1); font-family:var(--font);
  font-size:0.9062rem; line-height:1.46; -webkit-font-smoothing:antialiased; }
button{ font:inherit; color:inherit; background:none; border:0; cursor:pointer; }
a{ color:inherit; text-decoration:none; }
h1,h2,h3,h4,p{ margin:0; }
.tnum{ font-variant-numeric:tabular-nums; }
:focus-visible{ outline:2px solid var(--brand); outline-offset:2px; border-radius:var(--r-5); }
:focus:not(:focus-visible){ outline:none; }
.ico{ width:1.0625rem; height:1.0625rem; flex:none; fill:none; stroke:currentColor; stroke-width:1.75;
  stroke-linecap:round; stroke-linejoin:round; }

.app{ display:flex; height:100dvh; overflow:hidden; }

/* ---------------------------------------- barra lateral */
.side{ width:var(--side-w); flex:0 0 auto; display:flex; flex-direction:column;
  background:var(--surface-2); border-right:1px solid var(--hair); overflow:hidden; }
.side-head{ display:flex; align-items:center; gap:0.625rem; padding:1rem 0.9375rem 0.75rem; min-height:3.75rem; }
.logo{ width:1.625rem; height:1.625rem; flex:none; }
.brand-txt strong{ display:block; font-size:0.9062rem; font-weight:650; letter-spacing:-.01em; }
.brand-txt span{ display:block; font-size:0.7188rem; color:var(--ink-3); }
.search-wrap{ padding:0 0.8125rem 0.8125rem; }
.search{ display:flex; align-items:center; gap:0.5rem; height:2.1875rem; padding:0 0.625rem; width:100%;
  background:var(--surface-3); border:1px solid var(--hair); border-radius:var(--r-md);
  color:var(--ink-3); cursor:pointer; transition:border-color .15s, background .15s; }
.search:hover{ border-color:rgba(0,180,255,.45); color:var(--ink-2); }
.search .kbd{ margin-left:auto; }
.kbd{ font-family:var(--mono); font-size:0.6562rem; color:var(--ink-3);
  border:1px solid var(--hair); border-radius:var(--r-4); padding:1px 0.3125rem; background:rgba(255,255,255,.03); }
.nav-list{ flex:1; min-height:0; overflow-y:auto; padding:2px 0.8125rem 0.5rem;
  scrollbar-width:thin; scrollbar-color:rgba(255,255,255,.13) transparent; }
.sec-h{ padding:1rem 0.625rem 0.375rem; font-size:0.75rem; font-weight:500;
  color:var(--ink-3); display:flex; align-items:center; gap:0.5rem; }
.sec-h b{ margin-left:auto; font-size:0.75rem; color:var(--ink-3); font-weight:500; font-variant-numeric:tabular-nums; }
.nav-a{ display:flex; align-items:center; gap:0.625rem; padding:0.4375rem 0.625rem; margin-bottom:1px;
  border-radius:var(--r-md); color:var(--ink-2); font-size:0.875rem; font-weight:500;
  transition:background .12s, color .12s; }
.nav-a .ico{ color:var(--ink-3); transition:color .12s; }
.nav-a:hover{ background:rgba(255,255,255,.04); color:var(--ink-1); }
.nav-a:hover .ico{ color:var(--ink-2); }
/* El activo es un relleno neutro, sin color de marca: el acento queda para los datos. */
.nav-a[aria-current="page"]{ background:var(--surface-3); color:var(--ink-1); }
.nav-a[aria-current="page"] .ico{ color:var(--ink-1); }
.nav-a .lbl{ flex:1; }
.nav-a .gem-ico{ color:var(--gem); opacity:.85; }
.no-hits{ padding:0.625rem 0.625rem; font-size:0.8125rem; color:var(--ink-3); }
.side-foot{ display:flex; align-items:center; gap:0.625rem; padding:0.6875rem 0.8125rem; border-top:1px solid var(--hair); }
.avatar{ width:1.875rem; height:1.875rem; flex:none; border-radius:var(--r-pill);
  background:var(--avatar-1); display:grid; place-items:center;
  font-size:0.75rem; font-weight:700; color:var(--avatar-ink); }
.avatar .ini,.avatar-lg .ini{ display:block; line-height:1; }
.who{ flex:1; min-width:0; }
.who strong{ display:block; font-size:0.8125rem; font-weight:600; white-space:nowrap; }
.who span{ display:block; font-size:0.7188rem; color:var(--ink-3); white-space:nowrap; }
.icon-btn{ display:grid; place-items:center; width:1.875rem; height:1.875rem; flex:none;
  border-radius:var(--r-sm); color:var(--ink-3); transition:background .12s, color .12s; }
.icon-btn:hover{ background:rgba(255,255,255,.06); color:var(--ink-1); }

/* ---------------------------------------- columna principal */
.main{ flex:1; min-width:0; overflow-y:auto; display:flex; flex-direction:column;
  scroll-behavior:smooth; scrollbar-width:thin; scrollbar-color:rgba(255,255,255,.13) transparent; }
.topbar{ position:sticky; top:0; z-index:20; display:flex; align-items:center; gap:0.875rem;
  padding:0.75rem 1.375rem; min-height:3.625rem; background:var(--bg);
  border-bottom:1px solid var(--hair); }
.topbar h1{ font-size:1.125rem; font-weight:650; letter-spacing:-.015em; line-height:1.3; }
.topbar .sub{ font-size:0.8125rem; color:var(--ink-3); }
.top-actions{ margin-left:auto; display:flex; align-items:center; gap:0.5625rem; }
.updated{ font-size:0.75rem; color:var(--ink-3); white-space:nowrap; }
.btn-ghost{ display:grid; place-items:center; width:2rem; height:2rem; border:1px solid var(--hair);
  border-radius:var(--r-md); background:var(--surface-1); color:var(--ink-2);
  transition:background .12s, color .12s; }
.btn-ghost:hover{ background:var(--surface-3); color:var(--ink-1); }

/* nav de secciones (seg desplazable) + filtros */
.subnav{ position:sticky; top:3.625rem; z-index:19; background:var(--bg);
  border-bottom:1px solid var(--hair); padding:0.6875rem 1.375rem 0.625rem; display:flex; align-items:center; gap:0.875rem; flex-wrap:wrap; }
.subnav[hidden]{ display:none; }
/* subnav desplazable: cuando las 9 pestañas desbordan aparece un scrollbar fino
   del tema (afordancia descubrible); cuando caben, el navegador no lo muestra. */
.segwrap{ overflow-x:auto; max-width:100%; scrollbar-width:thin; scrollbar-color:var(--surface-4) transparent; }
.segwrap::-webkit-scrollbar{ height:0.375rem; }
.segwrap::-webkit-scrollbar-thumb{ background:var(--surface-4); border-radius:var(--r-pill); }
.seg{ display:inline-flex; gap:2px; padding:0.1875rem; background:var(--surface-3);
  border:1px solid var(--hair); border-radius:var(--r-11); }
.seg button{ padding:0.375rem 0.75rem; border-radius:var(--r-8); font-size:0.8438rem; font-weight:500;
  color:var(--ink-2); white-space:nowrap; transition:background .12s, color .12s; }
.seg button:hover{ color:var(--ink-1); background:rgba(255,255,255,.04); }
.seg button[aria-selected="true"]{ background:var(--surface-4); color:var(--ink-1); font-weight:600; }
.filters{ margin-left:auto; display:flex; align-items:center; gap:0.75rem; flex-wrap:wrap; }
.fgroup{ display:inline-flex; align-items:center; gap:0.5rem; }
.flab{ font-size:0.75rem; color:var(--ink-3); font-weight:500; }
.pillset{ display:inline-flex; gap:2px; padding:2px; border:1px solid var(--hair);
  border-radius:var(--r-md); background:var(--surface-1); }
.pillset button{ padding:0.3125rem 0.625rem; border-radius:var(--r-6); font-size:0.7812rem; font-weight:500;
  color:var(--ink-3); white-space:nowrap; transition:background .12s, color .12s; }
.pillset button:hover{ color:var(--ink-1); }
.pillset button[aria-selected="true"]{ background:var(--surface-3); color:var(--ink-1); }

/* ---------------------------------------- contenido */
.content{ width:100%; padding:1.25rem 1.5rem 3.5rem; display:flex; flex-direction:column; gap:1.25rem; }
.view[hidden]{ display:none; }
/* Una vista aparece en su sitio, sin entrada animada: en un panel que se mira todo el día, el movimiento
   es respuesta a una acción, no decoración. Un gap único (1rem) separa todos los bloques de una vista. */
.view{ display:flex; flex-direction:column; gap:1rem; }
.view.noanim, .view.noanim *{ animation:none !important; }

/* cabecera de sección — compacta */
.secrow{ display:flex; align-items:baseline; gap:0.75rem; padding:1px 1px 2px; }
.secrow h2{ font-size:1.0312rem; font-weight:680; letter-spacing:-.015em; color:var(--ink-1); }
.secrow .desc{ font-size:0.8125rem; color:var(--ink-3); }
.secrow .live{ margin-left:auto; }
.live{ display:inline-flex; align-items:center; gap:0.375rem; font-size:0.75rem; color:var(--ink-3); white-space:nowrap; }
/* Punto de estado plano, sin halo: verde mientras el auto-refresco trae datos. */
.pulse{ width:0.4375rem; height:0.4375rem; border-radius:var(--r-pill); background:var(--good); flex:none; }

/* ---- rejilla bento de 12 columnas ---- */
.bento{ display:grid; grid-template-columns:repeat(12,1fr); gap:1rem; }
.s3{ grid-column:span 3; } .s4{ grid-column:span 4; } .s5{ grid-column:span 5; }
.s6{ grid-column:span 6; } .s7{ grid-column:span 7; } .s8{ grid-column:span 8; }
.s9{ grid-column:span 9; } .s12{ grid-column:span 12; }
/* Los anchos (s7/s8/s9) van a fila completa pronto; los medios (s6) y tercios (s3/s4) aguantan
   dos-columnas hasta 1024px para que un portátil típico (1180–1280) no vea Resumen en una tira alta. */
@media(max-width:1180px){ .s7,.s8,.s9{ grid-column:span 12; } .s3,.s4,.s5{ grid-column:span 6; } }
@media(max-width:1024px){ .s6{ grid-column:span 12; } }
@media(max-width:640px){ .bento > *{ grid-column:span 12 !important; } }

/* ---- tira de KPI: celdas unidas por hairlines (bento) ---- */
.kstrip{ display:grid; gap:1px; background:var(--hair); border:1px solid var(--hair);
  border-radius:var(--r-card); overflow:hidden; }
.kstrip.c4{ grid-template-columns:repeat(4,1fr); }
.kstrip.c3{ grid-template-columns:repeat(3,1fr); }
@media(max-width:960px){ .kstrip.c4,.kstrip.c3{ grid-template-columns:repeat(2,1fr); } }
/* En móvil dos columnas (una sola apilaba ocho cifras en una tira de pantalla y media); solo por
   debajo de 21.25rem pasa a una. Igual en todos los módulos: no hay variante de KPI por módulo. */
@media(max-width:520px){
  .kstrip.c4,.kstrip.c3{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .kcell{ padding:0.75rem 0.8125rem 0.8125rem; }
  .kv{ font-size:1.375rem; }
}
@media(max-width:340px){ .kstrip.c4,.kstrip.c3{ grid-template-columns:1fr; } }
/* Una cifra es tipo, no una tesela: etiqueta gris arriba, valor en tinta, contexto debajo. Sin icono ni
   hover (la celda no es interactiva y no debe parecerlo). */
.kcell{ background:var(--surface-1); padding:0.9375rem 1.125rem 1rem; display:flex; flex-direction:column; gap:0.3125rem;
  position:relative; min-width:0; }
/* Atención: un punto ámbar delante de la etiqueta. Señala sin enmarcar la celda (el anillo de antes se
   leía como un foco o una selección). */
.kcell.attn .kl::before{ content:""; width:0.4375rem; height:0.4375rem; flex:none; border-radius:var(--r-pill); background:var(--warn); }
.kl{ display:flex; align-items:center; gap:0.4375rem; font-size:0.8125rem; color:var(--ink-2); font-weight:500; min-width:0; }
.kl .ico{ display:none; }
.kv{ font-size:1.625rem; font-weight:620; letter-spacing:-.02em; line-height:1.1; font-variant-numeric:tabular-nums; }
.kv .ku{ font-size:0.8125rem; font-weight:500; color:var(--ink-3); letter-spacing:0; margin-left:0.1875rem; }
.kc{ display:flex; align-items:center; flex-wrap:wrap; gap:0.25rem 0.375rem; min-height:1.25rem; font-size:0.75rem; color:var(--ink-3); }
.kc b{ color:var(--ink-1); font-weight:600; font-variant-numeric:tabular-nums; }

/* delta: el número lleva el color de su sentido; sin píldora, la ventana va en palabras al lado. */
.dl{ display:inline-flex; align-items:center; gap:2px; font-weight:600; font-size:0.75rem;
  font-variant-numeric:tabular-nums; }
.dl.up{ color:var(--pos); }
.dl.dn{ color:var(--serious); }
.dl.flat{ color:var(--ink-2); }
.dl .ico{ width:0.6875rem; height:0.6875rem; stroke-width:2.4; }

/* ---- tarjeta-compartimento ---- */
/* Superficie plana: un borde fino y un escalón de tono sobre el fondo, sin sombra en reposo ni reacción
   al pasar el ratón (una tarjeta no es un botón). */
.card{ background:var(--surface-1); border:1px solid var(--hair); border-radius:var(--r-card);
  display:flex; flex-direction:column; overflow:hidden; min-width:0; }
.ch{ display:flex; align-items:center; flex-wrap:wrap; gap:0.5rem 0.75rem; padding:0.75rem 1.125rem; border-bottom:1px solid var(--hair);
  min-height:3rem; box-sizing:border-box; }
.ch h3{ font-size:0.9375rem; font-weight:620; letter-spacing:-.01em; color:var(--ink-1); }
.ch .sub{ font-size:0.75rem; color:var(--ink-3); margin-top:1px; }
.ch .r{ margin-left:auto; display:flex; align-items:center; flex-wrap:wrap; justify-content:flex-end; gap:0.5rem; }
.cb{ padding:1rem 1.125rem; flex:1; min-height:0; }
.cb.pad0{ padding:0; }
.cb.tight{ padding:0.6875rem 1.125rem; }

/* mini stat inline (dentro de tarjeta) */
.miniStats{ display:grid; grid-auto-flow:column; gap:1px; background:var(--hair); border-radius:var(--r-md);
  overflow:hidden; border:1px solid var(--hair); }
.miniStats .ms{ background:var(--surface-1); padding:0.5625rem 0.75rem; }
.ms .l{ font-size:0.7188rem; color:var(--ink-3); }
.ms .v{ font-size:1rem; font-weight:650; margin-top:1px; letter-spacing:-.02em; font-variant-numeric:tabular-nums; }

/* chart */
.chart-svg{ display:block; width:100%; height:auto; }
.chart-svg text{ font-family:var(--font); }
/* Contenedor de lienzo de Chart.js: la relación de aspecto la fija la ALTURA del wrapper
   (el canvas no lleva height), y Chart.js llena el ancho de forma responsive. */
.ccwrap{ position:relative; width:100%; }
.ccwrap canvas{ max-width:100%; display:block; }
/* Alternativa textual de una gráfica: oculta a la vista, disponible para el lector de pantalla. */
.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; }
.legendrow{ display:flex; align-items:center; gap:1rem; flex-wrap:wrap; padding:2px 1.0625rem 0.625rem; }
.lgd{ display:flex; align-items:center; gap:0.4375rem; font-size:0.8125rem; color:var(--ink-2); }
.lk{ width:0.875rem; height:0.1562rem; border-radius:var(--r-2); flex:none; }
.lk.dashed{ background:none; border-top:2px dashed var(--warn); height:0; }
.lgd b{ color:var(--ink-1); font-weight:650; font-variant-numeric:tabular-nums; }

/* botón «Restablecer selección» de las gráficas multi-serie (Rendimiento / Ancho) */
.zreset{ display:inline-flex; align-items:center; gap:0.3125rem; height:1.375rem; padding:0 0.5625rem; font-size:0.7188rem;
  font-weight:650; color:var(--ink-1); cursor:pointer; background:var(--surface-3);
  border:1px solid var(--hair-2); border-radius:var(--r-pill); transition:border-color .15s var(--ease); }
.zreset:hover{ border-color:var(--brand); }
.zreset .ico{ width:0.75rem; height:0.75rem; color:var(--ink-2); }

/* chips / dots */
.chip{ display:inline-flex; align-items:center; flex:none; gap:0.3125rem; height:1.375rem; padding:0 0.5rem; white-space:nowrap;
  border-radius:var(--r-pill); font-size:0.75rem; font-weight:550; background:rgba(255,255,255,.05);
  border:1px solid var(--hair); color:var(--ink-2);
  transition:background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease); }
/* Un estado sano no se pinta como una píldora: punto verde y texto neutro. Así una columna de «OK» no se
   lee como una franja de color y lo que sí es aviso (ámbar, rojo) destaca solo. */
.chip.good{ color:var(--ink-2); border-color:transparent; background:transparent; }
.chip.warn{ color:var(--warn); border-color:var(--warn-line); background:var(--warn-faint); }
.chip.crit{ color:var(--neg); border-color:var(--neg-line); background:var(--neg-faint); }
.dot{ width:0.4375rem; height:0.4375rem; border-radius:var(--r-pill); flex:none; display:inline-block; }
.dot.good{ background:var(--good);} .dot.warn{ background:var(--warn);}
.dot.crit{ background:var(--crit);} .dot.mute{ background:var(--ink-3);}

/* listas de barras compactas */
.bars{ display:flex; flex-direction:column; gap:0.6875rem; }
.bar{ display:grid; width:100%; grid-template-columns:6.25rem 1fr auto; align-items:center; gap:0.6875rem; text-align:left; }
.bar .nm{ font-size:0.8438rem; color:var(--ink-1); display:flex; align-items:center; gap:0.5rem; min-width:0; }
.bar .nm > span{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.trk{ height:0.375rem; border-radius:var(--r-pill); background:var(--surface-3); overflow:hidden; }
.trk i{ display:block; height:100%; border-radius:var(--r-pill); background:var(--s1); }
.trk i.g{ background:var(--s2); }
.trk i.o{ background:var(--serious); }
.bar .vv{ font-size:0.8438rem; font-weight:650; color:var(--ink-1); font-variant-numeric:tabular-nums; min-width:2.875rem; text-align:right; }
.fl{ font-family:var(--mono); font-size:0.6875rem; font-weight:700; color:var(--ink-3);
  border:1px solid var(--hair); border-radius:var(--r-4); padding:2px 0.25rem; flex:none; }

/* tablas compactas */
.tblwrap{ flex:1; min-height:0; overflow:auto; }
table{ width:100%; border-collapse:separate; border-spacing:0; font-size:0.875rem; }
/* Cabecera en minúsculas de frase, gris y en peso normal: más baja que los datos que rotula. */
thead th{ text-align:left; white-space:nowrap; font-size:0.75rem; font-weight:500;
  color:var(--ink-3); padding:0.625rem 1.125rem; background:var(--surface-1);
  border-bottom:1px solid var(--hair); position:sticky; top:0; z-index:1; }
thead th.sortable{ cursor:pointer; user-select:none; }
thead th.sortable:hover{ color:var(--ink-1); }
thead th .car{ opacity:.6; margin-left:0.1875rem; }
.sort-action{ display:inline-flex; align-items:center; color:inherit; font:inherit; letter-spacing:inherit;
  text-transform:inherit; white-space:inherit; }
.row-action{ display:flex; width:100%; align-items:center; color:inherit; text-align:left; }
tbody td{ padding:0.625rem 1.125rem; border-top:1px solid var(--hair); vertical-align:middle; }
tbody tr:first-child td{ border-top:0; }
tbody tr{ transition:background .1s; }
tbody tr.click{ cursor:pointer; }
tbody tr:hover td{ background:rgba(255,255,255,.024); }
tbody tr.sel td{ background:rgba(0,180,255,.07); }
tbody tr.sel:hover td{ background:rgba(0,180,255,.1); }
/* Tope de comparación alcanzado: las filas/barras no seleccionadas quedan inertes. */
tr.click.capped, .bar.click.capped{ opacity:.4; cursor:not-allowed; }
tr.click.capped:hover td{ background:transparent; }
/* Cifras a la derecha y tabulares: unidades bajo unidades, decenas bajo decenas, y la cabecera enrasada
   con su columna. Lo que una celda numérica apila (cifra + medidor) se enrasa también a la derecha. */
th.num,td.num{ text-align:right; font-variant-numeric:tabular-nums; }
th.num .sort-action{ justify-content:flex-end; }
td.num .cap{ align-items:flex-end; }
td.num .tps,td.num .bw{ justify-content:flex-end; }
.nid{ font-size:0.875rem; font-weight:650; color:var(--ink-1); }
.uuid{ font-family:var(--mono); font-size:0.7188rem; color:var(--ink-3); }
.tag{ display:inline-flex; align-items:center; flex:none; height:1.375rem; padding:0 0.5rem; white-space:nowrap; border-radius:var(--r-6);
  border:1px solid var(--hair); background:rgba(255,255,255,.04); font-size:0.75rem; font-weight:550;
  color:var(--ink-2); }
/* El tipo de nodo es una categoría, no un estado: etiqueta neutra con un punto que lo distingue. El
   color de estado (verde, ámbar, rojo) queda libre para lo que sí pide atención. */
.tag--game,.tag--proxy,.tag--backend{ gap:0.375rem; color:var(--ink-2); }
.tag--game::before,.tag--proxy::before,.tag--backend::before{ content:""; width:0.375rem; height:0.375rem; border-radius:var(--r-pill); flex:none; }
.tag--game::before{ background:var(--s1); }
.tag--proxy::before{ background:var(--s4); }
.tag--backend::before{ background:var(--ink-3); }
/* Las etiquetas de tipo de nodo miden todas lo mismo (Juego, Proxy y Backend en una columna se leen
   como una sola pieza) y nunca encogen: dentro de una fila flexible un nombre largo al lado las
   aplastaba y recortaba. */
.tag.tag--game,.tag.tag--proxy,.tag.tag--backend{ justify-content:center; min-width:6.4em; }
.bar .nm > .tag{ overflow:visible; }
.tps{ display:inline-flex; align-items:center; gap:0.4375rem; font-variant-numeric:tabular-nums; font-size:0.9062rem; font-weight:650; }
.cap{ display:flex; flex-direction:column; align-items:flex-start; gap:0.25rem; }
.cap .v i{ font-style:normal; color:var(--ink-3); }
.meter{ width:4.5rem; height:0.25rem; border-radius:var(--r-pill); background:rgba(0,180,255,.18); overflow:hidden; }
.meter i{ display:block; height:100%; border-radius:var(--r-pill); background:var(--s1); }
/* Sin dato: un guion gris, como texto (una caja con borde se leía como un control o como «cargando»). */
.na{ display:inline; color:var(--ink-3); }
.kv .na{ font:inherit; color:inherit; }
.bw{ display:inline-flex; gap:0.625rem; justify-content:flex-end; font-variant-numeric:tabular-nums; font-size:0.8438rem; font-weight:600; }
.bw .dn,.bw .up{ display:inline-block; min-width:3.125rem; text-align:right; }
.bw .dn{ color:var(--s3);} .bw .up{ color:var(--brand);}

/* filtro tabla */
.tsearch{ display:flex; align-items:center; gap:0.4375rem; height:2rem; width:clamp(10rem,28vw,15rem); max-width:100%;
  padding:0 0.625rem; background:var(--surface-3); border:1px solid var(--field-line); border-radius:var(--r-md); color:var(--ink-3); }
.tsearch:focus-within{ border-color:var(--brand); }
.tsearch .ico{ width:0.875rem; height:0.875rem; flex:none; }
.tsearch input{ flex:1; min-width:0; border:0; background:none; outline:none; color:var(--ink-1); font:inherit; font-size:0.8438rem; }
.tsearch input::placeholder{ color:var(--ink-3); }

/* paginación */
.pager{ display:flex; align-items:center; gap:0.5rem; padding:0.6875rem 0.9375rem; border-top:1px solid var(--hair); }
.pager .info{ font-size:0.7812rem; color:var(--ink-3); }
.pager .pg{ margin-left:auto; display:inline-flex; gap:0.25rem; }
.pgbtn{ min-width:1.875rem; height:1.875rem; padding:0 0.5rem; border:1px solid var(--hair); border-radius:var(--r-sm);
  color:var(--ink-2); font-size:0.8125rem; font-variant-numeric:tabular-nums; display:grid; place-items:center;
  transition:background .12s,color .12s; }
.pgbtn:hover{ background:var(--surface-3); color:var(--ink-1); }
.pgbtn[aria-current="true"]{ background:var(--surface-4); color:var(--ink-1); }
.pgbtn[disabled]{ opacity:.4; cursor:default; }

/* donut — cifra y leyenda van DENTRO del SVG, centradas por medición (getBBox) */
/* Anillo arriba, centrado; debajo su leyenda como una tabla breve: muestra, rótulo y cifra a la derecha. */
.donut-wrap{ display:flex; flex-direction:column; align-items:center; gap:1rem; width:100%; }
.donut{ width:10rem; height:10rem; flex:none; }
.donut svg{ display:block; width:100%; height:100%; }
.donutbody{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:0.9375rem; }
.dleg{ display:flex; flex-direction:column; width:100%; }
.dleg .row{ display:grid; grid-template-columns:0.5rem minmax(0,1fr); align-items:center; gap:0.625rem; min-height:1.875rem;
  border-top:1px solid var(--hair); }
.dleg .row:first-child{ border-top:0; }
.dleg .sw{ width:0.5rem; height:0.5rem; border-radius:var(--r-pill); flex:none; }
.dleg .t{ display:flex; flex-direction:row-reverse; justify-content:space-between; align-items:baseline; gap:0.75rem; min-width:0; }
.dleg .t b{ font-size:0.875rem; font-weight:600; color:var(--ink-1); font-variant-numeric:tabular-nums; white-space:nowrap; }
.dleg .t span{ font-size:0.8125rem; color:var(--ink-2); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* versiones */
.tag-ver{ display:flex; align-items:center; gap:0.75rem; padding:0.5rem 0; border-top:1px solid var(--hair); }
.tag-ver:first-child{ border-top:0; }
.tag-ver .lab{ font-family:var(--mono); font-size:0.7812rem; color:var(--ink-1); min-width:5.5rem; }

/* jugador detalle */
.playhead{ display:flex; align-items:center; gap:0.875rem; }
.avatar-lg{ width:3rem; height:3rem; border-radius:var(--r-13); display:grid; place-items:center;
  background:var(--avatar-1); font-size:1.125rem; font-weight:700; color:var(--avatar-ink); }
.playhead .h1{ font-size:1.125rem; font-weight:650; letter-spacing:-.015em; }
.playhead .meta{ font-size:0.7812rem; color:var(--ink-3); }
.backlink{ display:inline-flex; align-items:center; gap:0.375rem; font-size:0.8125rem; color:var(--ink-2);
  padding:0.375rem 0.6875rem; border:1px solid var(--hair); border-radius:var(--r-pill); background:var(--surface-1); cursor:pointer;
  transition:background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease); }
.backlink:hover{ color:var(--ink-1); border-color:var(--hair-2); }
.pdgrid{ display:grid; grid-template-columns:repeat(4,1fr); gap:1px; background:var(--hair);
  border:1px solid var(--hair); border-radius:var(--r-md); overflow:hidden; }
@media(max-width:820px){ .pdgrid{ grid-template-columns:repeat(2,1fr); } }
.pdcell{ background:var(--surface-1); padding:0.8125rem 0.9375rem; }
.pdcell .l{ font-size:0.7188rem; color:var(--ink-3); }
.pdcell .v{ font-size:1.0625rem; font-weight:680; margin-top:0.1875rem; font-variant-numeric:tabular-nums; }
.pdcell .v small{ font-size:0.7188rem; color:var(--ink-3); font-weight:500; }
.aidx{ display:inline-flex; gap:0.1875rem; margin-top:0.3125rem; }
.aidx i{ width:1.25rem; height:0.3125rem; border-radius:var(--r-3); background:var(--surface-4); }
.aidx i.on{ background:var(--s1); }
.punch{ display:grid; grid-template-columns:1.875rem repeat(24,1fr); gap:0.1875rem; align-items:center; }
.punch .hh{ font-size:0.625rem; color:var(--ink-3); text-align:center; font-variant-numeric:tabular-nums; }
.punch .dd{ font-size:0.7188rem; color:var(--ink-3); }
.punch .cell{ aspect-ratio:1; border-radius:var(--r-2); background:var(--surface-3);
  transition:transform .1s var(--ease), box-shadow .1s var(--ease); }
.punch .cell:hover{ transform:scale(1.4); box-shadow:0 0 0 1.5px var(--brand); position:relative; z-index:2; }
.punchwrap{ position:relative; }
.punchtip{ position:absolute; pointer-events:none; z-index:6; background:var(--surface-4);
  border:1px solid var(--hair-2); border-radius:var(--r-8); padding:0.375rem 0.5625rem; font-size:0.75rem;
  box-shadow:var(--shadow); white-space:nowrap; color:var(--ink-2); }
.punchtip b{ color:var(--ink-1); }
.punchlegend{ display:flex; align-items:center; gap:0.4375rem; margin-top:0.8125rem; font-size:0.7188rem; color:var(--ink-3); }
.punchlegend .sc{ display:inline-flex; gap:2px; }
.punchlegend .sc i{ width:0.75rem; height:0.75rem; border-radius:var(--r-2); }
/* Aviso en línea: neutro por defecto (información), con tono cuando el contenido lo pide. Lo construye
   secnote(tone, html) en shell.js, siempre con su icono. */
.secnote{ display:flex; align-items:flex-start; gap:0.5625rem; background:var(--surface-3);
  border:1px solid var(--hair-2); color:var(--ink-2); border-radius:var(--r-md); padding:0.625rem 0.8125rem;
  font-size:0.8125rem; line-height:1.5; }
.secnote b{ color:var(--ink-1); font-weight:650; }
.secnote .ico{ flex:none; width:0.9375rem; height:0.9375rem; margin-top:1px; color:var(--ink-3); }
.secnote.ok{ background:var(--pos-faint); border-color:var(--pos-line); }
.secnote.ok .ico{ color:var(--pos); }
.secnote.warn{ background:var(--warn-faint); border-color:var(--warn-line); }
.secnote.warn .ico{ color:var(--warn); }
.secnote.crit{ background:var(--neg-faint); border-color:var(--neg-line); color:var(--ink-1); }
.secnote.crit .ico{ color:var(--neg); }
/* Error de un campo o de un formulario, bajo el control que lo provocó. */
.field-err,.login-error,.twofa-err{ margin:0; min-height:1rem; font-size:0.8125rem; color:var(--neg); }
.field-err:empty,.twofa-err:empty{ min-height:0; }
tr.acc-warn td{ background:var(--warn-faint); }
tr.acc-crit td{ background:var(--neg-faint); }

/* mapa procedencia */
.mapwrap{ position:relative; background:var(--surface-2);
  border-radius:var(--r-md); }
.map-svg{ display:block; width:100%; height:auto; }
.bub{ cursor:pointer; transition:opacity .15s; }
.bub:hover{ opacity:.85; }
.bub.sel circle{ stroke:var(--brand); stroke-width:2; }
.geo-list{ display:flex; flex-direction:column; }
.geo-row{ display:grid; grid-template-columns:1.625rem 1fr auto; align-items:center; gap:0.6875rem; text-align:left;
  padding:0.5rem 0.6875rem; border-radius:var(--r-md); cursor:pointer;
  transition:background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease); }
.geo-row:hover{ background:rgba(255,255,255,.03); }
.geo-row[aria-pressed="true"]{ background:var(--surface-3); }
.geo-row .nm{ font-size:0.8438rem; }
.miniback{ display:block; height:0.25rem; border-radius:var(--r-pill); background:var(--surface-3); margin-top:0.3125rem; overflow:hidden; }
.miniback i{ display:block; height:100%; background:var(--s1); border-radius:var(--r-pill); }
.cmp{ display:grid; grid-template-columns:1fr auto 1fr; gap:0.75rem; align-items:center; }
.cmp .col{ text-align:center; }
.cmp .col .big{ font-size:1.5rem; font-weight:680; font-variant-numeric:tabular-nums; letter-spacing:-.02em; }
.cmp .col .lb{ font-size:0.75rem; color:var(--ink-3); }
.cmp .vs{ font-size:0.7188rem; color:var(--ink-3); font-weight:700; }
.cmpbar{ display:flex; height:0.4375rem; border-radius:var(--r-pill); overflow:hidden; margin-top:0.6875rem; }
.cmpsel-row{ display:flex; align-items:center; gap:0.5625rem; }
.cmpsel-row .vs{ font-size:0.7188rem; color:var(--ink-3); font-weight:700; flex:none; }
.cmpsel{ flex:1; min-width:0; height:2rem; padding:0 0.5625rem; font:inherit; font-size:0.8125rem; color:var(--ink-1);
  background:var(--surface-3); border:1px solid var(--field-line); border-radius:var(--r-md); cursor:pointer;
  transition:border-color .15s var(--ease); }
.cmpsel:hover{ border-color:var(--hair-2); }
.cmpsel:focus-visible{ outline:2px solid var(--brand); outline-offset:1px; }

/* timeline historial */
.tl{ display:flex; flex-direction:column; }
.tl-row{ display:grid; grid-template-columns:4.375rem 1.125rem 1fr; gap:0.75rem; }
.tl-time{ font-size:0.75rem; color:var(--ink-3); font-variant-numeric:tabular-nums; text-align:right; padding-top:0.6875rem; }
.tl-mark{ display:flex; flex-direction:column; align-items:center; }
.tl-mark .d{ width:0.625rem; height:0.625rem; border-radius:var(--r-pill); margin-top:0.75rem; border:2px solid var(--bg); }
.tl-mark .ln{ flex:1; width:2px; background:var(--hair); margin-top:2px; }
.tl-row:last-child .tl-mark .ln{ display:none; }
.tl-card{ margin:0.4375rem 0; background:var(--surface-3); border:1px solid var(--hair); border-radius:var(--r-md); padding:0.625rem 0.875rem; }
.tl-card .ev{ font-size:0.875rem; font-weight:650; color:var(--ink-1); }
.tl-card .de{ font-size:0.7812rem; color:var(--ink-2); margin-top:2px; }
.tl-card .de b{ color:var(--ink-1); font-weight:600; }
.tl-card .ev b{ font-weight:700; }
/* Cabecera de día en la cronología: «Hoy», «Ayer», «miércoles 8 de octubre». */
.tl-day{ margin:1rem 0 0.25rem calc(4.375rem + 1.125rem + 1.5rem); font-size:0.8125rem; font-weight:600;
  color:var(--ink-2); }
.tl-day:first-child{ margin-top:0; }

.hidden{ display:none !important; }

/* ---- paleta de comandos (Ctrl/⌘ K): <dialog> modal nativo en la capa superior ---- */
.cmdk{ width:min(38.75rem,92vw); max-width:none; max-height:70vh; margin:12vh auto auto; padding:0;
  flex-direction:column; color:var(--ink-1); background:var(--surface-1); border:1px solid var(--hair-2);
  border-radius:var(--r-14); box-shadow:var(--shadow-pop); overflow:hidden; }
.cmdk[open]{ display:flex; animation:cmdkIn .16s var(--ease); }
.cmdk::backdrop{ background:var(--scrim); }
@keyframes cmdkIn{ from{ opacity:0; transform:translateY(-8px) scale(.985); } }
.cmdk-inp{ display:flex; align-items:center; gap:0.625rem; padding:0.8125rem 0.9375rem; border-bottom:1px solid var(--hair); }
.cmdk-inp .ico{ color:var(--ink-3); width:1.125rem; height:1.125rem; }
.cmdk-inp input{ flex:1; min-width:0; border:0; background:none; outline:none; color:var(--ink-1); font:inherit; font-size:0.9375rem; }
.cmdk-inp input::placeholder{ color:var(--ink-3); }
.cmdk-list{ flex:1; min-height:0; overflow-y:auto; padding:0.375rem; scrollbar-width:thin; scrollbar-color:rgba(255,255,255,.13) transparent; }
.cmdk-item{ display:flex; align-items:center; gap:0.6875rem; padding:0.5625rem 0.6875rem; border-radius:var(--r-md); cursor:pointer; }
.cmdk-item .ci-ic{ display:grid; place-items:center; width:1.75rem; height:1.75rem; flex:none; border-radius:var(--r-sm);
  background:var(--surface-3); color:var(--ink-2); }
.cmdk-item .ci-ic .ico{ width:0.9375rem; height:0.9375rem; }
.cmdk-item .ci-tx{ flex:1; min-width:0; }
.cmdk-item .ci-tx b{ font-size:0.9062rem; font-weight:600; color:var(--ink-1); display:block;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cmdk-item .ci-tx span{ font-size:0.75rem; color:var(--ink-3); }
.cmdk-item .ci-type{ font-size:0.75rem; font-weight:500; color:var(--ink-3); flex:none; }
.cmdk-item[aria-selected="true"]{ background:var(--surface-3); }
.cmdk-item[aria-selected="true"] .ci-ic{ background:var(--brand); color:var(--on-accent); }
.cmdk-empty{ padding:1.75rem; text-align:center; color:var(--ink-3); font-size:0.875rem; }
.cmdk-foot{ display:flex; gap:1rem; padding:0.5625rem 0.875rem; border-top:1px solid var(--hair); font-size:0.75rem; color:var(--ink-3); }
.cmdk-foot .kbd{ margin-right:0.1875rem; }

/* microinteracciones */
.spark{ display:block; width:100%; height:2.5rem; }
/* cuerpo scrollable: llena la tarjeta (que se estira a la altura de su fila
   bento) y sólo scrollea cuando el contenido desborda — sin altura fija. */
.scrolly{ flex:1; min-height:0; overflow-y:auto; scrollbar-width:thin; scrollbar-color:rgba(255,255,255,.13) transparent; }
.scrolly::-webkit-scrollbar{ width:0.5rem; }
.scrolly::-webkit-scrollbar-thumb{ background:rgba(255,255,255,.12); border-radius:var(--r-8); }
.spin{ animation:spin .6s var(--ease); }
@keyframes spin{ to{ transform:rotate(360deg); } }

@media (prefers-reduced-motion: reduce){
  *{ animation:none !important; transition-duration:.001ms !important; }
  .main{ scroll-behavior:auto; }
}

/* ============================================================
   Compatibilidad módulo Divisas (renderCurrency, verbatim del panel
   anterior) — su plantilla usa .card-head y un .sub genérico que el
   diseño «definitivo» expresa como .ch/.ch .sub. Se mapean aquí para
   que la vista de divisas conserve su aspecto sin tocar su JS.
   ============================================================ */
.sub{ font-size:0.7188rem; color:var(--ink-3); margin-top:1px; }

/* estados de carga / error / vacío de una sección de Analíticas */
.loading-note{ padding:1.875rem; text-align:center; color:var(--ink-3); font-size:0.875rem; }
.loading-note .dot-dot{ display:inline-block; animation:blink 1.2s var(--ease) infinite; }
@keyframes blink{ 50%{ opacity:.35; } }
.empty-note{ padding:1.625rem; text-align:center; color:var(--ink-3); font-size:0.8438rem; }
tbody td.empty-cell{ padding:1.625rem 1.0625rem; text-align:center; color:var(--ink-3); font-size:0.8438rem; }
tbody tr:hover td.empty-cell{ background:transparent; }

/* ---- página de acceso (login.html) ---- */
.login-wrap{ min-height:100dvh; display:flex; align-items:center; justify-content:center; padding:1.5rem;
  background:var(--bg); }
.login-card{ width:100%; max-width:22.5rem; display:flex; flex-direction:column; align-items:center;
  background:var(--surface-1); border:1px solid var(--hair); border-radius:var(--r-16); padding:2.125rem 1.875rem 1.875rem; }
.login-logo{ width:3.25rem; height:3.25rem; display:grid; place-items:center; margin-bottom:1rem; }
.login-logo svg{ width:2.75rem; height:2.75rem; display:block; }
.login-title{ font-size:1.25rem; font-weight:680; letter-spacing:-.02em; color:var(--ink-1); }
.login-sub{ font-size:0.8438rem; color:var(--ink-3); margin-top:0.375rem; text-align:center; }
.login-form{ width:100%; margin-top:1.375rem; display:flex; flex-direction:column; gap:0.75rem; }
/* Campo de código de 6 dígitos (login y vínculo de app 2FA): un <input> real, transparente, bajo seis
   celdas pintadas. Un solo input conserva pegar, autocompletar one-time-code y lectores de pantalla. */
.code-field{ position:relative; height:3.5rem; width:100%;
  background:var(--surface-3); border:1px solid var(--hair); border-radius:var(--r-10); transition:border-color .15s; }
.code-field:focus-within{ border-color:var(--brand); }
.code-input{ position:absolute; inset:0; width:100%; height:100%; border:0; background:none; outline:none;
  color:transparent; caret-color:transparent; font-size:1rem; letter-spacing:0; padding:0 0.875rem; }
.code-cells{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center; gap:0.5625rem;
  pointer-events:none; }
.code-cell{ position:relative; width:1.2ch; text-align:center; font-family:var(--mono); font-size:1.7rem;
  font-variant-numeric:tabular-nums; color:var(--ink-3); }
.code-cell.filled{ color:var(--ink-1); }
.code-cell.active::after{ content:""; position:absolute; left:0; right:0; bottom:-4px; height:2px;
  background:var(--brand); animation:blink 1s steps(1) infinite; }
@media (prefers-reduced-motion: reduce){ .code-cell.active::after{ animation:none; } }
.login-error{ min-height:1rem; font-size:0.8125rem; color:var(--neg); text-align:center; margin:0; }
.login-btn{ display:inline-flex; align-items:center; justify-content:center; gap:0.5rem; height:2.75rem;
  border:0; border-radius:var(--r-10); background:var(--brand); color:var(--on-accent); font:inherit; font-size:0.9375rem;
  font-weight:650; cursor:pointer; transition:filter .15s, opacity .15s; }
.login-btn:hover{ filter:brightness(1.08); }
.login-btn:disabled{ opacity:.6; cursor:default; }
.login-btn svg{ width:1.0625rem; height:1.0625rem; fill:none; stroke:currentColor; stroke-width:1.9;
  stroke-linecap:round; stroke-linejoin:round; }

/* ============================================================
   Módulo Divisas — sólo lo que no existe ya en el lenguaje de Analíticas.
   Reutiliza .kstrip/.kcell/.bento/.card/.ch/.cb/.bars/.trk/.vv/.donut/
   .subnav/.seg/.pillset/.filters/.fgroup/.flab/.legendrow/.lgd/.lk/.chip/.tag.
   ============================================================ */
/* subnav de Divisas: activo por clase .on (Analíticas usa [aria-selected]; misma apariencia) */
.seg button.on{ background:var(--surface-4); color:var(--ink-1); font-weight:600; }
/* fila de filtros de Movimientos */
.mfilters{ display:flex; align-items:center; gap:0.75rem; flex-wrap:wrap; }
/* leaderboards (Rankings) */
.lead{ display:flex; flex-direction:column; }
.lead-row{ display:grid; grid-template-columns:1.375rem 1fr auto; align-items:center; gap:0.625rem;
  padding:0.5rem 0; border-top:1px solid var(--hair); }
.lead-row:first-child{ border-top:0; }
.rk{ font:700 0.75rem/1 var(--mono); color:var(--ink-3); text-align:center; }
.rk.top{ color:var(--rank-gold); }
.pill-av{ width:1.4375rem; height:1.4375rem; border-radius:var(--r-pill); background:var(--surface-4);
  display:grid; place-items:center; font-size:0.6875rem; color:var(--ink-2); }
.lead-nm{ display:flex; align-items:center; gap:0.5625rem; font-size:0.8438rem; color:var(--ink-1); }
.lead-v{ font-size:0.8438rem; font-weight:640; color:var(--ink-1); font-variant-numeric:tabular-nums; }
/* tags de tipo de transacción (sobre la base .tag existente) */
.tag.rc{ color:var(--tag-rc); border-color:var(--pos-line); background:var(--pos-faint); }
.tag.sp{ color:var(--tag-sp); border-color:var(--neg-line); background:var(--neg-faint); }
.tag.tr{ color:var(--tag-tr); border-color:var(--value-line); background:var(--value-faint); }
.tag.st{ color:var(--tag-st); border-color:var(--warn-line); background:var(--warn-faint); }
/* importe con signo y fecha monoespaciada en el libro de Movimientos */
.dv-pos{ color:var(--pos); }
.dv-neg{ color:var(--neg); }
.dv-mono{ font-family:var(--mono); }
/* botón «Cargar más» */
.more{ display:flex; justify-content:center; padding:0.6875rem; border-top:1px solid var(--hair); }

/* ============================================================
   Pulido product (impeccable) — micro-detalles transversales.
   Registro producto: familiaridad Grafana/Linear-class; motion
   sólo como feedback de estado (150-200ms ease-out), nunca
   decorativa. Sin blur (WebAssetsTest).
   ============================================================ */
/* Todo número es dato: cifras tabulares en KPIs, tablas y barras para que las columnas no bailen. */
.kv,.big,.vv,.lead-v,.tps,td.num{ font-variant-numeric:tabular-nums; }
/* Interactivos con la misma curva corta en todo el panel. */
.seg button,.pillset button,.zreset,.chip,.icon-btn,.btn-ghost,.tag{
  transition:background-color .15s cubic-bezier(.16,1,.3,1), color .15s cubic-bezier(.16,1,.3,1), border-color .15s cubic-bezier(.16,1,.3,1); }
/* Anillo de foco (:focus-visible) y apagado de motion (prefers-reduced-motion) son autoritativos
   arriba del archivo; no se redeclaran aquí para evitar duplicados. */
/* Scroll fino y del tema en los cuerpos scrollables. */
.scrolly,.tblwrap,.tl{ scrollbar-width:thin; scrollbar-color:var(--surface-4) transparent; }
.scrolly::-webkit-scrollbar,.tblwrap::-webkit-scrollbar,.tl::-webkit-scrollbar{ width:0.5rem; height:0.5rem; }
.scrolly::-webkit-scrollbar-thumb,.tblwrap::-webkit-scrollbar-thumb,.tl::-webkit-scrollbar-thumb{
  background:var(--surface-4); border-radius:var(--r-8); }

/* Pase de pulido (impeccable) — chip de acción «ver →» clicable + elipsis del paginador. */
button.chip{ cursor:pointer; }
/* Acción de texto en la cabecera de una tarjeta («Ver TPS →»): sin caja, sube a tinta plena al apuntarla. */
.ch-link{ display:inline-flex; align-items:center; gap:0.3125rem; height:1.5rem; padding:0 0.25rem; border-radius:var(--r-4);
  font-size:0.8125rem; font-weight:500; color:var(--ink-2); white-space:nowrap; transition:color .15s var(--ease); }
.ch-link:hover{ color:var(--ink-1); }
button.chip:hover{ color:var(--ink-1); border-color:var(--hair-2); }
.pg-ell{ align-self:center; padding:0 0.25rem; color:var(--ink-3); font-size:0.8125rem; user-select:none; }

/* adapt — barra lateral colapsable a un rail de iconos (toggle #sideToggle · Ctrl B · auto <1100px). */
/* Controles del plano de operador — compartidos por módulos que editan estado autoritativo. */
.ops-view .chip{ white-space:nowrap; }
.ops-form{ display:grid; flex:none; grid-template-columns:repeat(12,minmax(0,1fr)); gap:0.875rem;
  align-items:end; }
.ops-form > .secnote,.ops-form > .ops-feedback,.ops-form > .tblwrap{
  grid-column:1 / -1; }
.ops-field{ grid-column:span 6; min-width:0; display:flex; flex-direction:column; gap:0.375rem; }
.ops-field--full{ grid-column:1 / -1; }
.ops-field--small{ grid-column:span 2; }
.ops-field--medium{ grid-column:span 4; }
.ops-label{ font-size:0.75rem; font-weight:650; color:var(--ink-2); }
.ops-control{ width:100%; min-width:0; height:2.25rem; padding:0.4375rem 0.625rem; color:var(--ink-1);
  background:var(--surface-2); border:1px solid var(--field-line); border-radius:var(--r-md);
  font:inherit; font-size:0.8438rem; transition:border-color .15s var(--ease), background .15s var(--ease); }
.ops-control:hover:not(:disabled){ border-color:var(--ink-3); }
.ops-control--sm{ height:2rem; padding:0.3125rem 0.5625rem; font-size:0.8125rem; }
select.ops-control{ padding-right:1.75rem; cursor:pointer; }
.ops-control:focus-visible{ border-color:var(--brand); background:var(--surface-3); }
.ops-control:disabled{ color:var(--ink-3); background:var(--surface-3); opacity:1; cursor:not-allowed; }
textarea.ops-control{ min-height:4.5rem; height:auto; resize:vertical; line-height:1.4; }
.ops-search{ width:100%; }
.ops-search:focus-within{ outline:2px solid var(--brand); outline-offset:2px; }
.ops-actions{ grid-column:1 / -1; display:flex; align-items:center; justify-content:flex-end;
  gap:0.5rem; flex-wrap:wrap; }
.ops-actions--start{ justify-content:flex-start; }
.ops-feedback{ display:flex; flex-direction:column; gap:0.625rem; }
.ops-button{ display:inline-flex; align-items:center; justify-content:center; min-height:2.25rem;
  padding:0 0.8125rem; border:1px solid var(--hair-2); border-radius:var(--r-md);
  background:var(--surface-3); color:var(--ink-1); font-size:0.8125rem; font-weight:650;
  transition:border-color .15s var(--ease), background .15s var(--ease), opacity .15s var(--ease); }
.ops-button:hover:not(:disabled){ border-color:var(--brand); background:var(--surface-4); }
.ops-button--primary{ background:var(--brand); border-color:var(--brand); color:var(--on-accent); }
.ops-button--primary:hover:not(:disabled){ background:var(--s3); border-color:var(--s3); }
.ops-button:disabled{ opacity:.42; cursor:not-allowed; }
.ops-button--danger{ color:var(--neg); border-color:var(--neg-line); background:var(--neg-faint); }
.ops-button--danger:hover:not(:disabled){ border-color:var(--neg); background:var(--neg-faint); }
/* Acción destructiva repetida en cada fila: neutra en reposo para que la tabla no grite, roja al apuntarla. */
.ops-button--quiet-danger{ color:var(--ink-2); }
/* Spawners sin grupo elegido: la pregunta y los grupos como botones, en vez de un vacío. */
.sc-pick-lead{ margin:0 0 0.875rem; font-size:0.9375rem; color:var(--ink-2); }
.sc-picks{ display:flex; flex-wrap:wrap; gap:0.625rem; }
.ops-button--quiet-danger:hover:not(:disabled),.ops-button--quiet-danger:focus-visible{ color:var(--neg); border-color:var(--neg); background:var(--neg-faint); }
.ops-button--sm{ min-height:1.875rem; padding:0 0.625rem; font-size:0.7812rem; }
.ops-button .ico{ width:0.875rem; height:0.875rem; margin-right:0.375rem; }
.ops-table{ min-width:42.5rem; }
.ops-table .tnum,.ops-table .nid{ white-space:nowrap; }
.ops-table .row-action{ color:var(--brand); font-weight:600; }
.ops-table .row-action:hover:not(:disabled){ color:var(--s3); }
.ops-table .row-action:disabled{ color:var(--ink-3); cursor:not-allowed; }
.ops-table--wide{ min-width:1160px; }
.ops-table--wide .ops-control{ min-width:6rem; height:2rem; padding:0.3125rem 0.5rem; }
.ops-check-hit{ display:grid; place-items:center; width:2rem; height:2rem; cursor:pointer; }
.ops-check-hit:has(.ops-check:disabled){ cursor:not-allowed; }
.ops-check{ width:1.125rem; height:1.125rem; accent-color:var(--brand); }
.ops-stack{ display:flex; flex-direction:column; gap:0.625rem; }
.ops-table--compact{ min-width:26.25rem; }

@media(max-width:720px){
  .ops-card .ch .ops-legend{ width:100%; margin-left:0; justify-content:flex-start; }
  .ops-form{ grid-template-columns:1fr; gap:0.75rem; }
  .ops-field,.ops-field--full,.ops-field--small,.ops-field--medium{ grid-column:1; }
  .ops-actions{ justify-content:stretch; }
  .ops-actions--start{ justify-content:flex-start; }
  .ops-button{ flex:1 1 8.25rem; min-height:2.5rem; }
}

.side-toggle{ margin-left:auto; }
.app[data-collapsed="true"] .side{ width:4rem; }
.app[data-collapsed="true"] .brand-txt,
.app[data-collapsed="true"] .search span,
.app[data-collapsed="true"] .sec-h > span,
.app[data-collapsed="true"] .sec-h b,
.app[data-collapsed="true"] .nav-a .lbl,
.app[data-collapsed="true"] .who{ display:none; }
/* Rail colapsado (4rem): logo y toggle apilados en vertical (no caben en horizontal sin apelotonarse
   contra los bordes); búsqueda y avatar como iconos centrados con el mismo ritmo que los del nav. */
.app[data-collapsed="true"] .side-head{ flex-direction:column; gap:0.75rem; padding:0.875rem 0 0.625rem; justify-content:center; min-height:0; }
.app[data-collapsed="true"] .side-toggle{ margin:0; }
.app[data-collapsed="true"] .search-wrap{ padding:0 0 0.625rem; display:flex; justify-content:center; }
.app[data-collapsed="true"] .search{ width:2.375rem; height:2.375rem; padding:0; justify-content:center; border-radius:var(--r-md); }
.app[data-collapsed="true"] .nav-list{ padding:2px 0 0.5rem; }
.app[data-collapsed="true"] .nav-a{ justify-content:center; padding:0.5625rem 0; margin:0 0.8125rem 2px; }
.app[data-collapsed="true"] .side-foot{ flex-direction:column; justify-content:center; gap:0.375rem; padding:0.75rem 0; }
@media (prefers-reduced-motion: reduce){ .side{ transition:none; } }

/* A fixed compact rail leaves usable content space even on a 20rem viewport. */
@media(max-width:720px){
  .side{ width:3.5rem; }
  .brand-txt,.sec-h,.nav-a .lbl,.who,.side-foot .avatar,.side-toggle,
  .search span{ display:none; }
  .side-head{ min-height:3.25rem; justify-content:center; padding:0.75rem 0 0.5rem; }
  .search-wrap{ display:flex; justify-content:center; padding:0 0 0.5rem; }
  .search{ width:2.5rem; height:2.5rem; justify-content:center; padding:0; }
  .nav-list{ padding:2px 0 0.5rem; }
  .nav-a{ min-height:2.75rem; justify-content:center; margin:0 0.4375rem 2px; padding:0.625rem 0; }
  .side-foot{ flex-direction:column; justify-content:center; gap:0.25rem; padding:0.5rem 0; }
  .topbar{ min-height:3.25rem; gap:0.5rem; padding:0.5625rem 0.75rem; }
  .topbar > div:first-child{ min-width:0; }
  .topbar h1{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .topbar .sub,.updated{ display:none; }
  .top-actions{ gap:0.375rem; }
  .subnav{ top:3.25rem; gap:0.5rem; padding:0.5rem 0.75rem; }
  .filters{ width:100%; margin-left:0; gap:0.4375rem; }
  .content{ padding:0.875rem 0.75rem 2.5rem; gap:0.875rem; }
  .view{ gap:0.875rem; }
  .secrow{ align-items:flex-start; flex-wrap:wrap; }
  .bar{ grid-template-columns:minmax(5.5rem,1fr) minmax(4.5rem,2fr) auto !important; }
}

/* En un teléfono la cabecera conserva el título y lo esencial: el punto de «en vivo» sin su texto y sin
   exportar CSV (una hoja de cálculo no se abre ahí); el resto cabe sin desbordar la pantalla. */
@media(max-width:480px){
  .live .live-lbl,#exportBtn{ display:none; }
}

/* Compact desktop controls gain a full target only when touch is the primary pointer. */
@media (pointer:coarse){
  .icon-btn,.btn-ghost,.pgbtn,.nav-a,.search,.seg button,.pillset button,.zreset,.ch-link,
  .row-action,.sort-action,.bar.click,.geo-row,.ops-button,.ops-check-hit{
    min-width:44px; min-height:44px;
  }
}

/* animate — destello del sello «Actualizado» al refrescar (feedback de estado, ~0.7s). */
@keyframes cc-upflash{ from{ color:var(--pos); } to{ color:var(--ink-3); } }
.updated.flash{ animation:cc-upflash .7s var(--ease); }
@media (prefers-reduced-motion: reduce){ .updated.flash{ animation:none; } }

/* «en pausa»: el chip deja de fingir liveness cuando el auto-refresco está suspendido (zoom/selección). */
.live.paused{ color:var(--ink-3); }
.live.paused .pulse{ background:var(--ink-3); animation:none; box-shadow:none; }
/* «sin conexión»: el último refresco falló y la vista conserva los datos anteriores. */
.live.stale{ color:var(--warn); }
.live.stale .pulse{ background:var(--warn); }
/* Vista o bloque que no cargó: el aviso y, debajo, «Reintentar». */
.load-error{ display:flex; flex-direction:column; align-items:flex-start; gap:0.75rem; }
.load-error .secnote{ align-self:stretch; }

/* Glosario (dialog nativo) — ayuda para un operador nuevo. */
.gloss{ border:1px solid var(--hair-2); border-radius:var(--r-card); background:var(--surface-1);
  color:var(--ink-1); max-width:33.75rem; width:calc(100% - 2rem); padding:0; box-shadow:var(--shadow-pop); }
.gloss::backdrop{ background:var(--scrim); }
.gloss-head{ display:flex; align-items:center; justify-content:space-between; padding:0.8125rem 1.125rem;
  border-bottom:1px solid var(--hair); }
.gloss-head h3{ font-size:0.9375rem; font-weight:650; }
.gloss-dl{ margin:0; padding:0.875rem 1.125rem 1.125rem; display:grid; grid-template-columns:auto 1fr; gap:0.5rem 1rem;
  max-height:min(70vh,35rem); overflow-y:auto; scrollbar-width:thin; scrollbar-color:var(--surface-4) transparent; }
.gloss-dl dt{ font-weight:650; color:var(--ink-1); font-size:0.8438rem; white-space:nowrap; }
.gloss-dl dd{ margin:0; color:var(--ink-2); font-size:0.8438rem; line-height:1.46; }

/* Diálogos del panel (ccConfirm / ccPrompt / ccNotice): el armazón del glosario con un formulario. */
.ccdlg{ max-width:27.5rem; }
.ccdlg-body{ display:flex; flex-direction:column; gap:0.75rem; padding:0.875rem 1.125rem 1.125rem; }
.ccdlg-text{ margin:0; font-size:0.8438rem; line-height:1.5; color:var(--ink-2); }
.ccdlg-text b{ color:var(--ink-1); font-weight:650; }
.ccdlg .ops-actions{ margin-top:0.25rem; }

/* Apps de autenticación (2FA) — tarjeta de «Accesos» con los controles ops-*. */
.twofa-lead{ margin:0; font-size:0.8438rem; line-height:1.46; color:var(--ink-2); }
.twofa-note{ margin:0; font-size:0.8125rem; color:var(--ink-3); }
.twofa-err{ margin:0; min-height:1rem; font-size:0.8125rem; color:var(--neg); }
.twofa-err:empty{ min-height:0; }
.twofa-qr{ align-self:center; width:12.25rem; height:12.25rem; padding:0.375rem; background:var(--qr-bg); border-radius:var(--r-md); }
.twofa-qr svg{ display:block; width:100%; height:100%; }
.twofa-key{ display:flex; align-items:center; gap:0.625rem; }
.twofa-key code{ flex:1; min-width:0; font-family:var(--mono); font-size:0.8125rem; color:var(--ink-1);
  overflow-wrap:anywhere; letter-spacing:.04em; }

/* Visor de logs — texto de consola archivado. Pozo (surface-2) + mono, con su propio scroll: una
   ejecución larga no puede empujar el ancho de la página (regla de contenido ancho del panel). */
.logview{ margin:0; max-height:min(62vh,40rem); overflow:auto; background:var(--surface-2);
  border:1px solid var(--hair); border-radius:var(--r-md); padding:0.75rem 0.875rem;
  font-family:var(--mono); font-size:0.7812rem; line-height:1.5; color:var(--ink-2);
  white-space:pre; tab-size:4; scrollbar-width:thin; scrollbar-color:var(--surface-4) transparent; }
.logview:focus-visible{ outline:2px solid var(--brand); outline-offset:2px; }
/* Colores de consola: ERROR y FATAL en rojo, WARN en ámbar; una traza hereda el de su línea. */
.logview .lg-err{ color:var(--neg); }
.logview .lg-warn{ color:var(--warn); }
.logview .lg-b{ font-weight:700; }
/* Herramientas del visor: búsqueda y saltos, en su propia fila bajo la cabecera. */
.lg-tools{ display:flex; align-items:center; flex-wrap:wrap; gap:0.625rem; padding:0.625rem 1.0625rem 0; }
.lg-tools-r{ margin-left:auto; display:flex; gap:0.5rem; }

/* ============================================================
   Secciones por módulo. Cada módulo añade aquí SOLO lo que no existe ya en las primitivas de
   arriba (card, kstrip, ops-*, secnote, tsearch, tablas); una variante local de una primitiva es
   un bug de consistencia, no un estilo propio.
   ============================================================ */

/* ---- módulo: shell · Funciones de la shell: accesos, auditoría, resumen, exportación ---- */
/* «Accesos» no vive en la lista de módulos: su puerta (el escudo del pie) se marca como el nav activo. */
.side-foot .icon-btn[aria-current="page"]{ background:var(--surface-3); color:var(--ink-1); }
/* Tarjeta «Apps de autenticación»: el aviso y el error del formulario ocupan su fila entera. */
.twofa-new > .twofa-lead,.twofa-new > .twofa-err{ grid-column:1 / -1; }
.twofa-link{ display:flex; flex-direction:column; gap:0.75rem; max-width:28.75rem; }
/* «Auditoría»: el filtro de acción no estira la barra; los textos libres se parten en vez de ensanchar. */
.fgroup .au-action{ width:auto; min-width:10rem; max-width:15rem; }
.au-text{ min-width:7.5rem; max-width:20rem; overflow-wrap:anywhere; }
.sh-nowrap{ white-space:nowrap; }
/* Glosario con dos listas (términos y atajos de teclado) bajo un solo scroll. */
.gloss-scroll{ max-height:min(70vh,35rem); overflow-y:auto; scrollbar-width:thin; scrollbar-color:var(--surface-4) transparent; }
.gloss-scroll .gloss-dl{ max-height:none; overflow:visible; }
.gloss-sub{ margin:0; padding:0.5rem 1.125rem 0; font-size:0.8125rem; font-weight:600; color:var(--ink-2); }
/* Una vista sin secciones (las páginas de la shell, un módulo de una sola vista) no deja una píldora vacía. */
.seg:empty{ display:none; }
/* Avisos de módulo en la barra lateral: cifra pequeña en el tono de la escala fija. Con el rail
   colapsado (o en móvil) se posa sobre la esquina del icono, que es lo único visible. */
.nav-a{ position:relative; }
.nav-attn{ display:inline-grid; place-items:center; flex:none; min-width:1.125rem; height:1.125rem; padding:0 0.3125rem;
  border:1px solid var(--hair); border-radius:var(--r-pill); background:var(--surface-3); color:var(--ink-2);
  font-size:0.6875rem; font-weight:700; line-height:1; font-variant-numeric:tabular-nums; }
.nav-attn.warn{ color:var(--warn); border-color:var(--warn-line); background:var(--warn-faint); }
.nav-attn.crit{ color:var(--neg); border-color:var(--neg-line); background:var(--neg-faint); }
.nav-attn.good{ color:var(--pos); border-color:var(--pos-line); background:var(--pos-faint); }
.app[data-collapsed="true"] .nav-attn{ position:absolute; top:2px; right:0.3125rem; min-width:0.9375rem; height:0.9375rem; padding:0 0.1875rem; font-size:0.625rem; }
@media(max-width:720px){
  .nav-attn{ position:absolute; top:2px; right:0.25rem; min-width:0.9375rem; height:0.9375rem; padding:0 0.1875rem; font-size:0.625rem; }
}
/* «Resumen»: un acceso compacto por módulo, con su aviso si lo tiene. */
.ov-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(13.125rem,1fr)); gap:0.625rem; }
.ov-tile{ display:flex; flex-wrap:wrap; align-items:center; gap:0.5rem 0.625rem; min-height:3.25rem; padding:0.625rem 0.75rem;
  background:var(--surface-2); border:1px solid var(--hair); border-radius:var(--r-md); color:var(--ink-1);
  transition:border-color .15s cubic-bezier(.16,1,.3,1), background-color .15s cubic-bezier(.16,1,.3,1); }
.ov-tile:hover{ border-color:var(--hair-2); background:var(--surface-3); }
.ov-ic{ display:grid; place-items:center; width:1.25rem; height:1.25rem; flex:none; color:var(--ink-3); }
.ov-name{ flex:1; min-width:0; font-size:0.875rem; font-weight:650; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* El aviso baja a su propia línea, alineado con el nombre: así no lo parte el ancho de la tesela. */
.ov-state{ flex-basis:100%; min-width:0; padding-left:1.875rem; }
.ov-attn{ display:flex; align-items:baseline; gap:0.4375rem; font-size:0.8125rem; line-height:1.35; color:var(--ink-2); }
.ov-attn .dot{ transform:translateY(-0.0625rem); }
.ov-attn.warn{ color:var(--warn); } .ov-attn.crit{ color:var(--neg); }
.ov-state:empty{ display:none; }
/* ---- fin módulo: shell ---- */

/* ---- módulo: analytics · Analíticas ---- */
/* Color de texto por rol (antes style en línea): apagado, secundario, positivo, RX ↓ y TX ↑. */
.an-mute{ color:var(--ink-3); }
.an-dim{ color:var(--ink-2); }
.an-trait small{ display:block; margin-top:2px; font-size:0.7188rem; color:var(--ink-3); }
.an-pos{ color:var(--pos); }
.an-rx{ color:var(--s3); }
.an-tx{ color:var(--s4); }
.an-axis{ color:var(--ink-3); font-weight:600; }
.an-unit{ color:var(--ink-3); font-weight:500; }
.an-note{ color:var(--ink-3); font-size:0.7812rem; }
.an-mono{ font-family:var(--mono); font-size:0.7812rem; }
.tps.an-tps-low{ color:var(--serious); }
/* Muestras de color de leyendas y de la selección multi-nodo. */
.an-bg-s1{ background:var(--s1); }
.an-bg-rx{ background:var(--s3); }
.an-bg-tx{ background:var(--s4); }
.lk.an-lk-sq{ width:0.5625rem; height:0.5625rem; border-radius:var(--r-3); }
.lk.an-swatch{ width:0.8125rem; }
.lk.an-swatch-sm{ width:0.6875rem; }
.dot.an-dot-off{ background:var(--surface-4); }
/* Identidad en fila: muestra o avatar + id/nombre (tablas de Rendimiento y Jugadores). */
.an-ident{ display:flex; align-items:center; gap:0.5625rem; }
.an-ident--player{ gap:0.625rem; }
.an-stack{ display:flex; flex-direction:column; }
.avatar.an-avatar-sm{ width:1.75rem; height:1.75rem; font-size:0.7188rem; }
.an-grow{ flex:1; min-width:0; }
.an-gap-top{ margin-top:0.875rem; }
.an-gap-bottom{ margin-bottom:0.8125rem; }
/* Variantes de columnas de las listas de barras (nombre · pista · valor). */
.bar.an-bar-narrow{ grid-template-columns:5rem 1fr auto; }
.bar.an-bar-wide{ grid-template-columns:8.125rem 1fr auto; }
.bar.an-bar-label{ grid-template-columns:9.375rem 1fr auto; }
/* Nombre con etiqueta de tipo delante (Ocupación): sitio para la etiqueta y un id de nodo completo. */
.bar.an-bar-tag{ grid-template-columns:11.75rem 1fr auto; }
.bar.an-bar-funnel{ grid-template-columns:minmax(9.375rem,12.5rem) 1fr auto; }
.bar.an-bwbar{ display:flex; flex-direction:column; align-items:stretch; gap:0.375rem; width:100%; text-align:left; cursor:pointer; }
.an-bwhead{ display:flex; align-items:center; justify-content:space-between; gap:0.625rem; min-width:0; }
.an-bwhead .nm{ display:flex; align-items:center; gap:0.4375rem; min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
.trk i.an-fill-rx{ background:var(--s3); }
.miniback.an-tx-track{ margin-top:0; }
.miniback i.an-fill-tx{ background:var(--s4); }
.an-bwvals{ display:flex; gap:0.75rem; flex:none; white-space:nowrap; font-size:0.8125rem; font-weight:650; font-variant-numeric:tabular-nums; }
/* Plataformas: donut con la leyenda debajo y a todo el ancho; lista de versiones acotada. */
.donut-wrap.an-donut-stack{ flex-direction:column; gap:1rem; width:100%; }
.dleg.an-full{ width:100%; }
.donutbody.an-top{ justify-content:flex-start; }
.scrolly.an-scroll-400{ max-height:25rem; }
.vv.an-ver-n{ min-width:2.625rem; text-align:right; font-weight:650; font-variant-numeric:tabular-nums; }
/* Perfil de jugador. */
.backlink .ico{ width:0.875rem; height:0.875rem; }
.pdcell .v.an-v-text{ font-size:0.9375rem; }
.ms .v.an-v-small{ font-size:0.875rem; }
.uuid.an-ip{ font-size:0.8125rem; color:var(--ink-1); }
.an-subsec{ margin-top:0.875rem; border-top:1px solid var(--hair); padding-top:0.75rem; }
.an-sublabel{ font-size:0.7188rem; color:var(--ink-3); margin-bottom:0.4375rem; }
/* Procedencia. */
.an-geo-n{ font-size:0.8438rem; font-weight:650; font-variant-numeric:tabular-nums; }
.an-asn{ margin-top:0.75rem; border-top:1px solid var(--hair); padding-top:0.6875rem; font-size:0.7812rem; color:var(--ink-3); }
.an-asn b{ color:var(--ink-1); }
.cmpbar i.an-cmp-a{ background:var(--s1); }
.cmpbar i.an-cmp-b{ background:var(--s4); }
/* Punchcard: filas ARIA sin caja propia (las celdas siguen en la rejilla de .punch) e intensidad de cada
   celda como fracción --lv (0–1, en línea por celda) del color de marca, sin rgba en la plantilla. */
.punch .prow{ display:contents; }
.punch .cell.lv, .punchlegend .sc i.lv{
  background:color-mix(in srgb, var(--brand) calc(var(--lv, 0) * 100%), transparent); }
.punchlegend .sc i{ background:var(--surface-3); }
.punch .cell:focus-visible{ outline-offset:1px; position:relative; z-index:2; }
/* Comparaciones (TPS, ancho de banda, dominios): las series elegidas como chips con su color y una ×
   que la quita, en la misma franja que la leyenda de la gráfica. */
.an-selrow{ display:flex; align-items:center; flex-wrap:wrap; gap:0.375rem 0.5rem; min-height:1.875rem; padding:2px 1.0625rem 0.5rem; }
.chip.an-selchip{ gap:0.375rem; }
.chip.an-selchip .an-x{ margin-left:1px; font-size:0.875rem; line-height:1; color:var(--ink-3); }
.chip.an-selchip:hover .an-x{ color:var(--ink-1); }
/* Nota breve bajo el título de una tarjeta: qué mide y cómo leerlo. */
.an-cardnote{ margin:0; padding:0.625rem 1.0625rem 0; font-size:0.7812rem; line-height:1.5; color:var(--ink-3); }
.an-cardnote b{ color:var(--ink-2); font-weight:650; }
.an-cardnote:last-child{ padding-bottom:0.9375rem; }
.an-cardnote + .tblwrap{ margin-top:0.625rem; }
/* Dato que merece mirarse (un dominio que trae sobre todo jugadores nuevos). */
.an-hot{ color:var(--ink-1); font-weight:650; }
.kv .an-kv-host{ font-size:0.9375rem; overflow-wrap:anywhere; }
/* Cohortes de retención: la intensidad de cada celda es su porcentaje (--lv, 0–1, en línea por celda)
   del color de marca, como la punchcard; «—» es un plazo que aún no ha pasado y va sin fondo. */
.an-heat td.hc{ text-align:center; font-variant-numeric:tabular-nums;
  background:color-mix(in srgb, var(--brand) calc(var(--lv, 0) * 100%), transparent); }
.an-heat td.hc-na{ background:none; color:var(--ink-3); }
.an-heat th[scope="row"]{ padding:0.625rem 1.0625rem; border-top:1px solid var(--hair); white-space:nowrap; font-weight:500;
  text-align:left; }
.an-heat tbody tr:first-child th{ border-top:0; }
.an-heat td.hc{ padding:0.625rem 0.5rem; }
/* Selector de población de Abandono (Resumen · Nuevos · Veteranos), encima de la vista. */
.an-segbar{ display:flex; }
/* «Lo más importante»: una frase por fila, con la población que la dice. */
.an-insights{ margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:0.75rem; }
.an-insights li{ display:flex; align-items:baseline; gap:0.625rem; font-size:0.875rem; line-height:1.6; color:var(--ink-1); }
.an-insights .tag{ flex:none; min-width:4.75rem; justify-content:center; }
.an-insights b{ color:var(--ink-1); font-weight:650; }
/* Texto de la IA: markdown ligero a tamaño de lectura (títulos, párrafos, listas de dos niveles, negrita y
   código). El texto corrido va en ink-2 para que la negrita, en ink-1, marque de verdad lo importante. */
.an-md{ font-size:0.9375rem; line-height:1.68; color:var(--ink-2); }
.an-md p{ margin:0 0 0.75rem; text-wrap:pretty; }
.an-md h4{ margin:1.125rem 0 0.5rem; font-size:0.9375rem; font-weight:680; color:var(--ink-1); }
.an-md ul,.an-md ol{ margin:0 0 0.75rem; padding-left:1.375rem; }
.an-md li{ margin:0 0 0.5rem; padding-left:2px; }
.an-md li::marker{ color:var(--ink-3); }
.an-md li > ul{ margin:0.5rem 0 0; }
.an-md li > p{ margin:0.375rem 0 0; }
.an-md b{ color:var(--ink-1); font-weight:650; }
.an-md code{ font-family:var(--mono); font-size:.88em; color:var(--ink-1); background:var(--surface-3);
  padding:1px 0.3125rem; border-radius:var(--r-4); }
.an-md > :last-child{ margin-bottom:0; }
.an-steps{ margin:0.75rem 0 0; padding-left:1.25rem; font-size:0.875rem; line-height:1.7; color:var(--ink-1); }

/* ---- Jugadores · Análisis IA: cada parte del informe en su tarjeta, a tamaño de lectura ---- */
/* El texto corrido no pasa de ~82 caracteres por línea aunque la tarjeta sea ancha. */
.ai-prose .an-md{ max-width:82ch; }
/* La primera frase del diagnóstico es la conclusión: un punto más grande y en tinta plena. */
.ai-lead .an-md > p:first-child{ font-size:1rem; line-height:1.6; color:var(--ink-1); }
/* Acciones: numeradas por prioridad (el orden sí informa), con Por qué / Qué hacer / Cómo se verá. En una
   tarjeta ancha van en dos columnas; en una estrecha, una debajo de otra. */
.ai-acts{ list-style:none; margin:0; padding:0; display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,30rem),1fr));
  gap:1.75rem 2.5rem; }
.ai-act{ display:grid; grid-template-columns:1.875rem minmax(0,1fr); gap:0.875rem; align-content:start; }
.ai-act-n{ width:1.875rem; height:1.875rem; border-radius:50%; display:grid; place-items:center; background:var(--surface-3);
  border:1px solid var(--hair-2); color:var(--ink-1); font-size:0.875rem; font-weight:650; font-variant-numeric:tabular-nums; }
.ai-act-t{ margin:0.25rem 0 0.75rem; font-size:1rem; font-weight:650; line-height:1.4; color:var(--ink-1); text-wrap:balance; }
.ai-act-rows{ margin:0; display:grid; grid-template-columns:max-content minmax(0,1fr); gap:0.5rem 1rem; }
.ai-act-rows dt{ padding-top:2px; font-size:0.8125rem; font-weight:650; color:var(--ink-3); white-space:nowrap; }
.ai-act-rows dd{ margin:0; font-size:0.9375rem; line-height:1.6; color:var(--ink-2); text-wrap:pretty; }
.ai-act-rows dd b{ color:var(--ink-1); font-weight:650; }
.ai-act-note{ margin:0.5rem 0 0; font-size:0.9375rem; line-height:1.6; color:var(--ink-2); }
@media(max-width:640px){
  .ai-act-rows{ grid-template-columns:minmax(0,1fr); gap:2px; }
  .ai-act-rows dd{ margin-bottom:0.5rem; }
}

/* ---- Jugadores · Chat IA: un chat de verdad que ocupa la ventana; el hilo desplaza y la caja queda abajo ---- */
.content:has(.ai-chat){ padding-bottom:1.25rem; }
.ai-chat{ height:var(--ai-chat-h, calc(100dvh - 10.625rem)); min-height:27.5rem; display:flex; flex-direction:column; overflow:hidden; }
.ai-thread{ flex:1; min-height:0; overflow-y:auto; scrollbar-width:thin; scrollbar-color:var(--surface-4) transparent; }
.ai-col{ width:100%; max-width:55rem; margin:0 auto; padding:0 1.5rem; }
.ai-thread .ai-col{ min-height:100%; padding-top:1.625rem; padding-bottom:1.625rem; display:flex; flex-direction:column; gap:1.5rem; }
.ai-turn{ display:flex; gap:0.75rem; }
.ai-turn--user{ flex-direction:column; align-items:flex-end; gap:0.3125rem; }
.ai-bubble{ max-width:min(40rem,85%); padding:0.625rem 0.9375rem; border-radius:1rem 1rem 0.25rem 1rem; background:var(--brand-faint);
  border:1px solid var(--brand-line); color:var(--ink-1); font-size:0.9375rem; line-height:1.55; overflow-wrap:anywhere; }
.ai-avatar{ flex:none; width:1.875rem; height:1.875rem; border-radius:50%; display:grid; place-items:center; background:var(--surface-3);
  border:1px solid var(--hair-2); color:var(--brand); font:700 0.6875rem/1 var(--mono); }
.ai-turn-b{ flex:1; min-width:0; padding-top:0.3125rem; }
.ai-meta{ display:flex; align-items:baseline; gap:0.5rem; margin-bottom:0.5rem; font-size:0.875rem; }
.ai-meta b{ color:var(--ink-1); font-weight:650; }
.ai-time{ font-size:0.75rem; color:var(--ink-3); }
.ai-used{ display:flex; flex-wrap:wrap; align-items:center; gap:0.375rem; margin-top:0.75rem; font-size:0.7812rem; color:var(--ink-3); }
.ai-error{ display:flex; flex-wrap:wrap; align-items:center; gap:0.5rem 0.75rem; padding:0.6875rem 0.875rem; border-radius:var(--r-md);
  border:1px solid var(--neg-line); background:var(--neg-faint); color:var(--ink-1); font-size:0.9062rem; line-height:1.5; }
.ai-retry{ color:var(--brand); font-weight:650; }
.ai-welcome{ margin:auto 0; padding:1.5rem 0; text-align:center; }
.ai-welcome .ai-avatar{ width:2.875rem; height:2.875rem; margin:0 auto 1rem; font-size:0.875rem; }
.ai-welcome h2{ margin:0 0 0.5rem; font-size:1.3125rem; font-weight:680; letter-spacing:-.015em; color:var(--ink-1); text-wrap:balance; }
.ai-welcome p{ max-width:54ch; margin:0 auto; font-size:0.9062rem; line-height:1.55; color:var(--ink-3); }
.ai-suggest{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:0.625rem; margin-top:1.5rem; text-align:left; }
.ai-suggestion{ display:flex; flex-direction:column; gap:0.25rem; padding:0.8125rem 0.9375rem; border:1px solid var(--hair-2);
  border-radius:var(--r-md); background:var(--surface-2); color:var(--ink-2); font-size:0.875rem; line-height:1.45; text-align:left;
  transition:border-color .15s var(--ease), background .15s var(--ease); }
.ai-suggestion b{ color:var(--ink-1); font-size:0.9062rem; font-weight:650; }
.ai-suggestion:hover{ border-color:var(--brand-line); background:var(--surface-3); }
.ai-dock{ flex:none; padding:0.875rem 0 0.75rem; border-top:1px solid var(--hair); background:var(--surface-1); }
.ai-composer{ display:flex; align-items:flex-end; gap:0.5rem; padding:0.375rem 0.375rem 0.375rem 0.9375rem; border:1px solid var(--field-line);
  border-radius:0.875rem; background:var(--surface-2); transition:border-color .15s var(--ease), box-shadow .15s var(--ease); }
.ai-composer:focus-within{ border-color:var(--brand); box-shadow:0 0 0 0.1875rem var(--brand-faint); }
.ai-composer textarea{ flex:1; min-height:1.5rem; max-height:12.5rem; padding:0.4375rem 0; resize:none; border:0; background:transparent;
  color:var(--ink-1); font:inherit; font-size:0.9375rem; line-height:1.5; }
.ai-composer textarea:focus-visible{ outline:none; }
.ai-composer textarea::placeholder{ color:var(--ink-3); }
.ai-send{ flex:none; width:2.25rem; height:2.25rem; display:grid; place-items:center; border-radius:0.625rem; background:var(--brand);
  color:var(--on-accent); transition:background .15s var(--ease); }
.ai-send .ico{ width:1.125rem; height:1.125rem; stroke-width:2.2; }
.ai-send:disabled{ background:var(--surface-4); color:var(--ink-3); cursor:not-allowed; }
.ai-hint{ margin:0.5625rem 0 0; text-align:center; font-size:0.7812rem; color:var(--ink-3); }
.an-typing{ display:inline-flex; gap:0.25rem; padding:0.375rem 0; }
.an-typing i{ width:0.4375rem; height:0.4375rem; border-radius:50%; background:var(--ink-3); animation:an-typing 1.2s infinite ease-in-out; }
.an-typing i:nth-child(2){ animation-delay:.15s; } .an-typing i:nth-child(3){ animation-delay:.3s; }
@keyframes an-typing{ 0%,80%,100%{ opacity:.3; transform:translateY(0); } 40%{ opacity:1; transform:translateY(-3px); } }
@media (prefers-reduced-motion:reduce){ .an-typing i{ animation:none; } .ai-suggestion,.ai-composer,.ai-send{ transition:none; } }
@media(max-width:640px){ .ai-suggest{ grid-template-columns:minmax(0,1fr); } .ai-col{ padding:0 0.875rem; } .ai-bubble{ max-width:92%; } }
/* Retención por modo: cada servidor sangrado bajo su grupo. */
.an-indent{ padding-left:1rem; color:var(--ink-2); }
tr.an-member td{ font-size:0.8125rem; }
/* ---- fin módulo: analytics ---- */

/* ---- módulo: currency · Divisas ---- */
/* Barras de reparto (emisión por fuente, quema por concepto, tramos de saldo): columna de etiqueta fija
   para que las pistas arranquen alineadas; la variante ancha para los tramos. */
.dv-bars .bar{ grid-template-columns:9.375rem 1fr 4.625rem; }
.dv-bars--wide .bar{ grid-template-columns:10.625rem 1fr 4.625rem; }
.trk i.dv-in{ background:var(--good); }
.trk i.dv-out{ background:var(--crit); }
/* Muestra cuadrada de leyenda para barras y donut (la .lk base es una línea, propia de las series). */
.lk.dv-sq{ width:0.5625rem; height:0.5625rem; border-radius:var(--r-3); }
/* Donut «Suministro por economía»: lienzo arriba, leyenda centrada debajo. */
.dv-center{ display:flex; align-items:center; justify-content:center; }
.dv-donut{ display:flex; flex-direction:column; align-items:center; gap:1rem; }
.dv-donut-legend{ display:flex; flex-wrap:wrap; justify-content:center; gap:0.5rem 1.25rem; }
/* Importe de los rankings con el color de su sentido. */
.lead-v.dv-gem{ color:var(--gem); }
.lead-v.dv-pos{ color:var(--pos); }
.lead-v.dv-neg{ color:var(--neg); }
/* Filtros del libro dentro de su tarjeta, separados de la tabla. flex:none: un .cb crece (flex:1) y se
   repartiría la altura de la tarjeta a medias con el .tblwrap del libro. */
.dv-filters{ flex:none; display:flex; flex-direction:column; gap:0.5rem; border-bottom:1px solid var(--hair); }
.dv-input{ width:9.375rem; }
.dv-input--num{ width:5.25rem; }
.dv-hint{ margin:0; font-size:0.75rem; color:var(--ink-3); }
.dv-hint b{ color:var(--ink-2); font-weight:650; }
/* Libro: fecha, tipo e importe nunca se parten en dos líneas; en estrecho la tabla se desplaza en su
   .tblwrap en vez de apilar «Pago / enviado». */
.dv-ledger td:first-child,.dv-ledger .tag,.dv-ledger td.num{ white-space:nowrap; }
/* Segunda línea de una celda del libro: reparto por bolsa, actor y motivo. */
.dv-sub{ display:block; margin-top:2px; font-size:0.75rem; font-weight:400; color:var(--ink-3); }
/* Segunda línea de una celda (contexto de lo de arriba: categoría, mundo y nodo, ranura…), en tono bajo. */
.cell-sub{ display:block; margin-top:2px; font-size:0.75rem; font-weight:400; color:var(--ink-3); white-space:normal; }
.more .field-err{ align-self:center; margin-left:0.625rem; }
@media(max-width:720px){ .dv-input,.dv-input--num{ width:100%; } }
/* ---- fin módulo: currency ---- */

/* ---- módulo: trace · Trace ---- */
/* Categoría en la barra compartida: el select ops-control a su ancho natural, no al 100 % de un fgroup
   que se ajusta a su contenido (el porcentaje no tiene contra qué resolverse). */
.ops-control.trace-fsel{ width:auto; min-width:8.25rem; }
/* «Ver sensibles» y «Forzar»: casilla nativa .ops-check con su etiqueta en línea. */
.trace-toggle{ display:inline-flex; align-items:center; gap:0.5rem; font-size:0.8125rem; color:var(--ink-2); cursor:pointer; }
/* Ámbito de una operación: los filtros de Actividad como texto, con el chip para editarlos. */
.trace-scope{ display:flex; align-items:center; flex-wrap:wrap; gap:0.5rem; min-height:2.25rem;
  font-size:0.8438rem; color:var(--ink-1); }
/* Registro de eventos: ids de nodo, momentos y coordenadas en una línea (la tabla hace scroll propio
   antes que partir «game-1» o «100 / 64 / -2000» en dos). */
.trace-events td.tnum,.trace-events .nid{ white-space:nowrap; }
/* Payload desplegado bajo su evento: el pozo de .logview, más bajo y con ajuste de línea (un JSON largo
   no ensancha la tabla). */
.trace-payload > td{ padding-top:0; }
.trace-payload .logview{ max-height:min(40vh,22.5rem); white-space:pre-wrap; overflow-wrap:anywhere; }
/* Filtros avanzados plegables: la cabecera de la tarjeta es el <summary>; abre y cierra con un clic. */
.trace-adv > summary{ cursor:pointer; list-style:none; }
.trace-adv > summary::-webkit-details-marker{ display:none; }
.trace-adv > summary::after{ content:'▾'; margin-left:auto; color:var(--ink-3); transition:transform .15s var(--ease); }
.trace-adv:not([open]) > summary{ border-bottom:0; }
.trace-adv:not([open]) > summary::after{ transform:rotate(-90deg); }
.trace-adv-hint{ font-size:0.8125rem; color:var(--ink-3); }
@media (prefers-reduced-motion:reduce){ .trace-adv > summary::after{ transition:none; } }
/* Política editable: los controles de la tabla no se encogen por debajo de lo legible. */
.trace-poltable .ops-control{ min-width:7rem; }
/* ---- fin módulo: trace ---- */

/* ---- módulo: discipline · Discipline ---- */
/* «Avanzado» del formulario de sanción: la misma rejilla de 12 columnas que .ops-form, dentro de un
   fieldset bordeado (agrupa los overrides sin inventar otra tarjeta). Alineado arriba: solo algunos
   campos llevan .field-err, y alinear abajo desnivelaba sus controles. */
.dc-advanced{ grid-column:1 / -1; display:grid; grid-template-columns:repeat(12,minmax(0,1fr)); gap:0.875rem;
  align-items:start; min-width:0; margin:0; padding:0.625rem 0.875rem 0.875rem; border:1px solid var(--hair);
  border-radius:var(--r-md); }
.dc-advanced > legend{ padding:0 0.375rem; }
.dc-hint{ grid-column:1 / -1; margin:0; font-size:0.8125rem; color:var(--ink-3); }
/* Identificadores secundarios en una línea; el motivo, texto libre, se parte sin ensanchar la tabla. */
.dc-view .uuid{ white-space:nowrap; }
.ops-table td.dc-reason{ min-width:10rem; max-width:22.5rem; overflow-wrap:anywhere; }
@media(max-width:720px){
  .dc-advanced{ grid-template-columns:1fr; gap:0.75rem; }
}
/* ---- fin módulo: discipline ---- */

/* ---- módulo: custody · Custody ---- */
/* (reglas del módulo custody) */
/* ---- fin módulo: custody ---- */

/* ---- módulo: enderstorage · EnderStorage ---- */
/* Rejilla de la bóveda: 9 columnas como el inventario del juego. Cada hueco es un resumen de sólo
   lectura (material abreviado + cantidad en la esquina, la convención del propio juego). */
.ender-grid{ display:grid; grid-template-columns:repeat(9,minmax(0,1fr)); gap:0.375rem; width:min(100%,45rem); margin:0 auto; }
.ender-slot{ position:relative; display:grid; place-items:center; min-width:0; aspect-ratio:1; border:1px solid var(--hair-2);
  border-radius:var(--r-sm); background:var(--surface-3); color:var(--ink-1); font-family:var(--mono); font-size:0.75rem; }
.ender-slot.is-empty{ background:var(--surface-2); border-color:var(--hair); }
.ender-slot:focus-visible{ outline:2px solid var(--brand); outline-offset:2px; }
.ender-slot b{ position:absolute; right:0.25rem; bottom:2px; color:var(--value); font-size:0.75rem; }
.ender-material{ overflow:hidden; max-width:calc(100% - 0.5rem); color:var(--ink-2); font-size:0.6875rem; }
.ender-readonly{ margin:0 0 0.75rem; color:var(--ink-3); font-size:0.8125rem; }
@media(max-width:720px){
  .ender-grid{ gap:0.1875rem; }
  .ender-slot{ border-radius:var(--r-3); }
  .ender-material{ font-size:0.5625rem; }
  .ender-slot b{ right:2px; bottom:1px; font-size:0.625rem; }
}
/* ---- fin módulo: enderstorage ---- */

/* ---- módulo: spawnercontrol · SpawnerControl ---- */
/* Desplegable del filtro «Grupo» cuando hay demasiados grupos para una fila de píldoras: el ancho lo da
   el contenido, no el 100 % de .ops-control (dentro de un .fgroup en línea se colapsaría). */
.fgroup .sc-groupsel{ width:auto; min-width:9.375rem; max-width:16.25rem; }
/* Ajuste booleano: la casilla con su zona táctil y el estado en texto, en una sola línea. */
.sc-toggle{ display:inline-flex; align-items:center; gap:0.375rem; min-height:2.25rem; font-size:0.8438rem; color:var(--ink-1); }
/* Historial: la UUID del jugador en una sola línea (partida por los guiones no se puede leer ni copiar). */
.sc-history .uuid{ white-space:nowrap; }
/* ---- fin módulo: spawnercontrol ---- */

/* ---- módulo: logs · Logs ---- */
/* Filtro de grupo en la barra compartida: un select y no píldoras, porque una red con muchos grupos
   desbordaba la subnav. .ops-control ocupa el 100% de su contenedor; dentro de un .fgroup en línea eso
   no es un ancho, así que se acota aquí a algo legible que no empuje la barra. */
.logs-group{ width:auto; min-width:7.5rem; max-width:13.75rem; }
/* ---- fin módulo: logs ---- */
