/* ============================================================
   Portal del socio — mobile first, un despliegue para todos los gyms.
   El color de acento lo pinta cada gimnasio (variable --acento desde JS).
   Modo claro: [data-tema="claro"] — existe SOLO aquí, por decisión D4.
   ============================================================ */

:root{
  --bg:#0B0C0E;
  --surface:#111318;
  --card:#171A20;
  --card-2:#1E222A;
  --line:rgba(174,180,189,.14);
  --line-hi:rgba(220,226,235,.28);
  --text:#F4F6F8;
  --muted:#9AA1AA;
  /* Semaforo: fijo en todos los temas (ley 2 de diseno). Lo LEIA el rayo de
     app.js para la chispa ambar; antes iba cocido ahi. Hoy no lo lee ningun JS
     —la cara del socio se mudo a Flutter, y app.js dejo de ser alcanzable—,
     pero se queda: es un token de diseno y su valor es el que usa la cara
     nueva. */
  --amber:#F5A524;
  /* La tinta como triplete, para los bordes y los velos que van del color del
     texto: `rgb(var(--tinta-rgb) / .07)`. Es lo que hace que UNA regla funcione
     en los dos temas sin declarar un token por tema. Se consumia desde el
     rayado de la meta «sin dato» y no existia: la barra se quedaba lisa. */
  --tinta-rgb:244 246 248;

  /* La superficie de un campo. Es un token y no `--surface` a secas porque en
     los dos temas tiene que hundirse RESPECTO A LA TARJETA, y eso cae de lados
     distintos: en oscuro la tarjeta es mas clara que el fondo, en claro es
     blanca y hay que bajar al gris. Con `--surface` fijo, un campo en tema
     claro quedaba exactamente del color de su tarjeta y solo se veia por la
     raya de un pixel — que es justo el aspecto de formulario sin terminar. */
  --campo:var(--surface);

  --acento:#E10E1E;
  --acento-rgb:225 14 30;
  /* El texto que va ENCIMA del acento. Lo reescribe `marcaDelGym()`
     (portal/js/casa.js) al entrar, decidiéndolo por luminancia del color que
     eligió el gimnasio: con un acento oscuro —el rojo de fábrica, un azul— el
     blanco se lee perfecto, y con uno claro —un amarillo, un lima— desaparece y
     hay que bajar a tinta. No lleva variante por tema porque quien manda es el
     color del gimnasio, no el fondo de la pantalla: el botón principal es del
     mismo acento en claro y en oscuro. El valor de aquí es el del acento de
     fábrica, y sirve de red mientras la marca del gym no ha llegado. */
  --acento-texto:#fff;
  /* Los dos blancos que NO se mueven con el tema. Son tokens y no literales
     sueltos para que el candado del CSS (servidor/pruebas-casa-css.mjs) no
     tenga que permitir `#fff` en toda la hoja: permitido en un sitio, deja de
     ver el blanco cocido de cualquier otro.
       · El papel del código QR: un lector lee por contraste y espera fondo
         claro, así que el papel es blanco también en tema claro.
       · El texto de la celebración de récord: va sobre un velo casi negro
         (`.fiesta`), que es el mismo en los dos temas. */
  --qr-papel:#fff;
  --velo-texto:#fff;
  --verde:#27E08A;
  --ambar:#F5A524;
  --rojo:#FF5B66;
  /* El semaforo tambien como triplete: los chips, las alertas y las insignias
     lo piden con opacidad, y cocer el `rgba()` era cocer el color — en claro el
     texto se oscurecia y su fondo se quedaba con el tono del oscuro. */
  --verde-rgb:39 224 138;
  --ambar-rgb:245 165 36;
  --rojo-rgb:255 91 102;

  --f-display:"Archivo","Segoe UI",sans-serif;
  --f-mono:"JetBrains Mono",Consolas,monospace;
  --f-body:"Inter","Segoe UI",sans-serif;

  /* Los dos escalones que se repiten en toda la casa: el nombre fuerte de una
     fila y su renglon de apoyo en gris. Estaban escritos a mano en veintitantas
     reglas —de ahi que hubiera 13.5, 14 y 14.5 px para lo mismo— y alinearlos
     costo tocarlas una por una. Ahora la escala vive aqui. */
  --letra-nom:14px;
  --letra-sub:12px;
  --radius:16px;
  --ease:cubic-bezier(.22,.8,.3,1);
  --resorte:cubic-bezier(.2,.9,.3,1.15);
}

:root[data-tema="claro"]{
  --bg:#F2F3F6;
  --surface:#FFFFFF;
  --card:#FFFFFF;
  --card-2:#EDEFF3;
  --line:rgba(30,40,55,.12);
  --line-hi:rgba(30,40,55,.22);
  --text:#171A20;
  --muted:#5D6570;
  /* Semaforo: fijo en todos los temas (ley 2 de diseno). Igual que en el tema
     oscuro de arriba: ya no lo lee ningun JS, y se queda por ser token. */
  --amber:#F5A524;
  --tinta-rgb:23 26 32;
  --campo:var(--card-2);
  /* El semaforo NO cambia de significado —vencido es vencido en los dos temas—,
     solo se oscurece para que se LEA sobre blanco: el verde #27E08A daba 1.7:1
     de contraste, muy por debajo del piso de 3:1. Son los mismos valores que ya
     usan los temas claros del sistema local (sitio/css/tema.css). */
  --verde:#0E8A52;
  --ambar:#B45309;
  --rojo:#D92D20;
  --verde-rgb:14 138 82;
  --ambar-rgb:180 83 9;
  --rojo-rgb:217 45 32;
}

*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
  font-family:var(--f-body);
  background:
    radial-gradient(700px 420px at 80% -10%, var(--surface) 0%, transparent 60%),
    var(--bg);
  color:var(--text);
  font-size:15px;line-height:1.5;
  -webkit-font-smoothing:antialiased;
}
img{max-width:100%;display:block}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
input{font:inherit;color:var(--text)}
a{color:inherit;text-decoration:none}
:focus-visible{outline:2px solid rgb(var(--acento-rgb) / .8);outline-offset:2px;border-radius:6px}

.display{font-family:var(--f-display);font-weight:900;font-stretch:125%;text-transform:uppercase;letter-spacing:.5px;line-height:.95}
.mono{font-family:var(--f-mono);font-variant-numeric:tabular-nums}

#app{max-width:520px;margin:0 auto;min-height:100vh;display:flex;flex-direction:column;padding:0 16px}

@keyframes sube{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
.vista{animation:sube .4s var(--ease);padding-bottom:96px;flex:1}
.vista.centrada{display:flex;flex-direction:column;justify-content:center;padding-bottom:24px}

/* ---------- Tarjetas ----------
   UNA superficie para los tres nombres que la casa le da a lo mismo: la tarjeta
   del socio, la seccion del dueño y el desplegable. Estaban declaradas tres
   veces y ya habian empezado a separarse —solo la primera tenia sombra—, asi
   que en la misma pantalla convivian tarjetas con relieve y «secciones»
   planas. Lo que cada una tiene de suyo (el relleno) vive en su sitio. */
.card,.seccion,.plegado{
  background:linear-gradient(180deg,var(--card),var(--surface));
  border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:0 12px 30px rgba(0,0,0,.25);
  margin-bottom:14px;
  animation:sube .45s var(--ease) backwards;
}
.card{padding:16px}
:root[data-tema="claro"] :is(.card,.seccion,.plegado){box-shadow:0 8px 24px rgba(20,30,45,.08)}
/* El titulo de una tarjeta, de una seccion y de un desplegable: el mismo
   trabajo, tres nombres. Era mono de 10px en mayusculas con dos pixeles de
   tracking —un «eyebrow»— encima de CADA tarjeta de la casa: la cadencia que
   mas hace parecer generada una pantalla, y ademas la mono aqui no numera
   nada. Ahora es lo que es, un titulo, en la fuente del cuerpo. */
.c-label,.seccion h2,.plegado>summary{
  font-family:var(--f-body);font-size:var(--letra-nom);font-weight:600;
  color:var(--text);line-height:1.35;margin-bottom:10px;
}
.plegado>summary{margin-bottom:0}
/* La misma clase hace dos trabajos y el segundo es etiquetar un campo. Ahi se
   comporta como `.field label`, no como titulo: si las dos cosas pesan igual,
   el formulario deja de tener jerarquia. */
label.c-label{font-size:12.5px;font-weight:500;color:var(--muted)}

/* ---------- Botones ---------- */
/* Caja normal y fuente de cuerpo. En mono, en mayusculas y con tracking, un
   texto largo se partia en tres renglones dentro del boton — esta escrito en
   app.js como el motivo de sacar el nombre de la clase fuera del boton. */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;width:100%;
  font-family:var(--f-body);font-size:15px;font-weight:600;line-height:1.25;
  padding:14px 20px;border-radius:14px;transition:transform .15s,box-shadow .2s;
}
.btn:active{transform:scale(.97)}
/* Apagado mientras la peticion vuela. El JS lo deshabilita en once sitios
   —mandar el anuncio, lanzar el reto, pedir a la barra, liberar el lugar— y sin
   esta regla el boton se veia EXACTAMENTE igual que antes de tocarlo: la gente
   lo tocaba otra vez, y con razon. */
.btn:disabled{opacity:.55;cursor:not-allowed}
.btn:disabled:active{transform:none}
.btn-acento{
  background:linear-gradient(180deg,rgb(var(--acento-rgb) / .95),rgb(var(--acento-rgb) / .75));
  color:var(--acento-texto);box-shadow:0 8px 24px rgb(var(--acento-rgb) / .35);
}
.btn-borde{border:1px solid var(--line-hi);color:var(--muted)}
.btn-borde:hover{color:var(--text)}
/* El tercer boton, el de salida discreta: «Volver», «Entrar con otra cuenta».
   El JS lo pedia en cuatro sitios y el CSS no lo definia, asi que se pintaba
   con el mismo peso que la accion principal y sin ninguna forma propia. */
.btn-texto{color:var(--muted);font-weight:500}
.btn-texto:hover{color:var(--text)}

/* ---------- Lo que se elige tocando ----------
   Un solo idioma para el mismo gesto: los filtros del dueño (`.pill`), las
   opciones del socio (`.opciones button`), el selector de ejercicio y los chips
   del café eran CUATRO metricas distintas —11, 12, 12.5 y 13px, dos en mono y
   en mayusculas, cuatro radios— para elegir exactamente igual.

   Los 44px de alto no son estetica: es el minimo que un pulgar acierta sin
   mirar, y estas son las piezas que mas se tocan de la casa. */
.pill,
.opciones button,
.sel-ejercicio button,
.cf-chip{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:44px;padding:8px 16px;border-radius:999px;
  border:1px solid var(--line);background:transparent;color:var(--muted);
  font-family:var(--f-body);font-size:13px;font-weight:600;line-height:1.2;
  white-space:nowrap;cursor:pointer;
  transition:border-color .16s var(--ease),background .16s var(--ease),color .16s var(--ease);
}
.pill:hover,
.opciones button:hover,
.sel-ejercicio button:hover,
.cf-chip:hover{border-color:var(--line-hi);color:var(--text)}
.pill.on,
.opciones button.on,
.sel-ejercicio button.on,
.cf-chip.on{border-color:rgb(var(--acento-rgb) / .55);background:rgb(var(--acento-rgb) / .12);color:var(--text)}
.pill:disabled,
.opciones button:disabled,
.sel-ejercicio button:disabled,
.cf-chip:disabled{opacity:.5;cursor:not-allowed}

/* ---------- Campos ---------- */
.field{margin-bottom:14px}
.field label{display:block;font-family:var(--f-body);font-size:12.5px;font-weight:500;color:var(--muted);margin-bottom:7px}
/* La unidad que acompaña a una etiqueta —«Peso (kg)»— no es una cita: va
   derecha, como el resto. */
.field label em{font-style:normal;opacity:.85}
/* El campo. Los 16px NO son estetica: por debajo de eso iOS hace zoom al
   enfocar y desencuadra la pantalla entera. */
.input{
  width:100%;background:var(--campo);border:1px solid var(--line);border-radius:12px;
  padding:14px;font-size:16px;font-family:var(--f-body);color:var(--text);
  transition:border-color .16s var(--ease),box-shadow .16s var(--ease);
}
.input:hover{border-color:var(--line-hi)}
.input:focus{outline:none;border-color:rgb(var(--acento-rgb) / .6);box-shadow:0 0 0 3px rgb(var(--acento-rgb) / .14)}

/* Sin flechitas en las casillas de monto: no existe «el siguiente peso», y esos
   doce píxeles son justo lo que hace pensar que el campo es una perilla en vez
   de un renglón donde se escribe. La rueda del mouse la paraba el
   guardia de js/app.js, que ya no corre —esa cara vive en Flutter—; hoy la para
   la cara nueva. Se repite aquí y no se hereda de `sitio/css/sistema.css` porque el
   portal es otra aplicación y no comparte hojas con el mostrador. */
.input[data-dinero]::-webkit-outer-spin-button,
.input[data-dinero]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.input[data-dinero]{-moz-appearance:textfield;appearance:textfield}
.input:disabled{opacity:.55;cursor:not-allowed}
/* El texto de ejemplo tambien tiene que leerse: el gris de fabrica del
   navegador no llega al contraste minimo en ninguno de los dos temas. */
.input::placeholder{color:var(--muted);opacity:1}
/* Un area de texto con presencia: es la pieza principal de la pantalla donde
   vive, y una caja de una linea invita a escribir una linea. */
textarea.input{resize:vertical;min-height:92px;line-height:1.5}

/* ---------- El desplegable ----------
   Un `<select>` de fabrica es lo mas generico que puede haber en una pantalla:
   trae la flecha del SISTEMA OPERATIVO —distinta en cada telefono—, su propia
   caja y su propio tipo de letra, y no obedece a ningun tema. Se le quita la
   apariencia nativa y se le dibuja la flecha con dos bordes, del color del
   texto apagado: asi es la misma pieza en los dos temas y en los dos sistemas.

   La flecha va en un envoltorio y no en el propio `select` porque un `select`
   no pinta pseudo-elementos: `::after` sobre el no se dibuja en ningun
   navegador. */
.select-caja{position:relative;display:block}
.select-caja::after{
  position:absolute;right:15px;top:50%;margin-top:-6px;
  pointer-events:none;transform:rotate(45deg);
}
select.input{appearance:none;-webkit-appearance:none;padding-right:40px;cursor:pointer}
/* La lista desplegada la dibuja el sistema y casi no se puede tocar; lo unico
   que obedece es el color de cada opcion, y sin esto Windows la abre en blanco
   sobre una app oscura. Una lista propia hecha con divs se veria mejor y seria
   peor: dejaria fuera el teclado, el lector de pantalla y la rueda del telefono. */
select.input option{background:var(--campo);color:var(--text)}

/* El icono del calendario de un campo de fecha lo pinta el navegador en negro.
   Sobre un campo oscuro es un cuadro invisible que hay que adivinar. */
:root:not([data-tema="claro"]) .input[type="date"]::-webkit-calendar-picker-indicator{filter:invert(1)}
.input[type="date"]::-webkit-calendar-picker-indicator{opacity:.6;cursor:pointer}
.input[type="date"]:hover::-webkit-calendar-picker-indicator{opacity:1}

/* ---------- La marca del gimnasio ----------
   Aqui vivia ademas la portada con el BUSCADOR de gimnasios (`.hero`,
   `.gym-item`, `.gym-nombre`, `.gym-sub`). Esa pantalla no existe: cada
   gimnasio tiene su propio despliegue y su propia direccion, asi que no hay
   nada que buscar. Solo sobrevive el logo, que lo pinta `logoHTML()`. */
.gym-logo{
  width:44px;height:44px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--card-2);font-family:var(--f-display);font-weight:900;font-size:16px;
  box-shadow:inset 0 0 0 1px var(--line-hi);overflow:hidden;
}
.gym-logo img{width:100%;height:100%;object-fit:cover}

/* ---------- Cabecera del gym / app ---------- */
.gym-cab{display:flex;align-items:center;gap:13px;padding:22px 0 16px}
.gym-cab .gym-logo{width:52px;height:52px}
.gym-cab .g-nom{font-family:var(--f-display);font-weight:900;font-size:21px;letter-spacing:.5px}
.gym-cab .g-lema{font-family:var(--f-body);font-size:12px;color:var(--muted)}
/* El nombre del gimnasio cede antes que el boton: sin esto, un nombre largo
   —«Gimnasio Fuerza Total del Norte»— empujaba «Cerrar sesión» fuera de la
   pantalla. Un elemento flexible no encoge por debajo de su contenido mientras
   no se le diga que puede. */
.gym-cab>span{min-width:0}
.gym-cab .g-nom,.gym-cab .g-lema{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gym-cab .cerrar{margin-left:auto;flex:none;white-space:nowrap;color:var(--muted);font-size:12px;padding:8px 0}

/* ---------- Aviso ---------- */
.aviso{border:1px solid var(--line);background:var(--surface);border-radius:12px;padding:12px 14px;font-size:13px;margin-bottom:14px}
.aviso.rojo{border-color:rgb(var(--rojo-rgb) / .4);background:rgb(var(--rojo-rgb) / .08);color:var(--rojo)}
.aviso.ambar{border-color:rgb(var(--ambar-rgb) / .4);background:rgb(var(--ambar-rgb) / .08);color:var(--ambar)}
.aviso.verde{border-color:rgb(var(--verde-rgb) / .4);background:rgb(var(--verde-rgb) / .08);color:var(--verde)}

/* ---------- Navegación inferior ---------- */
.tabs-pie{
  position:fixed;left:0;right:0;bottom:0;z-index:20;
  display:flex;justify-content:center;gap:2px;
  background:color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter:blur(14px);
  border-top:1px solid var(--line);
  padding:8px 10px calc(10px + env(safe-area-inset-bottom));
}
.tabs-pie button{
  flex:1;max-width:120px;display:flex;flex-direction:column;align-items:center;gap:4px;
  min-height:52px;padding:7px 4px;border-radius:12px;color:var(--muted);
  font-family:var(--f-body);font-size:10.5px;font-weight:500;line-height:1.2;
  transition:color .2s,background .2s;
}
.tabs-pie svg{width:20px;height:20px}
.tabs-pie button.on{color:var(--text);background:rgb(var(--acento-rgb) / .14)}
.tabs-pie button.on svg{color:rgb(var(--acento-rgb) / 1);filter:drop-shadow(0 0 8px rgb(var(--acento-rgb) / .6))}

/* ---------- Hoy: rutina y captura ---------- */
.dia-titulo{font-family:var(--f-body);font-size:13px;font-weight:600;color:var(--muted);margin:16px 0 8px}
.dia-titulo.hoy{color:rgb(var(--acento-rgb) / 1)}
.ej-fila{
  display:flex;align-items:flex-start;gap:11px;padding:11px 2px;
  border-bottom:1px solid var(--line);
}
.ej-fila:last-child{border-bottom:none}
/* El nombre y, debajo, la nota del entrenador. Columna y no una sola linea:
   la nota puede ser larga y recortarla con puntos suspensivos se lleva justo la
   parte que avisa («…no bloquees la rodilla»). */
.ej-nom{display:flex;flex-direction:column;gap:3px;font-weight:600;font-size:14px;flex:1;min-width:0}
.ej-nota{font-weight:500;font-size:11.5px;line-height:1.35;color:var(--muted)}
.ej-meta{font-family:var(--f-mono);font-size:11px;color:var(--muted)}
.ej-pr{font-family:var(--f-mono);font-size:10.5px;color:var(--ambar);font-weight:700}

.captura{display:grid;grid-template-columns:1fr 1fr auto;gap:9px;align-items:end}
.captura .btn{width:auto;padding:14px 18px}

/* ---------- KPIs ---------- */
.kpis{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:14px}
/* La rejilla ya separa con `gap`: el margen de la tarjeta sobra y ademas
   descuadra las columnas. */
.kpis>.card{margin-bottom:0}
.kpi{padding:14px}
/* La etiqueta de ARRIBA, cuando el numero necesita que le digan de que es antes
   de leerlo. Debajo va `.k-sub`, que matiza lo que ya se leyo. */
.kpi .k-lbl{font-size:12px;font-weight:500;color:var(--muted);margin-bottom:2px}
.kpi .k-num{font-family:var(--f-mono);font-weight:700;font-size:26px;font-variant-numeric:tabular-nums;line-height:1.1}
/* La unidad pegada a la cifra («1.4 t»): mas chica y en gris, o compite con el
   numero. El JS ya la marcaba y el CSS no la definia, asi que salia del mismo
   tamaño que la cifra. */
.kpi .k-uni{font-family:var(--f-body);font-size:14px;font-weight:500;color:var(--muted);margin-left:2px}
.kpi .k-sub{font-family:var(--f-body);font-size:12px;color:var(--muted);margin-top:3px}

/* ---------- Gráficas (ApexCharts) ----------
   La librería trae su propio CSS; aquí solo va lo que tiene que obedecer al
   tema del gimnasio y al modo claro. Las gráficas se dibujan en js/graficas.js. */

.graf{width:100%;min-height:200px}
.apexcharts-canvas{margin:0 auto}

.apexcharts-tooltip.apexcharts-theme-dark,
.apexcharts-tooltip.apexcharts-theme-light{
  background:var(--card-2) !important;
  border:1px solid var(--line-hi) !important;
  border-radius:12px !important;
  box-shadow:0 12px 30px rgba(0,0,0,.4) !important;
  color:var(--text) !important;
  font-family:var(--f-body);
}
.apexcharts-tooltip-title{
  background:rgb(var(--acento-rgb) / .08) !important;
  border-bottom:1px solid var(--line) !important;
  font-family:var(--f-mono) !important;
  font-size:10px !important;letter-spacing:1.2px;text-transform:uppercase;
  color:var(--muted) !important;
  padding:7px 11px !important;margin:0 !important;
}
.apexcharts-tooltip-series-group{padding:6px 11px !important}
.apexcharts-tooltip-text-y-value{font-family:var(--f-mono);font-weight:700}
.apexcharts-legend-text{color:var(--text) !important;font-family:var(--f-body) !important}
.apexcharts-xaxistooltip{display:none !important}

/* ---------- El número que manda ----------
   La cifra grande arriba de la curva. El verde y el rojo son fijos: subir es
   subir aunque el gimnasio sea azul. */
.bottom-line{margin-bottom:12px}
.bottom-line .bl-eti{
  font-family:var(--f-body);font-size:12.5px;font-weight:500;color:var(--muted);
  margin-bottom:5px;
}
.bottom-line .bl-fila{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
/* Ancho proporcional en la cifra grande: el ancho fijo (que sí queremos en ejes
   y tablas) deja huecos entre dígitos y a este tamaño se ve floja. */
.bottom-line .bl-num{
  font-family:var(--f-mono);font-weight:700;font-variant-numeric:proportional-nums;
  font-size:34px;letter-spacing:-1.2px;line-height:1;
}
.bottom-line .bl-pie{margin-top:6px;font-size:12px;color:var(--muted)}

.bl-badge{
  display:inline-flex;align-items:center;gap:5px;flex:none;
  padding:4px 9px;border-radius:999px;
  font-family:var(--f-mono);font-size:11px;font-weight:700;
  border:1px solid transparent;
}
.bl-badge svg{width:11px;height:11px}
.bl-badge.sube{color:var(--verde);background:rgb(var(--verde-rgb) / .13);border-color:rgb(var(--verde-rgb) / .3)}
.bl-badge.baja{color:var(--rojo);background:rgb(var(--rojo-rgb) / .13);border-color:rgb(var(--rojo-rgb) / .3)}
.bl-badge.igual,
.bl-badge.neutra{color:var(--muted);background:rgb(var(--tinta-rgb) / .08);border-color:var(--line)}
.bl-badge .bl-nota{font-weight:500;color:var(--muted)}

/* ---------- Estado vacío de una gráfica ----------
   Un panel en blanco parece que la app falló. Esto dice por qué está vacío y
   ofrece el botón que lo llena. */
.vacio-graf{
  position:relative;overflow:hidden;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;gap:9px;padding:30px 16px;min-height:180px;
  border:1px dashed var(--line-hi);border-radius:var(--radius);
}
.vacio-graf::before{
  content:"";position:absolute;left:50%;top:12%;width:200px;height:200px;
  transform:translateX(-50%);pointer-events:none;
  background:radial-gradient(circle, rgb(var(--acento-rgb) / .12) 0%, transparent 68%);
}
.vacio-graf>*{position:relative}
.vacio-graf .vg-ico{width:54px;height:54px;color:var(--muted);opacity:.8}
.vacio-graf .vg-tit{font-size:14px;font-weight:600;color:var(--text)}
.vacio-graf .vg-sub{font-size:12.5px;color:var(--muted);max-width:32ch;line-height:1.5}
.vacio-graf .vg-cta{
  margin-top:4px;padding:11px 20px;border-radius:999px;
  font-size:13px;font-weight:700;color:var(--acento-texto);
  background:rgb(var(--acento-rgb) / 1);
  box-shadow:0 8px 22px rgb(var(--acento-rgb) / .35);
}
.vacio-graf .vg-cta:active{transform:scale(.97)}

/* ---------- Récords / medallas ---------- */
.pr-fila{display:flex;align-items:baseline;gap:10px;padding:9px 2px;border-bottom:1px solid var(--line)}
.pr-fila:last-child{border-bottom:none}
.pr-ej{font-weight:600;font-size:var(--letra-nom);flex:1}
.pr-peso{font-family:var(--f-mono);font-weight:700;font-size:16px;color:rgb(var(--acento-rgb) / 1)}
.pr-fecha{font-family:var(--f-mono);font-size:10px;color:var(--muted)}

.medallas{display:flex;flex-wrap:wrap;gap:10px}
.medalla{
  display:flex;flex-direction:column;align-items:center;gap:5px;width:76px;
  padding:10px 4px;border-radius:12px;background:var(--surface);border:1px solid var(--line);
  font-family:var(--f-body);font-size:11px;font-weight:500;line-height:1.3;color:var(--muted);text-align:center;
}
.medalla svg{width:26px;height:26px;color:var(--ambar)}

/* ---------- Racha ---------- */
.racha{display:flex;align-items:center;gap:16px}
.racha .r-num{font-family:var(--f-mono);font-weight:700;font-size:38px;color:rgb(var(--acento-rgb) / 1)}
.racha .r-txt{font-size:12.5px;color:var(--muted)}

/* ---------- QR ---------- */
.qr-caja{display:grid;place-items:center;padding:16px 0 6px}
.qr-caja canvas,.qr-caja svg{background:var(--qr-papel);border-radius:14px;padding:12px}
.qr-pie{text-align:center;font-family:var(--f-body);font-size:12px;color:var(--muted);line-height:1.4;margin-top:10px}

/* ---------- Vencimiento ---------- */
.vence-tira{display:flex;align-items:center;justify-content:space-between;gap:10px}
.vence-dias{font-family:var(--f-mono);font-weight:700;font-size:22px}

/* ---------- Selector de tema ---------- */
/* Los botones van con el resto de lo que se elige tocando, arriba. */
.opciones{display:flex;gap:8px;flex-wrap:wrap}

/* ---------- Toast ---------- */
.toast{
  position:fixed;left:50%;bottom:88px;transform:translateX(-50%) translateY(30px);
  background:var(--card-2);border:1px solid rgb(var(--verde-rgb) / .4);color:var(--verde);
  font-family:var(--f-body);font-size:13px;font-weight:500;
  padding:12px 20px;border-radius:12px;opacity:0;z-index:60;
  /* Las cuatro que cambian de verdad, enumeradas. `all` animaba tambien lo que
     nadie mueve y, peor, lo que se le agregue a esta regla despues. opacity y
     transform son la entrada y la salida (.toast.show); border-color y color
     son el salto de info a error, que SI transiciona porque casa.js reutiliza
     el mismo nodo y le reescribe `data-tipo` en cada aviso. */
  transition:opacity .3s var(--resorte),transform .3s var(--resorte),border-color .3s var(--resorte),color .3s var(--resorte);
  max-width:92vw;text-align:center;
}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
.toast[data-tipo="error"]{border-color:rgb(var(--rojo-rgb) / .5);color:var(--rojo)}

/* ---------- Celebración de récord ---------- */
.fiesta{
  position:fixed;inset:0;z-index:70;display:grid;place-items:center;
  background:rgba(4,5,7,.78);backdrop-filter:blur(4px);
  opacity:0;pointer-events:none;transition:opacity .25s;
}
.fiesta.on{opacity:1;pointer-events:auto}
.fiesta canvas{position:absolute;inset:0;width:100%;height:100%}
.fiesta-caja{position:relative;text-align:center;animation:pr-slam .6s var(--resorte)}
.fiesta-caja .f-tit{font-family:var(--f-display);font-weight:900;font-stretch:125%;font-size:44px;text-transform:uppercase;color:var(--velo-texto);text-shadow:0 0 34px rgb(var(--acento-rgb) / .9)}
.fiesta-caja .f-det{font-family:var(--f-mono);font-size:15px;color:var(--velo-texto);margin-top:10px}
.fiesta-caja .f-antes{opacity:.6;text-decoration:line-through;margin-right:10px}
@keyframes pr-slam{0%{transform:scale(1.6);opacity:0;filter:blur(8px)}62%{transform:scale(.96);opacity:1;filter:blur(0)}100%{transform:scale(1)}}

.vacio{padding:26px 10px;text-align:center;color:var(--muted);font-size:13px}
/* Un vacio con titulo y explicacion. Los dos van en su renglon: `<b>` y `<span>`
   son de linea, asi que «Nada agendado» y su explicacion salian pegados en una
   sola frase corrida — en la agenda del entrenador, en los canales y en los
   retos, que es donde se escribio ese patron. */
.vacio b{display:block;color:var(--text);font-size:var(--letra-nom);font-weight:600;margin-bottom:4px}
.vacio>span{display:block}
.centro{text-align:center}
.sep{height:1px;background:var(--line);margin:14px 0}

/* ============================================================
   Piezas compartidas de la casa: lo que usan las cuatro caras y no tenia
   sitio propio, o lo tenia repetido con tres medidas distintas.
   ============================================================ */

.mt{margin-top:10px}
.mb{margin-bottom:12px}

/* El titulo de un GRUPO de tarjetas, fuera de todas ellas. Es lo que evita la
   tarjeta anidada cuando varias cosas distintas pertenecen al mismo asunto: el
   grupo se nombra en el aire y las tarjetas cuelgan debajo. */
.grupo-titulo{font-size:16px;font-weight:600;color:var(--text);margin:22px 2px 10px}
.grupo-titulo:first-child{margin-top:6px}

/* Lo que estaba escrito a mano, nodo por nodo, con `style="…"`. Un tamaño de
   letra copiado en seis sitios es seis sitios donde puede quedarse distinto. */
.parrafo{font-size:15px;line-height:1.5}
.pregunta{font-size:19px;line-height:1.35}
.entre{display:flex;align-items:center;justify-content:space-between;gap:10px}
/* La tarjeta que solo contiene una lista de filas: las filas ya traen su propio
   aire, y el relleno normal de tarjeta las dejaba flotando. */
.card-lista{padding:6px 14px}
.captura .field{margin:0}
/* El codigo corto del pase, para dictarlo si el lector no toma el QR. */
.codigo-corto{font-size:26px;font-weight:700;letter-spacing:6px;margin-top:8px}

/* El centro de avisos usa la fila de dos textos que ya existia (`.dato-fila`);
   lo unico suyo es que lo no leido pesa y lo leido se apaga. Se clono entera
   para cambiarle dos propiedades, y esas dos subieron al componente. */
.dato-fila>span:first-child{flex:1;min-width:0}
.dato-fila .leido{font-weight:500;color:var(--muted)}
.dato-fila .cuando{font-size:10.5px;color:var(--muted);flex:none}
/* Un aviso que LLEVA a algún lado es un botón, no un renglón de texto: así lo
   anuncia el teclado, el lector de pantalla y el dedo. Se le quita el aspecto de
   botón —fondo, borde, alineación— y se le deja el ancho completo y la mano,
   que es lo único que tiene que decir. */
.fila-aviso{
  display:flex;width:100%;background:none;border:0;padding:inherit;
  font:inherit;color:inherit;text-align:left;cursor:pointer;
}
.fila-aviso:hover .fila-nom{color:var(--acento)}
.fila-aviso:focus-visible{outline:2px solid var(--acento);outline-offset:2px;border-radius:8px}
/* El veredicto del gimnasio a una solicitud (pausa, renovacion). */
.estado-linea{font-size:13px}

/* Una fila de lista: UN solo dato fuerte —el nombre— y el resto en gris. Sin
   esto cada fila era dos textos del mismo peso separados por un `<br>`. */
/* El color va explicito: esta clase se usa tambien dentro de `.dato-fila`, que
   apaga sus hijos directos para que la etiqueta quede en gris. */
.fila-nom{font-size:var(--letra-nom);font-weight:600;line-height:1.35;color:var(--text)}
.fila-sub{display:block;font-size:var(--letra-sub);color:var(--muted);line-height:1.4;margin-top:2px}

/* Una casilla con su texto, tocable entera y no solo en el cuadrito. */
.fila-check{display:flex;align-items:center;gap:10px;min-height:44px;font-size:14px;cursor:pointer}
.fila-check input{width:18px;height:18px;flex:none;accent-color:var(--acento)}

/* Una seccion con titulo, y un desplegable. Los dos son la MISMA caja que
   `.card`; existen porque la cara del dueño escribia `<section>` y `<h2>`
   pelados, y un selector de elemento se derrama sobre cualquier cara que
   estrene esa etiqueta. La superficie se declara una vez con `.card` —arriba—
   y aqui solo va lo que cada una tiene de suyo. */
.seccion{padding:15px}
/* Con subtitulo, el titulo se le pega y el aire va debajo de los dos. Donde
   `:has()` no exista, el titulo se queda con su margen y la unica diferencia
   es que el subtitulo respira un poco mas. */
.seccion h2:has(+ .sub){margin-bottom:3px}
/* El subtitulo de una seccion. Sirve dentro de una tarjeta, dentro de un
   desplegable y suelto en la pantalla: es el mismo trabajo en los tres sitios. */
.sub{font-size:12.5px;color:var(--muted);line-height:1.5;margin-bottom:12px}
:is(.seccion,.plegado) table{width:100%;border-collapse:collapse;font-size:var(--letra-nom)}
:is(.seccion,.plegado) td{padding:9px 0;border-bottom:1px solid rgb(var(--tinta-rgb) / .08);vertical-align:top}
:is(.seccion,.plegado) tr:last-child td{border-bottom:none}
/* Los numeros a la derecha y de ancho fijo; el texto, a la izquierda. */
:is(.seccion,.plegado) td:last-child{text-align:right;font-family:var(--f-mono);font-variant-numeric:tabular-nums;color:var(--muted);white-space:nowrap}

/* Lo que se consulta de vez en cuando, plegado. Es como una pantalla larga deja
   de ser una lista de diez bloques: arriba lo que manda, abierto; lo demas a un
   toque de distancia. */
.plegado>summary{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  min-height:48px;padding:13px 15px;cursor:pointer;list-style:none;
}
.plegado>summary::-webkit-details-marker{display:none}
/* El titulo y su contador van juntos a la izquierda; la flecha, al otro lado. */
.plegado>summary>span{display:inline-flex;align-items:center;gap:8px;flex:1;min-width:0}
/* La flecha, dibujada con dos bordes: no pide ningun archivo y obedece al tema.
   Es la MISMA que marca un desplegable de formulario; lo unico distinto es
   donde se pone y que esta gira al abrirse. */
.plegado>summary::after,.select-caja::after{
  content:"";width:8px;height:8px;
  border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);
}
.plegado>summary::after{
  flex:none;margin-right:3px;
  transform:translateY(-2px) rotate(45deg);transition:transform .18s var(--ease);
}
.plegado[open]>summary::after{transform:translateY(2px) rotate(-135deg)}
.plegado-cuerpo{padding:0 15px 15px}

/* ---------- pestaña Clases (F11) ---------- */
.cl-dia{
  font-family:var(--f-body);font-size:13px;font-weight:600;color:var(--muted);
  margin:16px 0 4px;
}
.cl-dia:first-of-type{margin-top:8px}
.cl-fila{
  display:flex;align-items:center;gap:10px;padding:11px 2px;
  border-bottom:1px solid var(--line);
}
.cl-fila:last-child{border-bottom:none}
.cl-datos{flex:1;min-width:0}
.cl-tit{font-size:var(--letra-nom);font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cl-sub{font-size:var(--letra-sub);color:var(--muted);margin-top:2px}
/* `width:auto` NO es adorno: `.btn` trae `width:100%` para el boton grande de una
   tarjeta, y aqui el boton vive DENTRO de un renglon flex. Sin anularlo se lleva
   el ancho entero, aplasta `.cl-datos` y el titulo se parte en un caracter por
   linea con el boton encima. */
.cl-btn{flex:none;width:auto;padding:8px 13px;font-size:12px}
/* «Añadir a mi calendario». Va DEBAJO del título y con letra de nota, nunca
   como `.btn`: en este renglón el botón de acción es uno solo y suelta o aparta
   un lugar. Algo que se le parezca a su lado invita a tocar el equivocado.
   El área de toque llega a los 32px con el padding vertical aunque la letra
   sea de 12: un enlace de un dedo de alto no se toca, se falla. */
.cl-cal{
  display:inline-block;margin-top:5px;padding:4px 0;
  background:none;border:none;font:inherit;font-size:var(--letra-sub);
  color:var(--muted);text-decoration:underline;text-underline-offset:3px;cursor:pointer;
}
.cl-cal:hover{color:var(--acento)}
.cl-chip{
  flex:none;font-size:11px;font-weight:600;padding:3px 9px;border-radius:999px;
  border:1px solid var(--line-hi);color:var(--muted);
}
.cl-chip.dentro{border-color:rgb(var(--acento-rgb) / .5);color:rgb(var(--acento-rgb) / 1);background:rgb(var(--acento-rgb) / .1)}
.cl-chip.espera{border-style:dashed}
.cl-chip.fuera{text-decoration:line-through}
.cl-chip.lleno{opacity:.75}
/* Lo que aprieta. Se marca con el acento pero SIN relleno, para que no compita
   con «Tienes tu lugar», que es el unico estado que le pertenece al socio. */
.cl-chip.aprieta{border-color:rgb(var(--acento-rgb) / .45);color:var(--text)}
/* En la fila: presente pero en voz baja. El socio no tiene lugar todavia. */
.cl-chip.en-fila{border-style:dashed;border-color:rgb(var(--acento-rgb) / .4)}
/* El lugar OFRECIDO es lo unico de esta pantalla que caduca en minutos, y por
   eso es lo unico que se pinta relleno y con latido. La animacion respeta a
   quien pidio que nada se mueva. */
.cl-chip.ofrecida{
  border-color:rgb(var(--acento-rgb) / .7);color:var(--text);
  background:rgb(var(--acento-rgb) / .16);animation:latido 2.4s ease-in-out infinite;
}
@keyframes latido{50%{background:rgb(var(--acento-rgb) / .3)}}
@media (prefers-reduced-motion:reduce){.cl-chip.ofrecida{animation:none}}

/* ---------- La tira de dias ----------
   Se desplaza sola en horizontal: catorce dias no caben en un telefono, y
   encogerlos hasta que quepan da casillas que se tocan por error. El pulgar la
   arrastra, que es como se navega una app de verdad. */
.cl-tira{
  display:flex;gap:6px;overflow-x:auto;padding:2px 0 8px;margin-bottom:2px;
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
}
.cl-tira::-webkit-scrollbar{display:none}
.cl-dia-chip{
  flex:none;display:flex;flex-direction:column;align-items:center;gap:2px;
  min-width:46px;padding:7px 8px 6px;border-radius:12px;
  border:1px solid var(--line-hi);background:transparent;color:var(--muted);
  font:inherit;cursor:pointer;
}
.cl-dia-chip.todos{justify-content:center;font-size:12px;font-weight:600;padding:7px 13px}
.cl-dia-chip .d{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.04em}
.cl-dia-chip .n{font-size:16px;font-weight:600;line-height:1.1;color:var(--text)}
.cl-dia-chip.on{
  border-color:rgb(var(--acento-rgb) / .55);background:rgb(var(--acento-rgb) / .12);color:var(--text);
}
.cl-dia-chip:focus-visible{outline:2px solid var(--acento);outline-offset:1px}
/* La densidad: un punto por clase, hasta tres. Dice de un vistazo que el martes
   esta cargado y el jueves tiene una sola, sin escribir un numero que a este
   tamaño no se leeria. El punto del acento es "aqui tienes lugar", que es la
   pregunta con la que el socio abre su app. */
.cl-densidad{display:flex;gap:2px;align-items:center;height:6px}
.cl-densidad i{width:3px;height:3px;border-radius:50%;background:rgb(var(--tinta-rgb) / .45)}
.cl-densidad i.mia{width:5px;height:5px;background:var(--acento)}

/* Lo que sigue de la misma serie cuando esta clase ya no tiene lugar. Colgado
   del renglon de arriba —sangrado y sin borde propio— para que se lea como su
   continuacion y no como otra clase mas de la lista. */
.cl-proxima{
  display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;
  margin:-2px 0 10px;padding:8px 11px;border-radius:10px;
  background:rgb(var(--tinta-rgb) / .05);font-size:12px;color:var(--muted);
}

.cl-veredictos{margin-bottom:10px}
.cl-veredicto{
  font-size:12px;padding:8px 11px;border-radius:9px;margin-bottom:6px;
  border:1px solid var(--line-hi);color:var(--muted);
}
.cl-veredicto.bien{border-color:rgb(var(--acento-rgb) / .45);color:var(--text)}
/* El rechazo. El JS lo marcaba desde que existe la pestaña y el CSS solo
   definia `.bien`: «tu reserva no entro» se leia igual que un aviso neutro. */
.cl-veredicto.mal{border-color:rgb(var(--rojo-rgb) / .4);background:rgb(var(--rojo-rgb) / .07);color:var(--rojo)}
.cl-avisos-txt{font-size:12.5px;color:var(--muted);margin:0 0 12px}
.cl-avisos-nota{font-size:12px;color:var(--muted);margin-top:10px;min-height:15px}

/* ---------- Eventos (E5) ----------
   Se pintan con las piezas de las clases —`cl-fila`, `cl-tit`, `cl-chip`— y
   aqui solo vive lo que un evento tiene y una clase no: una descripcion que
   explica de que va, y el aviso de que ya se transfirio. */

/* La descripcion, recortada a dos renglones. Un taller puede traer un parrafo
   entero y no puede empujar al boton fuera de la pantalla; dos renglones bastan
   para saber si interesa, que es la decision que se toma en esta lista. */
.ev-desc{
  font-size:var(--letra-sub);color:var(--muted);line-height:1.45;margin-top:4px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
/* «Ya transferi»: mismo trato que «Añadir a mi calendario» y por el mismo
   motivo. En este renglon el boton de accion es UNO y aparta o suelta el lugar;
   algo que se le parezca al lado invita a tocar el equivocado. El area de toque
   llega a 32px con el relleno vertical aunque la letra sea de 12. */
.ev-avisar{
  display:inline-block;margin-top:5px;padding:4px 0;
  background:none;border:none;font:inherit;font-size:var(--letra-sub);
  color:var(--muted);text-decoration:underline;text-underline-offset:3px;cursor:pointer;
}
.ev-avisar:hover{color:var(--acento)}

/* ---------- Paquetes de sesiones (P7) ----------
   El total se lee como la racha y con la misma pieza visual, porque responde a
   la misma pregunta de un vistazo: un numero grande y una frase que lo explica.
   Reusa el gesto, no la clase, porque lo que hay debajo es una lista de compras
   y no un texto suelto. */
.pq-total{display:flex;align-items:center;gap:16px;margin-bottom:6px}
.pq-num{font-family:var(--f-mono);font-weight:700;font-size:38px;color:rgb(var(--acento-rgb) / 1)}
.pq-txt{font-size:12.5px;color:var(--muted);line-height:1.45}

/* Las sesiones que quedan de UNA compra. En mono y tabular para que la columna
   se lea de arriba abajo sin bailar. */
.pq-libres{
  flex:none;font-size:17px;font-weight:700;font-variant-numeric:tabular-nums;
  color:var(--text);
}
/* Una compra sin saldo no se esconde: se apaga. Enseñarla igual de fuerte que
   una viva haria buscar dos veces cual sirve. */
.pq-libres.gastado{color:var(--muted);opacity:.6}

/* ---------- Avisos de transferencia ----------
   Los tres tonos de un aviso. `espera` es el estado normal —el gimnasio aun no
   mira su cuenta— y va en gris a proposito: un aviso en revision no es una
   alarma ni un logro, y pintarlo de color haria que «confirmada» dejara de
   distinguirse, que es la unica que de verdad cambia algo. */
.tr-espera{color:var(--muted)}
.tr-bien{color:var(--verde)}
.tr-mal{color:var(--rojo)}

/* ---------- pestaña Café (C6) ----------
   Reusa el chip de las clases —es el mismo idioma: "esperando", "listo",
   "no se pudo"— y sólo añade lo suyo: la fila de la carta con su contador y el
   pedido vivo destacado. */
.cf-fila{
  display:flex;align-items:center;gap:10px;padding:11px 2px;
  border-bottom:1px solid var(--line);
}
.cf-fila:last-child{border-bottom:none}
.cf-datos{flex:1;min-width:0}
.cf-nom{font-size:var(--letra-nom);font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cf-cat{font-size:var(--letra-sub);color:var(--muted);margin-top:2px}
.cf-precio{font-size:13px;font-weight:600;font-variant-numeric:tabular-nums}

/* ---------- Las secciones del menú ----------
   Lo que convierte la lista en una carta. Un menú impreso separa sus bloques con
   aire y una raya, no con una tarjeta por bloque: meter cada sección en su propia
   caja partiría la conversación («qué pido») en cinco pantallas.

   La raya y el aire van en el `+`, o sea SOLO ENTRE secciones: una línea encima
   de la primera la separaría del texto de la tarjeta, que es justo lo que la
   introduce. Y así el gimnasio que todavía no armó su menú —un único grupo, sin
   título— pinta exactamente la lista de antes, sin una regla de más. */
.cf-sec+.cf-sec{margin-top:16px;padding-top:14px;border-top:1px solid var(--line-hi)}
/* Un escalón por encima del nombre de un producto, y también por encima del
   título de la tarjeta. No es un descuido: dentro de una carta, los nombres de
   las secciones SON la estructura que el ojo recorre, y «La barra» es solo el
   rótulo de la caja que las contiene.

   En la fuente del cuerpo y en caja normal. No es un «eyebrow» en mayúsculas y
   mono: esa cadencia se retiró de la casa entera por hacer que todo pareciera
   generado, y una carta es justo donde más se notaría. */
.cf-sec-tit{font-size:15px;font-weight:700;line-height:1.3}
/* Lo que el dueño quiere decir de la sección entera («se preparan al momento»).
   Va debajo del título y no al lado: es una frase, no una etiqueta. */
.cf-sec-nota{font-size:var(--letra-sub);color:var(--muted);margin-top:3px}
.cf-sec-tit+.cf-fila,.cf-sec-nota+.cf-fila{margin-top:8px}
/* El último renglón de una sección no lleva raya: la que separa ya la pone la
   siguiente sección, y dos líneas a catorce píxeles se leen como un error. */
.cf-sec .cf-fila:last-child{border-bottom:none}

/* La descripción que el dueño escribió para vender el producto. Se corta a dos
   renglones: el servidor acepta 240 caracteres y una carta donde un solo
   producto ocupa media pantalla deja de ser una carta. */
.cf-desc{
  font-size:var(--letra-sub);color:var(--muted);margin-top:3px;line-height:1.4;
  display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}

/* Lo que la casa recomienda. Del acento del gimnasio y no del semáforo: no es un
   estado (vencido/al corriente), es una opinión del negocio — y el semáforo no
   se tematiza. Píldora chica dentro del renglón de apoyo, no una insignia
   encima del nombre: el nombre del producto es lo que se lee primero y nada
   debería quitarle el sitio. */
.cf-top{
  display:inline-block;margin-right:6px;padding:1px 7px;border-radius:999px;
  background:rgb(var(--acento-rgb) / .16);color:var(--text);
  font-size:11px;font-weight:600;
}

/* La foto de la carta. Cuadrada y chica: es una lista, no una galería — lo que
   se busca es reconocer el licuado de un vistazo mientras se baja con el pulgar.
   `cover` recorta y nunca deforma: una fruta estirada se ve peor que una fruta a
   la que le falta una esquina. */
.cf-foto{
  width:44px;height:44px;flex:none;border-radius:10px;object-fit:cover;display:block;
  background:var(--card-2);border:1px solid var(--line);
}
/* Sin foto, la inicial. Nunca un hueco: una carta a medio fotografiar no puede
   verse rota, y el gimnasio las sube poco a poco. */
.cf-foto-vacia{
  display:grid;place-items:center;font-size:15px;font-weight:700;color:var(--muted);
}
/* Lo que alimenta, en chico. Debajo del nombre y no al lado del precio: es un
   dato del producto, no del cobro. */
.cf-nutri{font-size:11px;color:var(--muted);margin-top:3px;font-variant-numeric:tabular-nums}
/* Lo que hoy no se puede. Apagado y sin botón, en vez de dejarlo pedir para que
   le rebote: el rechazo llega igual, pero después de esperar.

   Se apagan la foto, el nombre y el precio, pero NO el motivo: «Hoy no se
   puede» es la respuesta del negocio y es lo unico que hay que poder leer de
   esa fila. Va en los hijos y no en la fila entera porque un `opacity` en el
   padre no se puede deshacer desde dentro — apagaba tambien el aviso. */
.cf-fila-no .cf-foto,
.cf-fila-no .cf-nom,
.cf-fila-no .cf-precio{opacity:.45}
.cf-fila-no .cf-cat{color:var(--ambar)}

/* ¿Para cuándo? Chips, uno solo a la vez. */
.cf-cuando{display:flex;flex-wrap:wrap;gap:7px;margin-top:7px}
/* Su forma va con el resto de lo que se elige tocando, arriba. */

/* Pedir lo mismo otra vez. Borde y no acento: es un atajo, y el botón que manda
   el pedido tiene que seguir siendo el único que grita. */
.cf-repetir{width:100%;margin-top:6px;margin-bottom:10px}

/* Lo que alimenta la combinación que se está armando, dentro de la hoja. */
.hoja-nutri{
  display:flex;flex-direction:column;gap:2px;margin:-4px 0 10px;
  font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums;
}
.hoja-nutri span{font-size:11px}
.cf-alerg{color:var(--ambar)}
.cf-mas{display:flex;align-items:center;gap:8px;flex:none}
/* 34px de lado: el mínimo que un pulgar acierta sin mirar. */
.cf-btn{
  width:34px;height:34px;border-radius:10px;font-size:17px;line-height:1;
  border:1px solid var(--line-hi);background:transparent;color:var(--text);cursor:pointer;
}
.cf-btn:disabled{opacity:.35;cursor:not-allowed}
.cf-n{font-size:14px;font-weight:700;min-width:14px;text-align:center;font-variant-numeric:tabular-nums}
.pedido-vivo{display:flex;align-items:center;gap:10px}
.pv-que{flex:1;min-width:0;font-size:14px;font-weight:600}
.pv-motivo{font-size:12px;color:var(--muted);margin-top:8px}
.pv-nota{font-size:12px;color:var(--muted);margin-top:10px}
.cf-viejo{
  display:flex;align-items:center;gap:10px;justify-content:space-between;
  font-size:12.5px;color:var(--muted);padding:7px 2px;
}

/* ---------- Lo que llevas ----------
   Separado de la carta por una línea y no por una tarjeta aparte: es la misma
   conversación ("qué pido") y meterlo en otra caja obligaría a mirar dos sitios
   para saber cuánto va. Cada combinación es su propio renglón, que es la razón
   de que exista: en la carta, «licuado» es uno; aquí, el de almendra y el de
   entera son dos cosas distintas con dos precios distintos. */
.cf-carrito{margin-top:14px;padding-top:12px;border-top:1px solid var(--line-hi)}
.cf-linea{display:flex;align-items:center;gap:10px;padding:9px 2px}

/* ---------- La hoja de variantes ----------
   Sube desde abajo porque se abre con el pulgar: en un teléfono, lo que se toca
   vive en el tercio inferior y un modal centrado obliga a estirar la mano. */
/* Nacio en el café y la usa tambien Ajustes del dueño, que no tiene nada de
   café: por eso se llama `hoja` a secas y no lleva el prefijo de la carta. */
.hoja{
  position:fixed;inset:0;z-index:65;display:flex;align-items:flex-end;
  background:rgb(0 0 0 / .55);backdrop-filter:blur(2px);
}
.hoja-caja{
  width:100%;max-height:86vh;overflow-y:auto;
  background:var(--card);border-top:1px solid var(--line-hi);
  border-radius:20px 20px 0 0;padding:10px 18px 20px;
  animation:cf-subir .18s var(--ease);
}
@media (min-width:560px){
  .hoja{align-items:center;justify-content:center;padding:24px}
  .hoja-caja{max-width:420px;border-radius:18px;border:1px solid var(--line-hi)}
}
@keyframes cf-subir{from{transform:translateY(14px);opacity:.6}to{transform:none;opacity:1}}

/* El tirador: la señal de "esto se cierra tirando hacia abajo", que es lo que
   un pulgar intenta antes de buscar un botón. */
.hoja-tirador{
  width:36px;height:4px;border-radius:2px;background:var(--line-hi);
  margin:2px auto 14px;
}
.hoja-nom{font-size:16px;font-weight:700;margin-bottom:4px}

.cf-grupo{margin-top:16px}
.cf-grupo-tit{font-size:13px;font-weight:600;margin-bottom:7px}
/* La regla del grupo, en el idioma de las etiquetas del resto de la app:
   mono, chica y en versalitas. Dice obligatorio/opcional sin gritar. */
.cf-grupo-reg{
  font-family:var(--f-body);font-size:11.5px;font-weight:500;
  color:var(--muted);margin-left:7px;
}

.cf-op{
  display:flex;align-items:center;gap:10px;padding:11px 12px;margin-bottom:7px;
  border:1px solid var(--line);border-radius:12px;cursor:pointer;
  transition:border-color .12s var(--ease),background .12s var(--ease);
}
.cf-op.on{border-color:rgb(var(--acento-rgb) / .55);background:rgb(var(--acento-rgb) / .07)}
/* Agotada se ve, no se esconde: "no hay leche de almendra" es una respuesta del
   negocio, y quitarla de la lista hace creer que nunca existió. */
.cf-op.agotada{opacity:.42;cursor:not-allowed}
.cf-op input{flex:none;accent-color:var(--acento)}
.cf-op-nom{flex:1;min-width:0;font-size:14px}
.cf-op-delta{font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--muted)}

.hoja-pie{display:grid;grid-template-columns:1fr 1.6fr;gap:10px;margin-top:20px}
.hoja-pie .btn{margin:0}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001s !important;transition-duration:.001s !important}
}

/* ============================================================
   LA CASA — lo que se agregó al unir las tres caras.

   La dirección: sobriedad de herramienta con momentos de fiesta. La app se
   siente seria —jerarquía por peso y tamaño, no por adornos; la mono SOLO para
   cifras; una cifra grande por pantalla— hasta que rompes un récord, y entonces
   celebra de verdad. Eso es lo que separa una herramienta de trabajo de un
   tablero de datos: saber cuándo callarse y cuándo aplaudir.

   Todo por tokens. Un color literal aquí es un bug, no un detalle: el dueño
   repinta su acento desde Ajustes y esa regla se queda con el color de fábrica
   mientras el resto ya es azul. Las dos excepciones legítimas están marcadas:
   el logotipo de Google (su marca no es nuestra para tematizar) y el semáforo.
   ============================================================ */

/* ---------- Login: el separador y Google ---------- */

.separador{display:flex;align-items:center;gap:12px;margin:18px 0 14px;color:var(--muted);font-size:12px}
.separador::before,.separador::after{content:"";flex:1;height:1px;background:var(--line)}

.btn-google,.btn-apple{display:flex;align-items:center;justify-content:center;gap:10px}
/* Los colores del logotipo van cocidos en el SVG a propósito: son la marca de
   Google, y repintarla con el acento del gimnasio la falsifica. */

/* ---------- Canales ---------- */

.lista-canales{display:flex;flex-direction:column;gap:2px}
.canal-fila{
  display:flex;align-items:center;gap:12px;width:100%;text-align:left;
  padding:12px 4px;border-radius:12px;transition:background .16s var(--ease);
}
.canal-fila:hover{background:var(--card-2)}
.canal-fila svg{color:var(--muted);flex-shrink:0}
/* La rueda con las iniciales de alguien. */
.canal-ini{
  width:40px;height:40px;flex-shrink:0;border-radius:12px;
  display:grid;place-items:center;
  font-family:var(--f-mono);font-size:13px;font-weight:600;color:var(--muted);
  background:var(--card-2);border:1px solid var(--line);
}
.canal-ini.es-gym{background:rgb(var(--acento-rgb) / .14);border-color:rgb(var(--acento-rgb) / .3);color:var(--text)}
.canal-txt{flex:1;min-width:0}
.canal-nom{display:block;font-weight:600;font-size:var(--letra-nom)}
.canal-sub{display:block;font-size:var(--letra-sub);color:var(--muted);margin-top:1px}

.canal-cab{display:flex;align-items:center;gap:10px;padding:4px 0 14px;border-bottom:1px solid var(--line);margin-bottom:14px}
.canal-cab .canal-nom{flex:1;font-size:16px}
.btn-icono{
  width:36px;height:36px;flex-shrink:0;border-radius:10px;display:grid;place-items:center;
  color:var(--muted);transition:background .16s var(--ease),color .16s var(--ease);
}
.btn-icono:hover{background:var(--card-2);color:var(--text)}
.btn-chip{
  font-family:var(--f-body);font-size:11px;font-weight:600;
  border:1px solid var(--line-hi);border-radius:999px;padding:5px 11px;color:var(--muted);
}

/* El hilo crece hacia arriba: lo último queda pegado a donde se escribe, que es
   donde está el pulgar y donde mira el ojo. */
.canal-hilo{display:flex;flex-direction:column;gap:10px;max-height:calc(100dvh - 260px);overflow-y:auto;padding-right:2px}
.msj{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:11px 13px}
.msj.de-quien-lleva{background:rgb(var(--acento-rgb) / .07);border-color:rgb(var(--acento-rgb) / .22)}
.msj.borrado{opacity:.45;font-style:italic}
.msj-cab{display:flex;align-items:baseline;gap:8px;margin-bottom:5px}
.msj-quien{font-size:12.5px;font-weight:600}
.msj-hace{font-family:var(--f-mono);font-size:10px;color:var(--muted);letter-spacing:.6px}
/* Borrar y reportar, los dos botoncitos de la cabecera del mensaje. El de
   reportar lo escribia el JS y el CSS no lo definia: salia como un caracter
   suelto pegado a la fecha. El `::before` estira el blanco de toque a los 44px
   que un pulgar acierta, sin mover nada de sitio. */
.msj-borrar,.msj-reportar{
  position:relative;margin-left:auto;color:var(--muted);font-size:17px;line-height:1;padding:2px 4px;
}
.msj-borrar::before,.msj-reportar::before{content:"";position:absolute;inset:-12px -8px}
.msj-borrar+.msj-reportar{margin-left:2px}
.msj-borrar:hover{color:var(--rojo)}
.msj-reportar:hover{color:var(--ambar)}
.msj-txt{font-size:14px;line-height:1.5;overflow-wrap:anywhere}

.canal-pie{display:flex;gap:8px;align-items:flex-end;margin-top:14px}
.canal-pie .input{flex:1;resize:none;min-height:44px;max-height:120px;line-height:1.4}
.btn-enviar{width:44px;height:44px;flex-shrink:0;padding:0;display:grid;place-items:center;border-radius:12px}
.canal-pie-mudo{
  margin-top:14px;text-align:center;font-size:12.5px;color:var(--muted);
  border:1px dashed var(--line-hi);border-radius:12px;padding:12px;
}

/* ---------- Aforo ---------- */

.aforo-cab{display:flex;align-items:baseline;gap:12px}
.aforo-num{font-size:40px;font-weight:700;line-height:1}
.aforo-como{
  font-family:var(--f-body);font-size:11px;font-weight:600;
  padding:4px 10px;border-radius:999px;border:1px solid var(--line-hi);color:var(--muted);
}
/* Los tres niveles del aforo SÍ se tematizan: no son el semáforo de membresía
   —que jamás se toca—, son "hay lugar / está lleno", y eso es marca. */
.aforo-como[data-nivel="medio"]{color:var(--text);border-color:rgb(var(--acento-rgb) / .4)}
.aforo-como[data-nivel="alto"]{color:var(--text);background:rgb(var(--acento-rgb) / .16);border-color:rgb(var(--acento-rgb) / .5)}
.aforo-barra{height:8px;border-radius:99px;background:var(--card-2);overflow:hidden;margin-top:12px}
.aforo-barra span{display:block;height:100%;background:rgb(var(--acento-rgb) / 1);transition:width .5s var(--ease)}
.aforo-horas{display:flex;align-items:flex-end;gap:3px;height:80px;margin-top:8px}
.aforo-hora{flex:1;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;height:100%;gap:5px}
.aforo-hora span{width:100%;background:var(--card-2);border-radius:4px 4px 0 0;min-height:4px}
.aforo-hora em{font-family:var(--f-mono);font-size:8.5px;color:var(--muted);font-style:normal}

/* ---------- Constancia (el calendario que se pinta) ---------- */

.heat{overflow-x:auto;padding-bottom:4px}
.heat-rejilla{display:flex;gap:3px}
.heat-col{display:flex;flex-direction:column;gap:3px}
.heat-dia{width:11px;height:11px;border-radius:3px;background:var(--card-2);display:block}
.heat-dia.fuera{opacity:0}
/* El escalon cero, el de «menos» en la leyenda. Se apoyaba en el fondo de
   `.heat-dia` y no existia como regla: la leyenda funcionaba de casualidad. */
.heat-dia.n0{background:var(--card-2)}
.heat-dia.n1{background:rgb(var(--acento-rgb) / .35)}
.heat-dia.n2{background:rgb(var(--acento-rgb) / .65)}
.heat-dia.n3{background:rgb(var(--acento-rgb) / 1)}
.heat-meses{display:grid;grid-auto-flow:column;gap:3px;font-family:var(--f-mono);font-size:9px;color:var(--muted);margin-bottom:5px}
.heat-leyenda{display:flex;align-items:center;gap:4px;margin-top:10px;font-family:var(--f-mono);font-size:9px;color:var(--muted)}

/* ---------- Metas ---------- */

.meta-fila{display:grid;grid-template-columns:1fr auto;gap:6px 10px;align-items:center;padding:10px 0;border-bottom:1px solid var(--line)}
.meta-fila:last-of-type{border-bottom:none}
.meta-fila.simple{grid-template-columns:1fr auto}
.meta-txt{display:flex;justify-content:space-between;align-items:baseline;gap:10px;grid-column:1}
.meta-nom{font-size:14px;font-weight:500}
.meta-num{font-size:15px;font-weight:700;color:rgb(var(--acento-rgb) / 1)}
.meta-barra{grid-column:1;height:6px;border-radius:99px;background:var(--card-2);overflow:hidden}
.meta-barra span{display:block;height:100%;background:rgb(var(--acento-rgb) / 1);transition:width .6s var(--ease)}
/* Una meta que todavia no tiene con que medirse: la barra se raya en lugar de
   quedarse en cero. Un cero se lee como "no has avanzado nada" y eso es otra
   cosa —y peor— que "nadie te ha tomado una medida". */
.meta-barra.sin-dato{background:repeating-linear-gradient(
  -45deg, var(--card-2) 0 5px, rgb(var(--tinta-rgb) / .05) 5px 10px)}
.meta-pie{grid-column:1;font-size:11.5px;color:var(--muted)}
/* `1 / -1` y no `span 2`: la fila crecio con el pie y una cuenta fija de filas
   dejaba la equis pegada arriba. */
.meta-cerrar{grid-row:1 / -1;grid-column:2;color:var(--muted);font-size:20px;line-height:1;padding:0 6px}
.meta-cerrar:hover{color:var(--rojo)}

/* ---------- Cuerpo y medidas ---------- */

.imc{display:flex;align-items:center;gap:16px;padding:6px 0 14px}
.imc-num{font-size:44px;font-weight:700;line-height:1;color:rgb(var(--acento-rgb) / 1)}
.imc-txt{display:flex;flex-direction:column;gap:2px;font-size:13px}
.imc-txt span{color:var(--muted)}
.nota-chica{font-size:12px;color:var(--muted);line-height:1.5;margin:6px 0 14px}

.medidas{display:grid;grid-template-columns:repeat(auto-fill,minmax(96px,1fr));gap:10px;margin-bottom:14px}
.medida{background:var(--card-2);border-radius:12px;padding:10px 11px}
.med-nom{display:block;font-family:var(--f-body);font-size:11.5px;font-weight:500;color:var(--muted)}
.med-val{display:block;font-size:19px;font-weight:700;margin-top:3px}
.med-val em{font-size:11px;font-style:normal;color:var(--muted);margin-left:2px}
.med-dif{display:block;font-family:var(--f-mono);font-size:10.5px;min-height:14px;color:var(--muted)}
/* Sube y baja NO son bueno y malo: bajar de peso es una meta y subir de brazo
   también. Se usa el acento y el gris, nunca el verde y el rojo del semáforo. */
.med-dif.sube{color:rgb(var(--acento-rgb) / 1)}
.med-dif.baja{color:var(--muted)}

.sel-ejercicio{display:flex;gap:7px;overflow-x:auto;padding-bottom:8px;margin-bottom:6px}
.sel-ejercicio button{flex-shrink:0}

.grupos{display:flex;flex-direction:column;gap:9px}
.grupo{display:grid;grid-template-columns:78px 1fr 46px;gap:10px;align-items:center;font-size:13px}
.gr-nom{color:var(--muted);text-transform:capitalize;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gr-barra{height:8px;border-radius:99px;background:var(--card-2);overflow:hidden}
.gr-barra i{display:block;height:100%;background:rgb(var(--acento-rgb) / .8)}
.gr-val{text-align:right;font-size:12px;color:var(--muted)}

.pr-compartir{margin-left:8px;color:var(--muted);padding:2px}
.pr-compartir:hover{color:rgb(var(--acento-rgb) / 1)}

/* ---------- Insignias ---------- */

.insignias{display:grid;grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:10px}
.insignia{
  display:flex;flex-direction:column;align-items:center;gap:6px;text-align:center;
  background:var(--card-2);border-radius:14px;padding:13px 8px;
  border:1px solid rgb(var(--acento-rgb) / .22);
}
.insignia svg{color:rgb(var(--acento-rgb) / 1)}
.insignia em{font-style:normal;font-size:10.5px;line-height:1.3;color:var(--muted)}
.siguiente-insignia{
  display:flex;justify-content:space-between;align-items:center;gap:10px;
  margin-top:12px;padding-top:12px;border-top:1px solid var(--line);
  font-size:12.5px;color:var(--muted);
}

/* ---------- Retos ---------- */

.reto-desc{font-size:13px;color:var(--muted);margin-bottom:10px;line-height:1.5}
.reto-meta{font-size:12.5px;color:var(--muted);margin-bottom:12px}
.reto-barra{height:8px;border-radius:99px;background:var(--card-2);overflow:hidden}
.reto-barra span{display:block;height:100%;background:rgb(var(--acento-rgb) / 1);transition:width .6s var(--ease)}
.reto-avance{font-size:12px;color:var(--muted);margin:6px 0 12px}
.reto-tabla{list-style:none;display:flex;flex-direction:column;gap:1px;margin-bottom:12px}
.reto-tabla li{display:grid;grid-template-columns:26px 1fr auto;gap:10px;align-items:center;padding:8px 8px;border-radius:9px;font-size:14px}
.reto-tabla li.yo{background:rgb(var(--acento-rgb) / .12)}
.reto-tabla .pos{font-size:11px;color:var(--muted)}
.reto-tabla .quien{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.reto-tabla .cuanto{font-weight:600}
.reto-vacio{font-size:12.5px;color:var(--muted);margin-bottom:12px}
.reto-nuevo{margin-top:14px}
.reto-nuevo summary{font-size:13px;color:var(--muted);cursor:pointer;padding:8px 0}

/* ---------- Calificar ---------- */

.card.destacada{border-color:rgb(var(--acento-rgb) / .35);background:linear-gradient(180deg,rgb(var(--acento-rgb) / .07),transparent)}
.calificar{display:flex;flex-direction:column;gap:8px;padding:10px 0;border-bottom:1px solid var(--line)}
.calificar:last-child{border-bottom:none}
.cal-que b{display:block;font-size:var(--letra-nom);font-weight:600}
.cal-que span{font-size:12px;color:var(--muted)}
/* Con varios entrenadores en el piso a esa hora, el socio elige a quien
   califica. Angosto y pegado al renglon: es una precision del renglon, no un
   campo de formulario, y a ancho completo se leeria como si hubiera que
   contestarlo antes de las estrellas. */
.cal-quien{margin-top:6px;max-width:200px;font-size:12.5px;padding:5px 8px}
.estrellas{display:flex;gap:4px}
.estrellas button{font-size:26px;line-height:1;color:var(--card-2);transition:color .12s var(--ease),transform .12s var(--resorte)}
.estrellas button:hover,.estrellas button.on{color:var(--ambar)}
.estrellas button:active{transform:scale(1.25)}

/* ---------- Confirmar ---------- */

.confirmar{
  position:fixed;inset:0;z-index:60;display:grid;place-items:center;padding:24px;
  background:rgb(0 0 0 / .55);backdrop-filter:blur(2px);
}
.conf-caja{background:var(--card);border:1px solid var(--line-hi);border-radius:16px;padding:20px;max-width:320px;width:100%}
.conf-caja p{margin-bottom:16px;font-size:15px}
.conf-botones{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.conf-botones .btn{margin:0}

/* ---------- El segundo factor (P3 T10) ----------
   Se apoya entero en .confirmar/.conf-caja: es el mismo dialogo de siempre con
   una caja algo mas ancha, porque un QR de 200px no cabe en 320 con aire. Ni un
   color ni una fuente literales: todo sale de tokens, que es lo que el cruce 4
   de pruebas-casa-css afirma desde el 27 ago. */
.mfa-caja{max-width:360px;text-align:left}
.mfa-titulo{font-size:17px;font-weight:600;margin-bottom:8px}
.mfa-texto{font-size:14px;color:var(--muted);margin-bottom:16px;line-height:1.5}
.mfa-etiqueta{display:block;font-size:13px;font-weight:500;margin-bottom:6px}
/* La mono es para cifras, y seis digitos escritos a mano lo son. El espaciado
   ancho es lo que hace que se relean sin contarlos con el dedo. */
.mfa-codigo{font-family:var(--f-mono);font-size:20px;letter-spacing:6px;text-align:center}
/* El hueco se reserva SIEMPRE: si apareciera solo al fallar, el dialogo daria
   un salto justo cuando la persona esta leyendo por que no entro. */
.mfa-error{min-height:18px;margin-top:8px;font-size:13px;color:var(--rojo)}
.mfa-alta:empty{display:none}
.mfa-qr{display:grid;place-items:center;margin-bottom:12px}
.mfa-qr img{width:200px;height:200px;background:var(--qr-papel);border-radius:14px;padding:12px}
.mfa-secreto-pie{font-size:12px;color:var(--muted);margin-bottom:6px}
/* Seleccionable a proposito: quien no pueda escanear tiene que poder copiarlo. */
.mfa-secreto{display:block;font-family:var(--f-mono);font-size:13px;letter-spacing:1px;
  word-break:break-all;background:var(--surface);border:1px solid var(--line);
  border-radius:10px;padding:8px 10px;margin-bottom:16px;user-select:all}

/* ---------- La cara del entrenador ---------- */

.dia-nav{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:14px}
.dia-nom{font-size:16px;font-weight:600;text-transform:capitalize}

.bloque{
  display:flex;align-items:center;gap:14px;width:100%;text-align:left;position:relative;
  background:var(--card);border:1px solid var(--line);border-radius:14px;
  padding:14px;margin-bottom:9px;overflow:hidden;
}
.bloque.es-cita{background:var(--card-2)}
.bl-hora{font-size:15px;font-weight:700;flex-shrink:0;width:48px}
.bl-txt{flex:1;min-width:0}
.bl-nom{display:block;font-weight:600;font-size:var(--letra-nom)}
.bl-sub{display:block;font-size:var(--letra-sub);color:var(--muted);margin-top:1px}
/* La barra de ocupación va abajo del todo y finita: informa sin gritar. */
.bl-lleno{position:absolute;left:0;bottom:0;height:3px;width:var(--pct);background:rgb(var(--acento-rgb) / .8)}

.alumno-fila{
  display:flex;align-items:center;gap:12px;width:100%;text-align:left;
  padding:10px 4px;border-radius:12px;
}
button.alumno-fila:hover{background:var(--card-2)}
.alumno-fila.apagado{opacity:.5}
.al-foto{width:38px;height:38px;border-radius:11px;object-fit:cover;flex-shrink:0}
.al-ini{
  width:38px;height:38px;flex-shrink:0;border-radius:11px;display:grid;place-items:center;
  background:var(--card-2);font-family:var(--f-mono);font-size:12px;color:var(--muted);
}
.al-txt{flex:1;min-width:0}
.al-nom{display:block;font-size:var(--letra-nom);font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.al-sub{display:block;font-size:var(--letra-sub);color:var(--muted)}
.al-lugar{font-size:12px;color:var(--muted)}
.al-estado{font-family:var(--f-body);font-size:12px;font-weight:500;color:var(--muted)}
.al-estado.ok{color:var(--verde)}
.alumno-fila svg{color:var(--muted);flex-shrink:0}

.dato-fila{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:10px 0;border-bottom:1px solid var(--line);font-size:var(--letra-nom)}
.dato-fila:last-child{border-bottom:none}
/* El primer texto es la etiqueta y va en gris; el segundo es el dato. Con
   `>` para no apagar lo que cuelgue mas adentro. */
.dato-fila>span{color:var(--muted)}

/* ---------- El radar del dueño ---------- */

/* Los KPI del dueño eran una TERCERA familia de tarjeta-con-numero, distinta de
   la del socio (`.kpi`) y de la de su propia pestaña «Hoy» (`.t`). Hoy las tres
   son `.kpi`. */

/* `.bloque-radar` era una seccion SIN tarjeta, y convivia con las de tarjeta en
   la misma pantalla: dos formas de decir «una seccion» a la vez. Su cadencia de
   titulo —15px, peso 600, caja normal— es la que heredo `.seccion`, que es hoy
   la unica. */

.tabla-riesgo,.tabla-clases{display:flex;flex-direction:column}
.riesgo-fila,.clase-fila{
  display:grid;gap:10px;align-items:center;padding:10px 0;
  border-bottom:1px solid var(--line);font-size:14px;
}
.riesgo-fila{grid-template-columns:1fr auto auto}
.clase-fila{grid-template-columns:1fr 80px 42px auto}
.riesgo-fila:last-child,.clase-fila:last-child{border-bottom:none}
/* Un solo dato fuerte por fila: el nombre. */
.ri-nom,.cl-nom{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
.ri-cuando{font-size:12px;color:var(--ambar)}
.ri-vence,.cl-cancel{font-family:var(--f-mono);font-size:10.5px;color:var(--muted)}
.cl-barra{height:7px;border-radius:99px;background:var(--card-2);overflow:hidden}
.cl-barra i{display:block;height:100%;background:rgb(var(--acento-rgb) / .8)}
.cl-pct{font-size:12px;text-align:right}
.cl-estrellas{color:var(--ambar);font-size:13px;letter-spacing:1px}

.hito-fila{display:flex;justify-content:space-between;gap:12px;align-items:baseline;padding:9px 0;border-bottom:1px solid var(--line);font-size:14px}
.hito-fila:last-child{border-bottom:none}
.hi-que{font-size:var(--letra-sub);color:var(--muted)}

.an-fila{display:flex;gap:8px;margin:10px 0;flex-wrap:wrap}
.an-fila .input,.an-fila .select-caja{flex:1;min-width:130px}

.comentario{
  background:var(--card-2);border-radius:12px;padding:11px 13px;margin-bottom:8px;
  display:flex;flex-direction:column;gap:4px;
}
.co-txt{font-size:14px;line-height:1.5}
.co-quien{font-family:var(--f-mono);font-size:10px;color:var(--muted);letter-spacing:1px}

/* El area de texto vive con el resto de los campos, arriba. */

/* ---------- Respirar en pantalla grande ----------
   La app nació de un portal de teléfono y el dueño la abre también en la
   computadora. Sin esto, su radar se veía como una columna de 400px en medio
   de un monitor vacío. */
@media (min-width:720px){
  /* `auto-fit` y no cuatro columnas fijas: esta rejilla la comparten los cuatro
     KPI del dueño y los dos del socio, y cuatro columnas dejaban los dos del
     socio ocupando media pantalla con dos huecos al lado. */
  .kpis{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}
  .medidas{grid-template-columns:repeat(auto-fill,minmax(120px,1fr))}
  .heat-dia{width:13px;height:13px}
}

@media (prefers-reduced-motion:reduce){
  .aforo-barra span,.meta-barra span,.reto-barra span{transition:none}
  .estrellas button{transition:none}
}

/* ============================================================
   LA CARA DEL DUEÑO — lo que se mudo del panel PWA.

   Sus tokens propios (:root) NO viajaron: la casa tiene un solo juego, arriba
   de este archivo, y dos juegos era como el panel acababa con un acento y el
   portal con otro en el mismo telefono. Su pantalla de acceso tampoco: la
   puerta de la casa es una sola.
   ============================================================ */
/* ============================================================
   Panel del dueño — un solo tema oscuro con el acento del gimnasio.
   La identidad completa (6 temas) vive en el sistema local; aquí basta el
   acento de marca sobre fondo oscuro: es una pantalla de monitoreo.
   ============================================================ */


/* El relleno de abajo deja sitio a la barra de pestañas, que va fija: sin el,
   la ultima fila de cada pantalla quedaba debajo del menu.

   `width: 100%` NO sobra, y por que sobra el dia que alguien lo quite:

   #app es un contenedor flex en COLUMNA, asi que .caja es un item suyo y su
   ancho lo decide el eje transversal. Con `align-items: stretch` —el de
   fabrica— mediria lo que el contenedor le da. Pero `margin: 0 auto` ANULA el
   stretch: los margenes automaticos se comen el espacio sobrante, y entonces el
   item pasa a medir SU CONTENIDO (fit-content) hasta el tope del max-width.

   El resultado era que en la cara del dueno la pagina desbordaba 95 px con una
   ventana de 320 y 55 px con una de 360, y en las dos el contenido media
   exactamente 400 px: el ancho no lo mandaba la ventana, lo mandaba lo que
   hubiera dentro. Con `width: 100%` el item vuelve a medir lo que hay, y el
   `margin: 0 auto` se queda solo con lo suyo — centrar cuando sobra sitio. */
.caja { max-width: 640px; width: 100%; margin: 0 auto; padding: 14px 14px 96px }

/* Lo que va a la derecha en la cabecera del dueño: el chip de «en vivo» y el
   engrane de Ajustes. La cabecera es la misma `.gym-cab` de las otras dos
   caras; esto es lo unico suyo. */
.gym-cab .cab-der { margin-left: auto; display: flex; align-items: center; gap: 6px; flex: none }

.vivo {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 500;
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 9px; color: var(--muted);
}
.vivo::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--muted) }
.vivo[data-estado="vivo"] { color: var(--verde); border-color: rgb(var(--verde-rgb) / .3) }
.vivo[data-estado="vivo"]::before { background: var(--verde); animation: lat 2s infinite }
@keyframes lat { 50% { opacity: .3 } }

/* La cifra grande del dueño era un bloque propio: 38px en el color del acento
   sobre un degradado del acento, con su etiqueta en versalitas. Un hero-metric,
   que es de lo primero que prohibe la guia de diseño del proyecto. Ahora usa
   `.bottom-line`, la pieza que la casa ya tenia y que el dueño no gastaba. */

/* Las fichas `.rej`/`.t` eran la cuarta familia de tarjeta-con-numero. Todas
   las pantallas del dueño usan ya `.kpis`/`.kpi`, la misma del socio. */

/* La seccion, la tabla y sus celdas viven arriba, en las piezas compartidas,
   con clase propia. Estaban escritas aqui como `section`, `h2`, `table` y `td`
   pelados: selectores de elemento que se derraman sobre cualquier cara que
   estrene esa etiqueta, y que ya obligaban a la barra de pestañas del socio a
   ganarles por especificidad para no salir deformada. */
.fila-principal td { font-weight: 700; color: var(--text) }

/* `.vacio` ya existe arriba con el mismo significado. Aqui solo sobrevive el
   `.centro` que la acompaña: dos definiciones de la misma clase eran como la
   pantalla del dueño perdia el relleno del portal sin que nadie lo notara. */
.vacio.centro { padding: 40px 0 }
.ambar { color: var(--ambar) } .rojo { color: var(--rojo) } .verde { color: var(--verde) }

/* El chip de estado. En caja normal —«Vencido», no «VENCIDO»—: las versalitas
   con tracking se quedan en el kiosco, que es señaletica y se lee a tres
   metros. Sin `font-family` a proposito: asi `.chip.mono` (el contador del
   entrenador) conserva sus cifras de ancho fijo. */
.chip {
  display: inline-block; font-size: 11px; font-weight: 600;
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 9px; color: var(--muted);
  background: rgb(var(--tinta-rgb) / .05);
}
/* El semaforo lleva ademas su velo de fondo: el color solo nunca es la unica
   señal, y el texto del chip ya dice cual es el estado. */
.c-verde { color: var(--verde); border-color: rgb(var(--verde-rgb) / .35); background: rgb(var(--verde-rgb) / .12) }
.c-ambar { color: var(--ambar); border-color: rgb(var(--ambar-rgb) / .35); background: rgb(var(--ambar-rgb) / .12) }
.c-rojo { color: var(--rojo); border-color: rgb(var(--rojo-rgb) / .35); background: rgb(var(--rojo-rgb) / .12) }

.pie { text-align: center; color: var(--muted); opacity: .75; font-size: 10.5px; font-family: var(--f-mono); padding: 10px 0 14px }

svg { display: block }

.pills { display: flex; gap: 8px; margin-bottom: 12px; overflow-x: auto }
/* Su forma va con el resto de lo que se elige tocando, arriba. */

/* El buscador es `.input`, el campo de la casa. `.buscar` era el mismo campo
   escrito otra vez, con otro tamaño de letra y sin el anillo de foco. */

.b-fila { margin-bottom: 9px }
.b-cab { display: flex; justify-content: space-between; font-size: 13px }
.b-num { font-family: var(--f-mono); color: var(--muted) }
/* El carril de la barra, con el MISMO fondo que los otros cinco carriles de la
   casa (aforo, meta, clase, reto, grupo). Era blanco al 6%: invisible sobre una
   tarjeta clara, asi que en tema claro la barra no tenia por donde correr. */
.barra { height: 6px; border-radius: 99px; background: var(--card-2); overflow: hidden; margin-top: 4px }
.barra i { display: block; height: 100%; background: var(--acento) }

/* La barra de pestañas del dueño es la MISMA `.tabs-pie` que la del socio y la
   del entrenador. Estaba escrita aqui como `nav` pelado, con su propio fondo
   cocido y su propia tipografia: tres barras distintas para la misma app. */

/* ---------- acceso ---------- */


@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001s !important; transition-duration: .001s !important }
}

/* La marca de que un nombre de la tabla del reto es un alias y no el nombre de
   una persona. Va discreta: informa sin acusar a nadie. */
.reto-tabla .alias{
  font-style:normal;font-family:var(--f-body);font-size:11px;font-weight:500;
  color:var(--muted);margin-left:5px;
}
