/* ═══════════════════════════════════════════════════════════════════
   FITALY — Sistema de diseño
   Blanco + negro casi puro + azul de marca, inspirado en los patrones
   de interfaz de ClassPass (grid de categorías, carrusel con rating,
   tab bar flotante) con paleta e identidad propias.
   Los NOMBRES de los tokens de color se mantienen del sistema anterior
   (--pine, --green, etc.) para no tener que tocar cada referencia
   inline en app.js — solo cambian los valores hex que representan.
   ═══════════════════════════════════════════════════════════════════ */

:root{
  --bone:#F2F2F2; --paper:#FFFFFF; --ink:#0F0F0F;
  /* Morado de marca. Los nombres de los tokens (`--pine`, `--green`) son
     históricos y se conservan a propósito: aparecen en cientos de reglas
     y renombrarlos sería un cambio enorme sin ganancia visual. Lo que
     manda es el valor.

     Violeta de marca de Fitaly, fijado el 2026-08-13 en #5E16EB. Los tres
     tonos no son un degradado cualquiera: cada uno tiene un trabajo y un
     contraste que cumplir sobre blanco. Las cuentas para estos valores:

       --pine       #5E16EB  botones y acentos        7.5:1  ✓ AAA
       --pine-soft  #7B3FF0  texto secundario acento  5.5:1  ✓ AA
       --pine-pale  #EFE9FE  fondos; el violeta encima 6.4:1 ✓ AA
       --green-deep #4A0FC0  hover de botón, texto blanco encima 9.9:1 ✓ AAA

     Éste es más OSCURO y saturado que los anteriores (#882EC7 daba 6.4 y
     #9339D4 daba 5.6), así que el contraste sobra por todos lados y el
     texto blanco sobre los botones se lee mejor que antes.

     La regla al tocar estos valores sigue siendo la misma: el que manda es
     `--pine-soft`, no `--pine`. Es el que sostiene el texto MÁS CHICO
     (`.stat .s`, los lugares de una clase) y el primero que se cae por
     debajo de 4.5:1 al aclarar. Si algún día se quiere un violeta claro de
     verdad, hay que mover ANTES ese texto pequeño a `--ink`/`--mist` y
     dejar el color sólo para superficies; aclarar los tokens sin eso rompe
     la accesibilidad en silencio. */
  --pine:#5E16EB; --pine-soft:#7B3FF0; --pine-pale:#EFE9FE;
  --green:#5E16EB; --green-deep:#4A0FC0; --green-pale:#EFE9FE;
  --clay:#DC4545; --clay-pale:#FBE4E4;
  --sand:#E5E5E5; --sand-deep:#D6D6D6; --mist:#6B6B70;
  --blue-lt:#9B6BF5; --blue-dk:#3A0B96;

  --r-sm:10px; --r:16px; --r-lg:20px; --r-xl:32px;
  --shadow-sm:0 1px 2px rgba(15,15,15,.06);
  --shadow:0 4px 16px -4px rgba(15,15,15,.12), 0 1px 3px rgba(15,15,15,.06);
  --shadow-lg:0 16px 40px -12px rgba(15,15,15,.24);
  --safe-t:env(safe-area-inset-top,0px);
  --safe-b:env(safe-area-inset-bottom,0px);
  --ease:cubic-bezier(.22,.9,.32,1);

  /* Ancho máximo de la columna de contenido en escritorio. Un renglón de
     texto de 1500px es ilegible: el ojo pierde el inicio de la línea
     siguiente. 1080 deja caber dos tarjetas cómodas y mantiene la medida
     de lectura en un rango sano. */
  --ancho:1080px;

  /* ── Tiempos de interacción ──────────────────────────────────────
     Deliberadamente ASIMÉTRICOS. Al presionar, el elemento tiene que
     hundirse casi al instante (--press): cualquier retraso se lee como
     "no registró mi toque". Al soltar, se recupera con calma
     (--release), que es lo que da la sensación de material con peso.
     Antes todo usaba una transición pareja de 150ms para TODAS las
     propiedades: el hundido llegaba tarde y se sentía blando. */
  --press:70ms;
  --release:240ms;
  --ink-hover:#242424;
}

*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
html{-webkit-text-size-adjust:100%;height:100%}
body{
  font-family:'Inter',system-ui,-apple-system,sans-serif;
  background:var(--bone); color:var(--ink);
  font-size:15.5px; line-height:1.5; -webkit-font-smoothing:antialiased;
  height:100%; overflow:hidden; overscroll-behavior:none;
}
h1,h2,h3,.display{font-family:'Inter',system-ui,sans-serif;font-weight:800;letter-spacing:-.01em;line-height:1.1}
.mono{font-family:'JetBrains Mono',monospace}
button{font:inherit;cursor:pointer;border:none;background:none;color:inherit;-webkit-appearance:none}
button:focus-visible,[tabindex]:focus-visible,input:focus-visible{outline:2px solid var(--pine);outline-offset:2px}
input,select,textarea{font:inherit}
a{color:inherit}
img{max-width:100%;display:block}
::selection{background:var(--pine-pale);color:var(--ink)}
@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;transition-duration:.01ms!important}}

/* ── App shell: pantalla completa, sin chrome de navegador simulado ── */
#app{position:fixed;inset:0;display:flex;flex-direction:column;background:var(--paper)}

/* ── Cruce entre pantallas ─────────────────────────────────────────────
   Al cambiar de pestaña, el navegador fotografía el contenido antes y
   después y cruza las dos imágenes (ver `navegar()` en app.js). El cambio
   del DOM ocurre igual de rápido: la animación va sobre las fotos, así
   que la navegación no se vuelve ni un milisegundo más lenta.

   El nombre va en `#scr` —el área de contenido— y NO en la raíz. Si se
   dejara en la raíz, la fotografía incluiría la barra de arriba y la de
   pestañas, y desvanecerlas en cada toque sería reintroducir a mano el
   parpadeo que costó tanto quitar. Con el nombre aquí, esas dos barras se
   quedan quietas y sólo cruza lo que de verdad cambió.

   Sale un poco más rápido de lo que entra, y el que entra viene desde
   abajo: leído junto, se siente que una pantalla empuja a la otra en vez
   de que dos imágenes se disuelvan en el mismo sitio. */
#scr{view-transition-name:contenido}

::view-transition-old(contenido){animation:vtSale 170ms var(--ease) both}
::view-transition-new(contenido){animation:vtEntra 260ms var(--ease) both}
@keyframes vtSale{to{opacity:0;transform:translateY(-8px)}}
@keyframes vtEntra{from{opacity:0;transform:translateY(12px)}}

/* La raíz no se anima: es lo que deja quietas las barras. El
   `mix-blend-mode:normal` evita el destello que sale al cruzar dos capas
   semitransparentes con la mezcla que trae por defecto. */
::view-transition-old(root),
::view-transition-new(root){animation:none;mix-blend-mode:normal}

/* ── Encabezado de pantalla estándar (spec: 28-32px / 800) ─────────── */
.h-page{font-size:28px;font-weight:800;color:var(--ink);margin:18px 0 14px;letter-spacing:-.01em}
/* Bajada del encabezado: una línea que dice para qué sirve la pantalla.
   Se usa donde el título solo no basta — la de paquetes, por ejemplo,
   tiene que decir "cancelas cuando quieras" antes de enseñar precios. */
.sub-page{font-size:13.5px;color:var(--mist);line-height:1.45;margin:0 0 18px;max-width:420px}

/* ── Splash ────────────────────────────────────────────────────────── */
.splash{
  position:fixed;inset:0;background:var(--ink);color:var(--paper);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:14px;z-index:900;
}
.splash .word{font-weight:800;font-size:28px;letter-spacing:-.01em;animation:rise .5s var(--ease)}
.splash .bar{width:40px;height:4px;border-radius:2px;background:var(--pine);animation:grow .5s .15s var(--ease) backwards}
@keyframes rise{0%{opacity:0;transform:translateY(10px)}100%{opacity:1;transform:translateY(0)}}
@keyframes grow{0%{opacity:0;transform:scaleX(0)}100%{opacity:1;transform:scaleX(1)}}

/* ── Carga con marca ───────────────────────────────────────────────────
   Habla el mismo idioma que el splash —wordmark y una barra— para que
   esperar dentro de la app se sienta la misma pantalla que abrirla, y no
   un spinner genérico pegado encima.

   La barra va y viene en vez de llenarse de 0 a 100: una barra que se
   llena promete un final que no podemos prometer, y cuando llega al tope
   y sigue esperando se lee como que algo se atoró.

   Fondo translúcido con `backdrop-filter`: el contenido de atrás se
   adivina, así que la espera se siente como una capa encima de donde
   estabas y no como haber salido a otra pantalla. */
.cargando{
  position:fixed;inset:0;z-index:400;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;
  background:color-mix(in srgb, var(--paper) 82%, transparent);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  animation:fade .22s var(--ease);
}
.cargando.saliendo{animation:seVa .22s var(--ease) forwards}
.cargando .word{font-weight:800;font-size:22px;letter-spacing:-.01em;color:var(--pine)}
.cargando .msg{font-size:13px;color:var(--mist);max-width:260px;text-align:center;line-height:1.45}

/* La pista es el riel gris; el `::after` es lo que se desliza. Se usa un
   pseudo-elemento y no otro div para que quien la use no tenga que
   acordarse de anidar dos nodos. */
.barra-marca{width:120px;height:4px;border-radius:99px;background:var(--sand);overflow:hidden;position:relative}
.barra-marca::after{
  content:'';position:absolute;top:0;bottom:0;left:0;width:42%;
  border-radius:99px;background:var(--pine);
  animation:vaiven 1.15s var(--ease) infinite;
}
@keyframes vaiven{
  0%{transform:translateX(-110%)}
  100%{transform:translateX(345%)}
}

/* Versión en bloque, para una sección que todavía no tiene datos. Ocupa
   alto propio para que la página no dé un salto cuando el contenido
   llegue y empuje lo de abajo. */
.cargando-bloque{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;
  padding:44px 20px;min-height:180px;color:var(--mist);
  animation:fade .3s var(--ease) backwards;animation-delay:.12s;
}
.cargando-bloque .word{font-weight:800;font-size:15px;letter-spacing:-.01em;color:var(--ink);opacity:.85}
.cargando-bloque .msg{font-size:12.5px;text-align:center;max-width:240px;line-height:1.45}

/* ── Auth (login / registro) ──────────────────────────────────────── */
/* La pantalla de acceso es de DOS columnas en escritorio y de una en
   teléfono. En un monitor, un formulario de tres campos flotando en
   1400px de blanco se ve como una demo a medio hacer; la columna
   izquierda ocupa ese hueco con el argumento por el que alguien estaría
   creando la cuenta. En teléfono esa columna no se pinta. */
.auth-split{flex:1;display:flex;min-height:0;background:var(--paper)}
.auth-marca{display:none}

.auth{
  flex:1;display:flex;flex-direction:column;padding:calc(38px + var(--safe-t)) 24px 28px;
  background:var(--paper);color:var(--ink); overflow-y:auto;
}
/* La caja centra el formulario y le pone un ancho máximo legible: sin
   ella, en tablet los campos se estiran de borde a borde y el ojo pierde
   el renglón entre el label y su campo. */
.auth-caja{width:100%;max-width:400px;margin:0 auto;display:flex;flex-direction:column;flex:1}
.auth .mark{display:flex;align-items:center;gap:9px}
.auth .mark span{font-weight:800;font-size:19px;color:var(--pine)}
.auth h1{font-size:32px;font-weight:800;margin:20px 0 6px;letter-spacing:-.01em}
.auth .sub{color:var(--mist);font-size:14px;line-height:1.5;margin-bottom:22px}

/* Conmutador entrar / crear cuenta. Sustituye al enlace que vivía hasta
   abajo: con dos pestañas arriba, quien llega a crear cuenta y ya tenía
   una lo ve antes de llenar nada, en vez de descubrirlo al final. */
.auth-tabs{display:flex;gap:4px;background:var(--bone);border-radius:99px;padding:4px;margin-top:22px}
.auth-tabs button{flex:1;padding:10px;border-radius:99px;font-size:13.5px;font-weight:700;
  color:var(--mist);transition:.18s var(--ease)}
.auth-tabs button.on{background:var(--paper);color:var(--ink);box-shadow:var(--shadow)}

/* Por qué se le está pidiendo la cuenta AHORA. Lo escribe pedirCuenta()
   con la clase o el paquete que estaba a punto de tocar: sin esta línea,
   el formulario se lee como un peaje. */
.auth-motivo{background:var(--pine-pale);color:var(--pine);border-radius:var(--r-sm);
  padding:12px 14px;font-size:13.5px;line-height:1.45;font-weight:600;margin-top:16px}

.volver-explorar{display:inline-flex;align-items:center;gap:5px;color:var(--mist);
  font-size:13px;font-weight:600;margin-top:16px;align-self:flex-start}
.volver-explorar svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2.2}

.dos-campos{display:grid;grid-template-columns:1fr 1fr;gap:10px}

/* Lada fija al lado del campo, no dentro. Escrita dentro del input, la
   mitad de la gente la borra al teclear y la otra mitad la repite; a un
   lado se lee como parte del número sin ser editable. */
.campo-tel{display:flex;align-items:stretch;gap:0}
.tel-lada{
  display:flex;align-items:center;padding:0 13px;flex-shrink:0;
  background:var(--bone);border:1px solid var(--sand);border-right:none;
  border-radius:var(--r-sm) 0 0 var(--r-sm);
  font-size:15px;font-weight:700;color:var(--mist);
}
.campo-tel .field-input{border-radius:0 var(--r-sm) var(--r-sm) 0}

/* Zona para subir la foto del club. La caja tiene la proporción de la
   tarjeta donde va a salir después, así que lo que el dueño ve al elegir
   la imagen es más o menos lo que va a ver el socio. */
.foto-drop{display:block;cursor:pointer}
.foto-vacia{
  border:1.5px dashed var(--sand-deep);border-radius:var(--r);
  aspect-ratio:16/9;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:5px;text-align:center;padding:16px;background:var(--bone);
  transition:border-color .15s var(--ease),background .15s var(--ease);
}
.foto-drop:hover .foto-vacia{border-color:var(--pine);background:var(--pine-pale)}
.foto-vacia svg{width:26px;height:26px;fill:none;stroke:var(--mist);stroke-width:1.7;margin-bottom:2px}
.foto-vacia b{font-size:14px;color:var(--ink)}
.foto-vacia span{font-size:12px;color:var(--mist);line-height:1.4}
/* Con foto puesta, la caja deja de ser un marco punteado y pasa a ser la
   foto: el relleno se quita para que la imagen llegue al borde. */
.foto-vacia.con-foto{padding:0;border-style:solid;border-color:var(--sand);position:relative;overflow:hidden}
.foto-vacia.con-foto img{width:100%;height:100%;object-fit:cover;display:block}
.foto-cambiar{
  position:absolute;bottom:8px;right:8px;
  background:rgba(15,15,15,.72);color:var(--paper);
  padding:5px 10px;border-radius:99px;font-size:11.5px;font-weight:600;
}

/* Confirmación de alta de club */
.ok-icono{
  width:56px;height:56px;margin:22px 0 4px;border-radius:50%;
  background:var(--pine-pale);color:var(--pine);display:grid;place-items:center;
}
.ok-icono svg{width:28px;height:28px;fill:none;stroke:currentColor;stroke-width:2.6}
.auth .opt{font-weight:500;color:var(--sand-deep);text-transform:none;letter-spacing:0}

/* Campo de contraseña con ojo. El botón va DENTRO del campo y por eso el
   input lleva relleno extra a la derecha: sin él, el texto se mete
   debajo del ícono en cuanto la contraseña es larga. */
.campo-pass{position:relative}
.campo-pass input{padding-right:46px}
.ojo{position:absolute;right:6px;top:50%;transform:translateY(-50%);
  width:34px;height:34px;display:grid;place-items:center;border-radius:8px;color:var(--mist)}
.ojo svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.8}
.ojo.on{color:var(--pine)}

/* Medidor de contraseña: tres tramos que se encienden por LARGO, no por
   reglas de composición — ver medirPassword() en app.js. */
.fuerza{display:flex;align-items:center;gap:5px;margin-top:8px}
.fuerza i{height:3px;flex:1;max-width:38px;border-radius:99px;background:var(--sand);transition:.25s var(--ease)}
.fuerza span{margin-left:5px;font-size:11.5px;color:var(--mist)}
.fuerza[data-n="1"] i:nth-child(1){background:var(--clay)}
.fuerza[data-n="2"] i:nth-child(-n+2){background:var(--pine-soft)}
.fuerza[data-n="3"] i{background:var(--pine)}

.auth-seguro{display:flex;gap:8px;align-items:flex-start;margin-top:18px;
  font-size:12px;color:var(--mist);line-height:1.45}
.auth-seguro svg{width:15px;height:15px;flex-shrink:0;margin-top:1px;fill:none;stroke:currentColor;stroke-width:1.7}
.auth .field{margin-bottom:13px}
.auth label{display:block;font-size:11.5px;font-weight:700;letter-spacing:.02em;color:var(--mist);margin-bottom:6px}
.auth input{
  width:100%;background:var(--bone);border:1px solid var(--sand);
  color:var(--ink);border-radius:var(--r-sm);padding:14px 15px;font-size:15px;transition:.15s;
}
.auth input::placeholder{color:var(--mist)}
.auth input:focus{border-color:var(--pine);background:var(--paper);outline:none}
.auth .err{background:var(--clay-pale);border:1px solid #F3C6C6;color:#8C2A2A;
  padding:10px 13px;border-radius:var(--r-sm);font-size:13px;margin-bottom:14px;display:none}
.auth .err.on{display:block}
.auth .switcher{margin-top:auto;padding-top:24px;text-align:center;font-size:13.5px;color:var(--mist)}
.auth .switcher button{color:var(--pine);font-weight:700}

/* ── Columna de marca, sólo en pantallas anchas ────────────────────── */
@media (min-width:900px){
  .auth-marca{
    display:flex;flex-direction:column;flex:1 1 46%;max-width:560px;
    padding:calc(44px + var(--safe-t)) 48px 44px;
    background:var(--ink);color:var(--paper);
  }
  .auth-marca .mark span{font-weight:800;font-size:19px;color:var(--paper)}
  .am-cuerpo{margin-top:auto;margin-bottom:auto;padding-right:20px}
  .am-cuerpo h2{font-size:40px;line-height:1.12;font-weight:800;letter-spacing:-.02em;margin-bottom:32px}
  .am-puntos{list-style:none;display:flex;flex-direction:column;gap:20px}
  .am-puntos li{display:flex;gap:13px;align-items:flex-start}
  .am-puntos svg{width:19px;height:19px;flex-shrink:0;margin-top:2px;fill:none;stroke:var(--pine-soft);stroke-width:2.6}
  .am-puntos b{display:block;font-size:15px;font-weight:700;margin-bottom:3px}
  .am-puntos span{font-size:13.5px;line-height:1.5;opacity:.68}
  .am-precio{margin-top:34px;font-size:14px;opacity:.72}
  .am-precio b{font-size:19px;font-weight:800;opacity:1}

  /* Con la columna de marca al lado, el wordmark del formulario sobra:
     estaría dos veces en la misma pantalla.
     Va con `.auth` delante porque `.auth .mark{display:flex}` tiene dos
     clases y ganaba: escrito como `.mark-movil` a secas, la marca seguía
     saliendo duplicada. */
  .auth .mark-movil{display:none}
  .auth{padding-top:calc(52px + var(--safe-t));justify-content:center}
  .auth-caja{flex:0 1 auto}
}

/* Ícono de la hoja que ofrece activar Face ID al entrar por primera vez. */
.oferta-icono{
  width:66px;height:66px;margin:2px auto 14px;border-radius:22px;
  background:var(--pine-pale);color:var(--pine);
  display:grid;place-items:center;
}
.oferta-icono svg{width:34px;height:34px}

/* Separador "o" entre entrar con contraseña y entrar con biometría. */
.o-separador{display:flex;align-items:center;gap:12px;margin:18px 0 14px;color:var(--mist);font-size:12px}
.o-separador::before,.o-separador::after{content:'';flex:1;height:1px;background:var(--sand)}

/* Casilla de aceptación de términos del registro. La regla `.auth label`
   de arriba pone los labels en bloque y en mayúsculas de campo; esta
   los devuelve a texto corrido para que se lea como una frase. */
.auth .acepto{
  display:flex; align-items:flex-start; gap:10px; margin-top:16px;
  font-size:12.5px; line-height:1.5; font-weight:400;
  letter-spacing:0; color:var(--mist); text-transform:none;
}
/* `.auth input` de arriba está escrito para los campos de texto (100 % de
   ancho, relleno grueso, fondo propio). Sin anular eso, la casilla sale
   como una barra gris de lado a lado. */
.auth .acepto input[type=checkbox]{
  width:19px; height:19px; flex:0 0 19px; margin-top:1px;
  padding:0; background:none; border:none; border-radius:0;
  accent-color:var(--pine); cursor:pointer;
}
.auth .acepto a{color:var(--pine); font-weight:600}
.auth .acepto b{color:var(--ink); font-weight:650}

/* ── Barra de estado simulada + header de pantalla ────────────────── */
.topbar{
  padding:calc(14px + var(--safe-t)) 20px 12px;display:flex;align-items:center;gap:12px;
  background:var(--paper);position:relative;z-index:5;flex-shrink:0;
}
/* El wordmark es el logo de marca (public/images/logo-wordmark.png), no
   texto: trae su propio morado y su propio tipo, así que no depende de
   ningún token de color. */
.topbar-logo{height:28px;width:auto;display:block}
.topbar-right{margin-left:auto;display:flex;align-items:center;gap:10px}
.topbar .role-switch{display:flex;background:var(--bone);border-radius:99px;padding:3px;gap:2px}
.topbar .role-switch button{padding:6px 12px;border-radius:99px;font-size:11.5px;font-weight:700;color:var(--mist)}
.topbar .role-switch button.on{background:var(--ink);color:var(--paper)}

/* ── Menú de usuario (arriba a la derecha) ────────────────────────── */
.user-menu-wrap{position:relative}
.user-chip{display:flex;align-items:center;gap:7px;padding:5px 10px 5px 5px;border-radius:99px;background:var(--bone);flex-shrink:0}
.user-chip .avatar{width:24px;height:24px;border-radius:50%;background:var(--pine);color:var(--paper);display:grid;place-items:center;
  font-weight:700;font-size:10.5px;flex-shrink:0}
.user-chip .name{font-size:12.5px;font-weight:700;color:var(--ink);max-width:88px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.user-chip .chev{width:14px;height:14px;stroke:var(--mist);fill:none;stroke-width:2;transition:transform .18s var(--ease);flex-shrink:0}
.user-chip .chev.open{transform:rotate(180deg)}
.user-menu-bg{position:fixed;inset:0;z-index:150;background:transparent}
.user-menu{
  position:absolute;top:calc(100% + 8px);right:0;z-index:151;min-width:228px;background:var(--paper);
  border:1px solid var(--sand);border-radius:var(--r);box-shadow:var(--shadow-lg);padding:6px;animation:fade .15s;
}
.user-menu-head{padding:10px 12px 11px;border-bottom:1px solid var(--sand);margin-bottom:6px}
.user-menu-head b{font-size:14px;font-weight:800;display:block}
.user-menu-head small{font-size:11.5px;color:var(--mist);display:block;margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.user-menu button{width:100%;text-align:left;padding:10px 12px;border-radius:var(--r-sm);font-size:13.5px;font-weight:600;color:var(--ink)}
.user-menu button:active{background:var(--bone)}
.user-menu button.danger{color:var(--clay)}
.user-menu-sep{height:1px;background:var(--sand);margin:6px 4px}

/* ── Contenido con scroll ─────────────────────────────────────────── */
.screen{flex:1;overflow-y:auto;padding:0 20px;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.screen::-webkit-scrollbar{display:none}
/* Sólo un respiro entre la última tarjeta y la pastilla de navegación.
   Aquí había 112px + el área segura, y era un resto de cuando la barra
   era `position:fixed` y sí tapaba el contenido. Hoy la tabbar es un
   hermano flex con `flex-shrink:0`: ya ocupa su propio espacio, así que
   ese relleno no reservaba nada — se sumaba encima y dejaba ~146px de
   blanco al final de cada pantalla en un iPhone. El área segura tampoco
   va aquí: la absorbe el margen inferior de la propia barra. */
.screen-pad{padding-bottom:24px}

/* ── Entrada al cambiar de pestaña ──────────────────────────────────
   Se animan los BLOQUES de la pantalla, no el contenedor. Animar
   `.screen` en sí crearía un bloque contenedor durante la animación y
   el riel lateral de Inicio (position:sticky) daría un salto cada vez.

   El escalonado es corto a propósito: seis bloques a 45ms terminan en
   ~0.5s. Más lento se siente lento, no elegante — y esto se dispara en
   cada toque de la barra, así que tiene que ser algo que no canse a la
   décima vez.

   `backwards` mantiene el estado inicial durante el retraso; sin eso los
   bloques con delay aparecerían de golpe antes de empezar a animarse.

   La clase `.entra` es genérica: la usa el contenido del socio (`.screen`)
   y también el cuerpo de los paneles de club y plataforma (`.pbody`). */
.entra > *{animation:entraBloque .34s var(--ease) backwards}
.entra > *:nth-child(1){animation-delay:0ms}
.entra > *:nth-child(2){animation-delay:45ms}
.entra > *:nth-child(3){animation-delay:90ms}
.entra > *:nth-child(4){animation-delay:135ms}
.entra > *:nth-child(5){animation-delay:180ms}
.entra > *:nth-child(n+6){animation-delay:215ms}
@keyframes entraBloque{from{opacity:0;transform:translateY(10px)}}

/* Destello sobre el bloque al que te acaba de llevar una acción ("ver mi
   plan", "ver planes"). Sin esto, si el destino ya estaba en pantalla el
   desplazamiento no mueve nada y el botón parece no haber hecho nada. */
.destacado{animation:destello 1.1s var(--ease)}
@keyframes destello{
  0%   {box-shadow:0 0 0 0 rgba(0,87,255,0);      border-color:var(--sand)}
  18%  {box-shadow:0 0 0 4px rgba(0,87,255,.22);  border-color:var(--pine)}
  100% {box-shadow:0 0 0 0 rgba(0,87,255,0);      border-color:var(--sand)}
}

/* Contenedor de listas de tarjetas (resultados de Explorar, Mis clases,
   historial). En teléfono es una columna —igual que antes, las tarjetas
   traen su propio margen— y en escritorio se abre a dos, que es lo que
   evita la tira de tarjetas de 1500px de ancho. */
.lista-cards > .card{margin-bottom:11px}

/* ── Barra de búsqueda ─────────────────────────────────────────────── */
.search-bar{display:flex;align-items:center;gap:10px;background:var(--bone);border-radius:999px;height:54px;padding:0 18px;margin:6px 0 16px}
.search-bar svg{width:20px;height:20px;stroke:var(--mist);fill:none;stroke-width:2;flex-shrink:0}
.search-bar input{flex:1;min-width:0;background:transparent;border:none;font-size:15px;color:var(--ink)}
.search-bar input::placeholder{color:var(--mist)}
.search-bar input:focus{outline:none}

/* Los filtros de Explorar (deporte y costo) usan las pastillas `.chip`
   —definidas más abajo— en vez de las rejillas de tarjetas ilustradas y
   los cuadros de color que había antes. Dos renglones de pastillas
   ocupan una fracción del alto, se leen como filtros y no como
   decoración, y dejan los resultados a la vista sin tener que
   desplazarse. */

/* ── Estatus del club en su panel ─────────────────────────────────────
   Tres tonos y nada más: verde de marca cuando ya está visible, gris
   cuando la pelota está del lado de Fitaly, y rojo cuando le toca
   mover al club. El punto de color hace legible el estado de un vistazo
   sin tener que leer el texto completo. */
.estatus-banner{display:flex;gap:12px;align-items:flex-start;padding:14px 16px;border-radius:var(--r);
  border:1px solid var(--sand);background:var(--paper);margin-bottom:16px}
.estatus-banner .eb-dot{width:9px;height:9px;border-radius:50%;flex-shrink:0;margin-top:6px;background:var(--mist)}
.estatus-banner > div b{display:block;font-size:15px;font-weight:700;color:var(--ink);margin-bottom:3px}
.estatus-banner > div span{display:block;font-size:13.5px;color:var(--mist);line-height:1.45}
.estatus-banner.e-ok{background:var(--pine-pale);border-color:transparent}
.estatus-banner.e-ok .eb-dot{background:var(--pine)}
.estatus-banner.e-espera{background:var(--bone);border-color:transparent}
.estatus-banner.e-espera .eb-dot{background:var(--ink)}
.estatus-banner.e-falta{background:var(--clay-pale);border-color:transparent}
.estatus-banner.e-falta .eb-dot{background:var(--clay)}
.estatus-banner.e-falta > div b,
.estatus-banner.e-falta > div span{color:#8C2A2A}

/* ── Puerta de entrada para clubes, en la pantalla de acceso ──────────
   Un club que oye de Fitaly llega a la misma pantalla de login que
   un socio. Sin esto no tendría forma de saber que puede darse de alta
   solo, y la única vía sería que alguien de la plataforma lo capturara. */
.puerta-club{display:flex;align-items:center;gap:12px;width:100%;text-align:left;margin-top:26px;
  padding:15px 16px;border-radius:var(--r);border:1px solid var(--sand);background:var(--bone)}
.puerta-club b{display:block;font-size:14.5px;font-weight:700;color:var(--ink);margin-bottom:2px}
.puerta-club span{display:block;font-size:13px;color:var(--mist);line-height:1.4}
.puerta-club svg{width:18px;height:18px;stroke:var(--mist);fill:none;stroke-width:2;flex-shrink:0;margin-left:auto}

/* ── Bandeja de clubes por aprobar (panel de plataforma) ───────────── */
.aprobar-card{border:1px solid var(--pine);border-radius:var(--r);background:var(--pine-pale);
  padding:15px;margin-bottom:16px}
.ap-head b{display:block;font-size:15.5px;font-weight:800;color:var(--ink)}
.ap-head span{display:block;font-size:13px;color:#3A3A3E;line-height:1.45;margin-top:2px}
.ap-row{display:flex;align-items:center;gap:12px;background:var(--paper);border-radius:var(--r-sm);
  padding:11px 12px;margin-top:11px;flex-wrap:wrap}
.ap-photo{width:44px;height:44px;border-radius:11px;flex-shrink:0;background-size:cover;background-position:center}
.ap-main{min-width:0;flex:1}
.ap-main b{display:block;font-size:15px;font-weight:700;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ap-main small{display:block;font-size:12.5px;color:var(--mist);margin-top:2px}
.ap-links{display:flex;gap:10px;flex-wrap:wrap;margin-top:5px;font-size:12.5px}
.ap-links a{color:var(--pine);font-weight:600}
.ap-links .ap-nada{color:var(--clay)}
/* Los cuatro números que deciden la aprobación: cuánto inventario trae y
   si el trato se sostiene. Van en el renglón, no escondidos en la ficha. */
.ap-nums{display:flex;gap:16px;flex-wrap:wrap;width:100%;order:3;
  padding-top:10px;margin-top:2px;border-top:1px solid var(--sand)}
.ap-nums div{min-width:74px}
.ap-nums b{display:block;font-size:15px;font-weight:700;color:var(--ink);line-height:1.2}
.ap-nums span{display:block;font-size:9.5px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--mist);font-weight:700;margin-top:2px}
.ap-alerta{width:100%;order:4;background:var(--clay-pale);color:#8C2A2A;border-radius:var(--r-sm);
  padding:10px 12px;font-size:12.5px;line-height:1.45}
.ap-btns{display:flex;gap:8px;flex-shrink:0;order:5;margin-left:auto}
.ap-btns .btn{width:auto;padding:9px 15px}

@media (min-width:860px){
  /* En escritorio cabe todo en un renglón: los números se van a la derecha
     junto a los botones, en vez de bajar a una segunda línea. */
  .ap-nums{width:auto;order:2;border-top:none;padding-top:0;margin-top:0}
  .ap-alerta{order:4}
}

/* ── Encabezado de sección con carrusel ───────────────────────────── */
.sec-head{display:flex;justify-content:space-between;align-items:center;margin:28px 0 12px;gap:10px}
.sec-head h2{font-size:22px;font-weight:800;color:var(--ink)}
/* Ahora es un <button> de verdad (antes un <span aria-hidden> que
   prometía "hay más" y no hacía nada al tocarlo). */
.more-dots{font-size:20px;line-height:1;color:var(--mist);letter-spacing:1px;padding:6px 10px;flex-shrink:0;
  border-radius:99px;transition:background-color var(--release) var(--ease),color var(--release) var(--ease)}
.more-dots:active{background:var(--bone);transition-duration:var(--press)}

.hscroll{display:flex;gap:12px;overflow-x:auto;scrollbar-width:none;margin:0 -20px 4px;padding:0 20px 6px}
.hscroll::-webkit-scrollbar{display:none}

/* ── Tarjeta de carrusel (clubes/clases) ──────────────────────────── */
.carousel-card{flex:0 0 148px;text-align:left}
.cc-photo{width:148px;height:138px;border-radius:16px;margin-bottom:9px;background-size:cover;background-position:center;
  display:grid;place-items:center;color:rgba(255,255,255,.92);font-size:34px;font-weight:700;letter-spacing:.04em}
.cc-name{font-size:17px;font-weight:700;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cc-cat{font-size:14px;font-weight:500;color:var(--mist);margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cc-rating{display:flex;align-items:center;gap:4px;margin-top:6px;font-size:13px;color:var(--ink)}
.cc-rating .star{width:13px;height:13px;fill:var(--ink);flex-shrink:0}
.cc-rating b{font-weight:700}
.cc-rating .n{color:var(--mist);font-weight:500}
.cc-rating .exc{font-weight:700;margin-left:1px}

/* ── Banner de sugerencia / tip ───────────────────────────────────── */
/* Pasó de <div> a <a> para que la flechita signifique algo: hay que
   quitarle el subrayado y devolverle el color del texto, que el enlace
   trae por defecto. */
.tip-banner{background:var(--pine-pale);border-radius:var(--r-lg);padding:16px 18px;display:flex;align-items:center;gap:12px;margin:16px 0;
  text-decoration:none;color:inherit;transition:background-color var(--release) var(--ease),transform var(--release) var(--ease)}
.tip-banner:active{transform:scale(.99);transition-duration:var(--press)}
.tip-banner .tip-title{font-weight:800;font-size:15px;color:var(--ink);margin-bottom:3px}
.tip-banner .tip-text{font-size:15px;font-weight:400;color:#3A3A3E;line-height:1.42}
.tip-banner .tip-chev{width:20px;height:20px;stroke:var(--pine);stroke-width:2.2;fill:none;flex-shrink:0}

/* ── Tarjeta de monedero/cuenta ────────────────────────────────────── */
.wallet-card{background:var(--paper);border:1px solid var(--sand);border-radius:var(--r-lg);padding:20px;margin:14px 0 20px}
.wc-top{display:flex;gap:14px;align-items:flex-start}
.wc-icon{width:56px;height:56px;border-radius:16px;background:var(--pine);display:grid;place-items:center;flex-shrink:0}
.wc-credits{font-size:19px;font-weight:800;color:var(--ink);line-height:1.25}
.wc-credits b{font-size:23px}
.wc-plan{font-size:11px;letter-spacing:.07em;text-transform:uppercase;color:var(--mist);font-weight:700;margin-top:6px}
.wc-renew{font-size:12.5px;color:var(--mist);margin-top:2px}
.wc-desc{font-size:14px;color:var(--mist);line-height:1.5;margin:15px 0}
.wc-desc a{color:var(--ink);text-decoration:underline;font-weight:600}
.wc-actions{display:flex;gap:10px}

.btn-pill{flex:1;padding:14px;border-radius:999px;font-weight:700;font-size:14px;text-align:center;display:flex;align-items:center;justify-content:center;gap:6px;transition:.15s}
.btn-pill:active{transform:scale(.98)}
.btn-pill.dark{background:var(--ink);color:#fff}
.btn-pill.blue{background:var(--pine);color:#fff}
.btn-pill.sm{padding:10px 18px;font-size:13px;flex:none;width:auto}

/* ── Encabezado de perfil ──────────────────────────────────────────── */
.profile-head{display:flex;align-items:center;gap:14px;margin:16px 0 20px}
.profile-avatar{width:64px;height:64px;border-radius:50%;background:var(--pine);color:#fff;display:grid;place-items:center;font-weight:800;font-size:21px;flex-shrink:0}
.profile-name{font-size:19px;font-weight:800;color:var(--ink)}
.profile-email{font-size:14px;color:var(--mist);margin-top:2px}

/* ── Banner promocional (referidos) ───────────────────────────────── */
.promo-banner{display:flex;background:var(--pine-pale);border-radius:var(--r-lg);overflow:hidden;margin:20px 0}
.promo-text{flex:0 0 60%;padding:20px}
.promo-title{font-size:13px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;color:var(--ink);margin-bottom:7px}
.promo-text p{font-size:15px;font-weight:400;color:#3A3A3E;line-height:1.42;margin-bottom:14px}
.promo-art{flex:0 0 40%;background:var(--pine);display:grid;place-items:center}

/* ── Medidor de saldo (barras) — heredado, aún usado en algún lugar ── */
.meter{display:flex;gap:3px;flex-wrap:wrap}
.meter i{width:9px;height:16px;border-radius:3px;background:var(--sand);transition:background .3s,transform .3s}
.meter i.on{background:var(--pine)}

.eyebrow{font-size:10px;letter-spacing:.15em;text-transform:uppercase;color:var(--mist);font-weight:700;margin:26px 0 11px;display:flex;justify-content:space-between;align-items:center}
.eyebrow button{font-size:11px;letter-spacing:0;text-transform:none;color:var(--pine);font-weight:700}

/* ── Tarjeta genérica ──────────────────────────────────────────────── */
.card{background:var(--paper);border:1px solid var(--sand);border-radius:var(--r);padding:15px;margin-bottom:11px;
  transition:.15s;text-align:left;width:100%;display:block;position:relative}
.card:active{transform:scale(.98);border-color:var(--pine-soft)}
.card .row{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}
.card h4{font-size:17px;font-weight:700;margin-bottom:2px}
.card .club{font-size:14px;font-weight:500;color:var(--mist)}
.card .meta{font-size:12.5px;color:var(--pine-soft);margin-top:9px;display:flex;gap:11px;flex-wrap:wrap;align-items:center}

/* ── Tarjeta de sesión con miniatura (listas de clases) ───────────── */
.sesion-card{display:flex;gap:12px;align-items:center}
.sc-thumb{width:56px;height:56px;border-radius:14px;flex-shrink:0;background-size:cover;background-position:center;
  display:grid;place-items:center;color:rgba(255,255,255,.92);font-size:17px;font-weight:700;letter-spacing:.03em}
.sc-body{min-width:0;flex:1}
.sc-top{display:flex;justify-content:space-between;align-items:flex-start;gap:10px}

.cost{display:inline-flex;align-items:center;gap:3px;background:var(--bone);color:var(--ink);
  font-weight:800;font-size:13px;padding:5px 10px;border-radius:99px;white-space:nowrap;flex-shrink:0}
.dot{width:3px;height:3px;border-radius:50%;background:var(--sand-deep);display:inline-block}
.skel{background:linear-gradient(90deg,var(--sand) 25%,var(--bone) 50%,var(--sand) 75%);background-size:200% 100%;
  animation:shimmer 1.4s infinite;border-radius:var(--r)}
@keyframes shimmer{to{background-position:-200% 0}}

/* Silueta de tarjeta: miniatura y dos renglones, la misma forma que va a
   ocupar el contenido real. Así lo que llega RELLENA el hueco en vez de
   empujarlo, que es de donde viene la sensación de salto. */
.skel-card{display:flex;gap:12px;align-items:center;padding:13px;margin-bottom:11px;
  border:1px solid var(--sand);border-radius:var(--r);background:var(--paper);
  animation:fade .35s var(--ease) backwards}
.skel-thumb{width:62px;height:62px;border-radius:12px;flex-shrink:0}
.skel-lines{flex:1;display:flex;flex-direction:column;gap:8px;min-width:0}
.skel-lines .skel{border-radius:6px}

/* ── Portada del invitado ──────────────────────────────────────────────
   Lo que ve quien llega sin cuenta. No es un muro de registro: contesta
   qué es esto y por qué le conviene, y debajo trae clases reales para que
   la promesa se pueda comprobar en el mismo scroll. */
.hero{padding:16px 0 8px}
/* El margen inferior lo lleva ahora el título: debajo iba un párrafo que
   repetía la promesa y se quitó, así que sin esto los botones quedaban
   pegados al titular. */
.hero h1{font-size:34px;line-height:1.1;font-weight:800;letter-spacing:-.02em;margin-bottom:20px}
.hero-cta{display:flex;gap:10px;flex-wrap:wrap}
.hero-cta .btn{flex:1;min-width:180px}
.hero-nota{margin-top:14px;font-size:13px;color:var(--mist)}
.hero-nota b{color:var(--ink);font-weight:700}

/* Puerta a la explicación. Los tres pasos vivían en Inicio y ocupaban el
   lugar de lo único que alguien quiere ver al abrir la app: qué puede
   tomar hoy. La explicación la busca quien tiene la duda — para ese basta
   un botón, pero uno que se vea, con la promesa de cuánto va a tardar. */
.btn-como{display:flex;align-items:center;gap:9px;width:100%;text-align:left;
  margin:18px 0 4px;padding:11px 13px;border-radius:var(--r-sm);
  border:1px solid var(--sand);background:var(--paper);transition:.15s var(--ease)}
.btn-como:hover{border-color:var(--pine);background:var(--pine-pale)}
.btn-como > svg{width:18px;height:18px;flex-shrink:0;fill:none;stroke:var(--pine);stroke-width:1.9}
.btn-como b{display:block;font-size:13.5px;font-weight:700;color:var(--ink)}
.btn-como em{display:block;font-style:normal;font-size:11.5px;color:var(--mist);margin-top:1px;line-height:1.35}
.btn-como-chev{width:15px;height:15px;margin-left:auto;flex-shrink:0;fill:none;stroke:var(--sand-deep);stroke-width:2.2}

/* ── Pantalla "cómo funciona" ─────────────────────────────────────────
   Siete pasos numerados con una línea que los une: la línea es lo que
   convierte una lista de tarjetas en un PROCESO, que es lo que se está
   explicando. Se dibuja con un borde en el número y se corta en el
   último con :last-child. */
.cf-lista{margin:8px 0 6px}
.cf-paso{display:flex;gap:15px;align-items:flex-start;position:relative;padding-bottom:22px}
.cf-paso:last-child{padding-bottom:4px}
.cf-paso::before{content:'';position:absolute;left:15px;top:34px;bottom:0;width:1.5px;background:var(--sand)}
.cf-paso:last-child::before{display:none}
.cf-n{width:31px;height:31px;flex-shrink:0;border-radius:99px;background:var(--pine);color:var(--paper);
  display:grid;place-items:center;font-size:14px;font-weight:800;position:relative;z-index:1}
.cf-cuerpo{flex:1;min-width:0;padding-top:4px}
.cf-cuerpo h3{font-size:13px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  color:var(--mist);margin-bottom:5px}

/* La jerarquía es TODO el arreglo de esta pantalla. `cf-lead` es la frase
   que contesta el paso: grande, en tinta, legible de un vistazo. `cf-det`
   es el detalle, más chico y en gris, para quien quiera seguir leyendo.
   Cuando los dos pesaban igual, la página se leía como un muro. */
.cf-lead{font-size:16.5px;line-height:1.45;color:var(--ink);font-weight:500;margin-bottom:6px;letter-spacing:-.01em}
.cf-lead b{font-weight:750}
.cf-det{font-size:13.5px;line-height:1.55;color:var(--mist)}

/* Separador con rótulo: marca dónde deja de leerse de corrido y empieza
   lo que se consulta. */
.cf-sep{display:flex;align-items:center;gap:12px;margin:30px 0 14px;
  font-size:11.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--mist)}
.cf-sep::before,.cf-sep::after{content:'';flex:1;height:1px;background:var(--sand)}

/* Acordeón nativo. Cerrado por defecto: estas respuestas no se leen antes
   de comprar, se consultan cuando ya pasó algo. */
.cf-q{border:1px solid var(--sand);border-radius:var(--r-sm);margin-bottom:9px;overflow:hidden;background:var(--paper)}
.cf-q summary{display:flex;align-items:center;gap:10px;padding:15px 15px;cursor:pointer;
  font-size:14.5px;font-weight:650;color:var(--ink);list-style:none;transition:.15s var(--ease)}
.cf-q summary::-webkit-details-marker{display:none}
.cf-q summary:hover{background:var(--bone)}
.cf-q summary svg{width:17px;height:17px;margin-left:auto;flex-shrink:0;fill:none;
  stroke:var(--sand-deep);stroke-width:2.2;transition:transform .2s var(--ease)}
.cf-q[open] summary svg{transform:rotate(180deg)}
.cf-q[open] summary{border-bottom:1px solid var(--sand)}
.cf-q-cuerpo{padding:14px 15px 16px;animation:fade .2s var(--ease)}
.cf-q-cuerpo p{font-size:13.5px;line-height:1.6;color:var(--mist);margin-bottom:9px}
.cf-q-cuerpo p:last-child{margin-bottom:0}
.cf-q-cuerpo p b{color:var(--ink);font-weight:650}

/* Los números, como dato y no como prosa: se leen de un vistazo. */
.cf-datos{display:flex;flex-direction:column;gap:1px;background:var(--sand);
  border-radius:var(--r-sm);overflow:hidden;margin-bottom:12px}
.cf-datos > div{display:flex;align-items:center;gap:10px;padding:10px 12px;background:var(--paper);font-size:13px}
.cf-datos b{font-weight:700;color:var(--ink);flex:1;min-width:0}
.cf-datos span{color:var(--pine);font-weight:650;text-align:right;white-space:nowrap}

/* Tabla de niveles: nombre, a qué clases da acceso y cuánto cuesta. */
.cf-tabla{border:1px solid var(--sand);border-radius:var(--r-sm);overflow:hidden;margin:10px 0 2px}
.cf-fila{display:flex;align-items:center;gap:10px;padding:10px 12px;font-size:13px;border-top:1px solid var(--sand)}
.cf-fila:first-child{border-top:none}
.cf-fila span{font-weight:700;color:var(--ink);min-width:70px}
.cf-fila em{font-style:normal;color:var(--mist);flex:1}
.cf-fila b{font-weight:700;color:var(--pine);white-space:nowrap}

.cf-cierre{border-top:1px solid var(--sand);padding-top:26px;margin:26px 0 10px}
.cf-cierre h3{font-size:21px;font-weight:800;letter-spacing:-.01em;margin-bottom:6px}
.cf-cierre p{font-size:14px;line-height:1.55;color:var(--mist);margin-bottom:16px;max-width:440px}
.cf-legal{margin-top:14px;font-size:12px;color:var(--mist);line-height:1.45}
.cf-legal a{color:var(--pine);font-weight:600}

/* ══════════════════════════════════════════════════════════════════════
   ESCRITORIO — portada, paquetes y ayuda

   Hay una regla general en el bloque de abajo que gobierna todo esto:

       .screen > *{max-width:720px}

   Está bien pensada —limita los bloques de una sola columna a un ancho
   de lectura cómodo— pero se aplica a TODO hijo directo de la pantalla,
   y los bloques que se añadieron después nacieron dentro de ese tope sin
   pedirlo. El más visible: las tres tarjetas de paquete no caben en fila
   dentro de 720px, así que la tercera se caía a un segundo renglón y la
   pantalla se veía descuadrada con medio monitor vacío al lado.

   Aquí se levanta el tope SÓLO donde el ancho aporta, y se le devuelve
   composición propia a la portada.
   ══════════════════════════════════════════════════════════════════════ */
@media (min-width:860px){
  /* ── Portada ──────────────────────────────────────────────────────
     Centrada y con aire, que es lo que distingue una página web de una
     pantalla de teléfono estirada. La línea de abajo cierra la banda y
     separa la promesa del catálogo, sin necesidad de un fondo de color. */
  .screen > .hero{max-width:none}
  .hero{text-align:center;padding:62px 0 46px;margin-bottom:26px;border-bottom:1px solid var(--sand)}
  .hero h1{font-size:50px;line-height:1.06;max-width:15ch;margin:0 auto 26px}
  .hero-cta{justify-content:center}
  /* `width:auto` es la clave y no sobra: `.btn` nace con `width:100%`
     porque en teléfono los botones van de borde a borde. Con `flex:0 0
     auto`, la base del flex es ese `width`, así que cada botón medía el
     ancho ENTERO del contenedor —1080px— y los dos se apilaban como dos
     barras gigantes. Poner `flex` sin soltar el `width` no arregla nada. */
  .hero-cta .btn{flex:0 0 auto;width:auto;min-width:200px;padding-left:30px;padding-right:30px}
  .hero-nota{font-size:14px;margin-top:18px}

  /* El botón de "cómo funciona" acompaña a la portada centrada, así que
     se centra con ella en vez de quedarse anclado a la izquierda.
     Va con `.screen >` delante y no suelto: la regla general
     `.screen > *{max-width:720px}` tiene la misma especificidad y está
     escrita más abajo, así que un `.btn-como` a secas perdería. */
  .screen > .btn-como{max-width:430px;margin-left:auto;margin-right:auto}

  /* ── Paquetes ─────────────────────────────────────────────────────
     A lo ancho y en tantas columnas como quepan. `auto-fit` en vez de un
     `repeat(3)` fijo porque el número de paquetes lo decide el panel: con
     dos, tres o cuatro la fila sigue cuadrando.

     `stretch` + la lista flexible igualan la altura de las tarjetas y
     dejan todos los botones alineados abajo. Con alturas distintas —que
     es lo que pasa cuando una mezcla tiene más viñetas que otra— la fila
     se ve rota aunque el contenido esté bien. */
  .screen > #planesWrap,
  .screen > .pq-grid{max-width:none}

  /* ── Bloques de sección, a lo ancho ───────────────────────────────
     El tope general de 720px está pensado para piezas de una columna que
     se leen de corrido (un renglón de movimiento, la tarjeta de saldo).
     Estos no son eso: son bloques que pertenecen a una sección y viven
     debajo de un encabezado que SÍ ocupa los 1080px.

     Sin la excepción, el rótulo "Cerca de ti" cruzaba la pantalla y justo
     abajo el filtro, el estado vacío y el banner se encogían a 720px
     pegados a la izquierda, dejando un hueco de 360px a la derecha que
     hacía ver la pantalla rota. Es el mismo desalineado que ya se había
     corregido para las pastillas de filtro en teléfono, pero por el otro
     extremo. */
  .screen > .chips,
  .screen > .empty,
  .screen > .ubi-banner,
  .screen > .puerta-club,
  .screen > .lista-cards{max-width:none}
  .pq-grid{grid-template-columns:repeat(auto-fit,minmax(275px,1fr));gap:16px;align-items:stretch}
  .pq{display:flex;flex-direction:column;padding:20px}
  .pq-lista{flex:1}

  /* ── Cómo funciona ────────────────────────────────────────────────
     Se queda en columna de lectura (el tope general de 720px ya lo hace)
     y alineada a la izquierda igual que el título, para que el ojo tenga
     un solo margen de referencia. */
  .screen > .cf-lista{max-width:660px}   /* misma razón que .btn-como */
  .cf-cuerpo h3{font-size:13.5px}
  .cf-lead{font-size:18px}
  .cf-det{font-size:14px}
  .cf-q summary{font-size:15px;padding:16px 17px}
  .cf-q-cuerpo{padding:15px 17px 17px}

  /* ── Ritmo entre secciones ────────────────────────────────────────
     En teléfono los bloques se separan solos porque cada uno ocupa casi
     toda la pantalla. En un monitor caben varios a la vez y sin un
     espaciado explícito se leen como un solo bulto. */
  .sec-head{margin-top:34px}
  .hero + .btn-como{margin-top:0}
  .cf-sep{margin:38px 0 18px}
}

/* ── Calendario del club ───────────────────────────────────────────────
   Una rejilla con una fila por franja de 30 min y una columna por día (o
   por espacio). Los bloques se colocan con `grid-row: inicio / span n`,
   no con posición absoluta y cuentas de píxeles: así el navegador reparte
   el alto y basta cambiar `--ag-franja` para que todo se reescale.

   Lo que se busca no es ver las clases —eso ya lo hacía una tabla— sino
   ver los HUECOS. En una lista, "el martes de 10 a 12 no hay nada" es la
   ausencia de renglones, y la ausencia no se lee. Aquí es un espacio en
   blanco que salta a la vista.
   ─────────────────────────────────────────────────────────────────── */
.ag-top{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:14px}
.ag-nav{display:flex;align-items:center;gap:8px}
.ag-rango{font-weight:700;font-size:15px;min-width:190px;text-align:center}

/* El rótulo del periodo ES el selector de fecha: el <input type=date> va
   encima, transparente y del tamaño de la etiqueta, así que tocar el texto
   abre el calendario nativo del sistema. Se usa el nativo a propósito —en
   teléfono es un control que la gente ya sabe usar, y trae teclado y
   accesibilidad resueltos. */
.ag-fecha{position:relative;display:inline-flex;align-items:center;gap:7px;cursor:pointer;
  border:1px solid var(--sand);border-radius:10px;padding:7px 12px;background:var(--paper);
  transition:border-color .15s}
.ag-fecha:hover{border-color:var(--sand-deep)}
.ag-fecha svg{width:16px;height:16px;fill:none;stroke:var(--mist);stroke-width:1.8;flex-shrink:0}
.ag-fecha input[type=date]{position:absolute;inset:0;width:100%;height:100%;
  opacity:0;cursor:pointer;border:0;padding:0}

/* Ocupación del periodo visible. Se queda pegada abajo mientras se recorre
   la rejilla: es el dato que se consulta MIENTRAS se mira el calendario, no
   antes ni después. */
.ag-ocupacion{position:sticky;bottom:10px;z-index:3;
  display:inline-flex;align-items:center;gap:9px;flex-wrap:wrap;
  margin:12px 0 0;padding:9px 15px;border-radius:99px;
  background:var(--ink);color:var(--paper);font-size:12.5px;font-weight:600;
  box-shadow:var(--shadow)}
.ag-ocupacion b{font-weight:750}
.ag-ocupacion .dot{width:3px;height:3px;border-radius:50%;background:currentColor;opacity:.45}
.ag-vistas{display:flex;gap:3px;background:var(--bone);border-radius:99px;padding:3px}
.ag-vistas button{padding:8px 15px;border-radius:99px;font-size:13px;font-weight:650;color:var(--mist);transition:.18s var(--ease)}
.ag-vistas button.on{background:var(--paper);color:var(--ink);box-shadow:var(--shadow-sm)}

/* El scroll horizontal vive en el contenedor y no en la página: con seis
   salones en un teléfono, la rejilla se arrastra sola sin mover el resto
   del panel. */
.ag-scroll{overflow-x:auto;border:1px solid var(--sand);border-radius:var(--r);background:var(--paper)}
.ag-grid{
  --ag-franja:26px;
  display:grid;
  grid-template-columns:56px repeat(7, minmax(112px,1fr));
  position:relative;min-width:100%;
}
.ag-grid.semana{grid-template-columns:56px repeat(7, minmax(112px,1fr))}

.ag-cab{
  position:sticky;top:0;z-index:3;grid-row:1;
  background:var(--paper);border-bottom:1px solid var(--sand);
  padding:9px 6px;text-align:center;line-height:1.2;
}
.ag-cab b{display:block;font-size:12px;font-weight:700;text-transform:capitalize}
.ag-cab span{display:block;font-size:16px;font-weight:800;color:var(--mist);margin-top:1px}
.ag-cab.hoy b, .ag-cab.hoy span{color:var(--pine)}
.ag-cab.esquina{grid-column:1;border-right:1px solid var(--sand);z-index:4}

.ag-hora{
  grid-column:1;font-size:11px;color:var(--mist);text-align:right;
  padding:2px 7px 0 0;border-right:1px solid var(--sand);
  position:sticky;left:0;background:var(--paper);z-index:2;
}
/* Las rayas de fondo. `pointer-events:none` es obligatorio: sin eso se
   quedan encima de los bloques y ningún clic llega a la clase. */
.ag-linea{border-top:1px solid var(--bone);pointer-events:none}
.ag-linea.fuerte{border-top-color:var(--sand)}

.ag-bloque{
  margin:1px 3px;padding:5px 7px;border-radius:8px;overflow:hidden;
  text-align:left;line-height:1.25;z-index:1;min-width:0;
  border:1px solid transparent;transition:.15s var(--ease);
}
.ag-bloque b{display:block;font-size:11.5px;font-weight:700;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ag-bloque span{display:block;font-size:10.5px;opacity:.85;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ag-bloque em{display:block;font-style:normal;font-size:10px;opacity:.7;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Tres estados, y el color dice lo único que importa de un vistazo:
   si todavía se puede vender ese lugar. */
.ag-bloque.libre{background:var(--pine-pale);color:var(--pine);border-color:#E3CBFF}
.ag-bloque.lleno{background:var(--pine);color:var(--paper)}
.ag-bloque.ida{background:var(--bone);color:var(--mist)}
.ag-bloque:hover{transform:translateY(-1px);box-shadow:var(--shadow)}

.ag-pie{display:flex;gap:14px;flex-wrap:wrap;align-items:center;
  margin-top:10px;font-size:12px;color:var(--mist)}
.ag-leyenda{display:inline-flex;align-items:center;gap:6px}
.ag-leyenda i{width:11px;height:11px;border-radius:3px;display:inline-block}
.ag-leyenda .l-libre{background:var(--pine-pale);border:1px solid #E3CBFF}
.ag-leyenda .l-lleno{background:var(--pine)}
.ag-leyenda .l-ida{background:var(--bone);border:1px solid var(--sand)}

@media (min-width:860px){
  .ag-grid{--ag-franja:30px}
  .ag-bloque b{font-size:12.5px}
  .ag-bloque span{font-size:11px}
}

/* ── Invitación a compartir la ubicación ───────────────────────────────
   Va ARRIBA de la lista y no en un diálogo: un permiso que interrumpe se
   niega por reflejo, uno que aparece junto a lo que va a mejorar se
   entiende. Lleva el motivo escrito, que es lo que decide la respuesta. */
.ubi-banner{display:flex;gap:11px;align-items:center;width:100%;text-align:left;
  border:1px solid var(--sand);border-radius:var(--r);padding:13px 14px;margin-bottom:12px;
  background:var(--paper);font-size:13px;color:var(--mist);line-height:1.45}
.ubi-banner > svg{width:19px;height:19px;flex-shrink:0;fill:none;stroke:var(--pine);stroke-width:1.9}
.ubi-accion{transition:.15s var(--ease)}
.ubi-accion:hover{border-color:var(--pine);background:var(--pine-pale)}
.ubi-accion b{display:block;color:var(--ink);font-size:14px;font-weight:700;margin-bottom:2px}
.ubi-accion span{display:block}
.ubi-chev{width:16px;height:16px;margin-left:auto;flex-shrink:0;fill:none;stroke:var(--sand-deep);stroke-width:2.2}

/* ── Tarjeta de paquete ────────────────────────────────────────────────
   Tres precios sueltos no se pueden comparar. La tarjeta contesta las tres
   preguntas que uno se hace de verdad, en este orden: qué me llevo, a cómo
   me sale cada clase, y qué pasa si me arrepiento.

   Sin colores nuevos: la recomendada se distingue por BORDE y elevación,
   no por otro tono. Es lo que la hace destacar sin romper la paleta. */
.pq-grid{display:grid;gap:12px}
.pq{border:1px solid var(--sand);border-radius:var(--r);padding:17px;background:var(--paper);position:relative}
.pq-reco{border-color:var(--pine);border-width:1.5px;box-shadow:var(--shadow-lg)}
.pq-mio{border-color:var(--ink)}
.pq-cinta{position:absolute;top:-9px;left:17px;background:var(--pine);color:var(--paper);
  font-size:10.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  padding:3px 10px;border-radius:99px}
.pq-top{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}
.pq-nombre{font-size:19px;font-weight:800;letter-spacing:-.01em}
.pq-desc{font-size:12.5px;color:var(--mist);margin-top:2px;line-height:1.4}
.pq-precio{text-align:right;flex-shrink:0;line-height:1.15}
.pq-precio b{display:block;font-size:24px;font-weight:800;letter-spacing:-.02em}
.pq-precio span{font-size:11.5px;color:var(--mist)}
.pq-unitario{margin-top:9px;font-size:13px;color:var(--pine);font-weight:600}

/* Las viñetas son el corazón de la tarjeta: es lo que el socio se lleva.
   La palomita en color de marca y la nota en gris hacen que se lea de un
   vistazo qué es cantidad y qué es aclaración. */
.pq-lista{list-style:none;margin:14px 0 16px;padding:0;display:flex;flex-direction:column;gap:9px}
.pq-lista li{display:flex;gap:9px;align-items:flex-start;font-size:13.5px;line-height:1.4;color:var(--ink)}
.pq-lista em{font-style:normal;color:var(--mist);font-size:12.5px}
.pq-check{width:16px;height:16px;flex-shrink:0;margin-top:2px;fill:none;stroke:var(--pine);stroke-width:2.6}
.pq-actual{text-align:center;font-size:13px;font-weight:700;color:var(--pine);
  background:var(--pine-pale);border-radius:99px;padding:11px}

/* ── La oferta sobre una clase concreta ────────────────────────────────
   Lo que ve quien todavía no tiene paquete, en el momento de más deseo:
   ya encontró la clase que quiere. Por eso la comparación va con el precio
   del club tachado — el ahorro tiene que leerse sin hacer cuentas. */
.oferta{border:1.5px solid var(--pine);border-radius:var(--r);padding:16px;background:var(--pine-pale)}
.oferta-t{font-size:12px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--pine)}
.oferta-cmp{display:flex;gap:10px;margin:12px 0}
.oferta-cmp > div{flex:1;background:var(--paper);border-radius:12px;padding:10px 12px}
.oferta-cmp .k{display:block;font-size:11px;color:var(--mist);margin-bottom:2px}
.oferta-cmp b{font-size:18px;font-weight:800;letter-spacing:-.01em}
.tachado{text-decoration:line-through;text-decoration-thickness:1.5px;color:var(--mist);font-weight:600}
.oferta-txt{font-size:13.5px;line-height:1.5;margin:10px 0 14px;color:var(--ink)}
.oferta-suelta{display:block;width:100%;text-align:center;margin-top:12px;color:var(--mist);font-size:12.5px}

.chips{display:flex;gap:7px;overflow-x:auto;padding:3px 0 9px;scrollbar-width:none;margin:0 -20px;padding-left:20px;padding-right:20px}
.chips::-webkit-scrollbar{display:none}
.chip{border:1px solid var(--sand);border-radius:99px;padding:8px 15px;font-size:13.5px;font-weight:600;white-space:nowrap;background:var(--paper);transition:.15s;flex-shrink:0}
.chip.on{background:var(--ink);color:var(--paper);border-color:var(--ink)}

/* ── Tira de días de la mini agenda (ficha del club) ────────────────
   Se desborda a los lados con márgenes negativos, igual que `.chips`, para
   que la tira llegue al filo de la pantalla y se lea como algo deslizable
   en vez de una fila cortada a la mitad. */
.dias{display:flex;gap:8px;overflow-x:auto;scrollbar-width:none;
  margin:0 -20px;padding:3px 20px 9px}
.dias::-webkit-scrollbar{display:none}
.dia-pill{flex:0 0 auto;min-width:60px;padding:9px 10px 8px;border:1px solid var(--sand);
  border-radius:14px;background:var(--paper);display:flex;flex-direction:column;align-items:center;
  gap:1px;transition:.15s;position:relative}
.dia-pill .dp-dia{font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--mist)}
.dia-pill .dp-num{font-size:19px;font-weight:700;line-height:1.15;color:var(--ink)}
/* El contador de clases del día: es lo que evita tocar un día para
   descubrir que sólo tiene una. */
.dia-pill .dp-n{font-size:10.5px;font-weight:600;color:var(--pine-soft)}
.dia-pill.on{background:var(--ink);border-color:var(--ink)}
.dia-pill.on .dp-dia,.dia-pill.on .dp-num,.dia-pill.on .dp-n{color:var(--paper)}
.dia-pill:active{transform:scale(.95)}

.pill{font-size:10.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;padding:4px 9px;border-radius:99px;display:inline-block;white-space:nowrap}
.p-wait{background:var(--bone);color:var(--mist)}
.p-ok{background:var(--pine-pale);color:var(--pine)}
.p-no{background:var(--clay-pale);color:var(--clay)}
.p-grey{background:var(--bone);color:var(--mist)}

/* ── Nav inferior — pastilla flotante ──────────────────────────────── */
.tabbar{
  flex-shrink:0;background:var(--paper);margin:0 16px calc(14px + var(--safe-b));
  border:1px solid var(--sand);border-radius:26px;box-shadow:var(--shadow-lg);
  display:flex;padding:7px 5px;position:relative;z-index:10;
}
/* El ícono manda y la palabra confirma: a este tamaño lo que se reconoce
   de un vistazo es la silueta, no el texto. Antes pesaban casi igual
   (23px de ícono contra 10.5px de letra), así que se subió uno y se bajó
   la otra. `min-width:0` deja que las etiquetas se recorten con puntos
   suspensivos en pantallas muy angostas en vez de desbordar la pastilla. */
.tabbar button{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  font-size:10px;color:var(--ink);font-weight:700;padding:8px 2px;border-radius:16px;position:relative;transition:background .15s}
.tabbar button span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tabbar button.on{background:var(--bone)}
.tabbar .ic{width:24px;height:24px;stroke:var(--ink);fill:none;stroke-width:1.5;transition:.2s}
.tabbar .badge{position:absolute;top:0;right:calc(50% - 18px);background:var(--clay);color:#fff;font-size:9px;font-weight:700;min-width:15px;height:15px;border-radius:99px;display:grid;place-items:center;padding:0 4px}

/* ── Hoja modal ────────────────────────────────────────────────────── */
.sheet-bg{position:fixed;inset:0;background:rgba(15,15,15,.46);z-index:200;animation:fade .2s}
.sheet{
  position:fixed;left:0;right:0;bottom:0;z-index:201;background:var(--paper);
  border-radius:26px 26px 0 0;padding:10px 20px calc(24px + var(--safe-b));max-height:90vh;overflow-y:auto;
  animation:up .32s var(--ease);
}
.sheet .grip{width:38px;height:4px;background:var(--sand-deep);border-radius:9px;margin:0 auto 18px}
@keyframes up{from{transform:translateY(100%)}}

/* ── Salida de la hoja modal ────────────────────────────────────────
   `forwards` es obligatorio: sin él, al terminar la animación el
   elemento volvería de un salto a su posición original durante el
   instante que falta para que el JS lo quite del DOM. Se vería un
   parpadeo justo al final, que es peor que no animar nada.
   En teléfono la hoja se va hacia abajo, por donde entró. */
.sheet.cerrando{animation:sale .19s var(--ease) forwards}
.sheet-bg.cerrando{animation:seVa .19s var(--ease) forwards}
@keyframes sale{to{transform:translateY(100%)}}
@keyframes seVa{to{opacity:0}}
/* En escritorio es un diálogo centrado: se va encogiéndose donde está,
   no hacia el borde inferior de la pantalla. El translate(-50%,-50%) que
   lo centra tiene que repetirse en el fotograma final, porque un
   `transform` reemplaza al anterior en vez de sumarse. */
@keyframes saleDialogo{to{opacity:0;transform:translate(-50%,-46%) scale(.97)}}
/* Entrada del diálogo de escritorio: el keyframe `up` no sirve ahí porque
   pisaría el translate que lo centra. */
@keyframes aparece{from{opacity:0;transform:translate(-50%,-46%) scale(.97)}}
@keyframes fade{from{opacity:0}}

.btn{width:100%;background:var(--ink);color:var(--paper);border-radius:var(--r);padding:15px;font-weight:700;font-size:15px;
  display:flex;align-items:center;justify-content:center;gap:8px;transition:.15s}
.btn:active{transform:scale(.98)}
.btn:disabled{background:var(--sand);color:var(--mist)}
.btn.green{background:var(--green);color:#fff}
.btn.ghost{background:transparent;color:var(--ink);border:1px solid var(--sand)}
.btn.ghost.danger{color:var(--clay);border-color:var(--clay-pale)}
/* Sólido, no fantasma: confirma algo irreversible (eliminar la cuenta) y
   tiene que verse distinto a "cerrar sesión", que es .btn.ghost.danger.
   El :not(.ghost) es obligatorio — sin él este fondo rojo se le aplica
   también al botón fantasma, que solo redefine el color del texto, y
   "Cerrar sesión" queda rojo sobre rojo. */
.btn.danger:not(.ghost){background:var(--clay);color:#fff}
.btn.sm{padding:10px 15px;font-size:13.5px;width:auto}
.btn.block-sm{padding:11px;font-size:13.5px}
.btn.pay{background:#000;color:#fff;font-size:16px}
.btn.gpay{background:#fff;color:#3c4043;border:1px solid #dadce0}
.btn.loading{position:relative;color:transparent!important}
.btn.loading::after{content:'';position:absolute;width:18px;height:18px;border:2px solid rgba(255,255,255,.4);
  border-top-color:#fff;border-radius:50%;animation:spin .7s linear infinite}
.btn.ghost.loading::after{border-color:rgba(15,15,15,.25);border-top-color:var(--ink)}
@keyframes spin{to{transform:rotate(360deg)}}

.line{display:flex;justify-content:space-between;padding:11px 0;border-bottom:1px solid var(--sand);font-size:14px}
.line:last-child{border:none}
.line .k{color:var(--mist)}
.line .v{font-weight:700}
.line.total{font-weight:800;font-size:15px}

.pending{background:var(--ink);color:var(--paper);border-radius:var(--r-lg);padding:26px 20px;text-align:center}
.ring{width:112px;height:112px;margin:6px auto 15px;position:relative}
.ring svg{transform:rotate(-90deg)}
.ring circle{fill:none;stroke-width:5;stroke-linecap:round}
.ring .bg{stroke:rgba(255,255,255,.14)}
.ring .fg{stroke:var(--pine);transition:stroke-dashoffset 1s linear}
.ring .mid{position:absolute;inset:0;display:grid;place-items:center}
.ring .mid b{font-family:'JetBrains Mono';font-size:23px;font-weight:600;display:block}
.ring .mid small{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;opacity:.5}
.pulse{animation:pulse 2.2s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:.45}50%{opacity:1}}

.code{font-family:'JetBrains Mono';font-size:31px;font-weight:600;letter-spacing:.16em;text-align:center;margin-top:13px}

/* ── Pase de entrada — el código es el protagonista, porque es lo único
   que recepción puede teclear de verdad (ver la nota en app.js sobre el
   QR que se quitó). ── */
.pase{background:var(--ink);color:var(--paper);border-radius:var(--r-lg);padding:26px 18px;text-align:center}
.pase-k{font-size:10px;letter-spacing:.16em;text-transform:uppercase;opacity:.55;font-weight:700}
.pase-cod{font-family:'JetBrains Mono',monospace;font-size:38px;font-weight:600;letter-spacing:.04em;margin:12px 0 8px;line-height:1}
.pase-club{font-size:13px;opacity:.62}
@media (max-width:380px){ .pase-cod{font-size:31px} }

.field{margin-bottom:13px}
label{display:block;font-size:11.5px;color:var(--mist);font-weight:700;margin-bottom:5px}
input.field-input,select.field-input{width:100%;padding:12px 13px;border:1px solid var(--sand);border-radius:var(--r-sm);background:var(--paper)}
input.field-input:focus,select.field-input:focus{outline:none;border-color:var(--pine-soft)}

/* Contenedor del iframe de Stripe Elements (tarjeta) — no es un <input>,
   por eso no puede reusar la regla de arriba (va calificada por tag). */
.card-mount{width:100%;padding:13px;border:1px solid var(--sand);border-radius:var(--r-sm);background:var(--paper);transition:border-color .15s}
.card-mount.StripeElement--focus{border-color:var(--pine-soft)}
.card-mount.StripeElement--invalid{border-color:var(--clay)}

.note{background:var(--pine-pale);border-radius:14px;padding:13px 15px;font-size:14px;color:#3A3A3E;line-height:1.5}

/* Baja de cuenta. El enlace es deliberadamente discreto — no compite con
   "Cerrar sesión" — pero está a la vista, no escondido: la ley obliga a
   que el titular pueda ejercer su derecho de cancelación sin buscarlo. */
.link-baja{
  display:block;width:100%;text-align:center;margin:18px 0 8px;
  font-size:13px;font-weight:600;color:var(--mist);padding:8px;
}
.link-baja:hover{color:var(--clay);text-decoration:underline}
.aviso-baja{
  background:var(--clay-pale);border-radius:14px;padding:13px 15px;
  font-size:14px;line-height:1.5;color:#8A1E1E;margin-bottom:14px;
}
.note.pine{background:var(--pine-pale);color:#3A3A3E}
/* Aviso que pide una acción (confirmar el correo). Ámbar y no rojo a
   propósito: no está roto nada, falta un paso. */
.note.aviso{background:#FDF4E3;color:#6B4E16;border:1px solid #F0DCB4}
.note.aviso .link-sm{color:#8A5A12;display:block}
.empty{text-align:center;padding:50px 20px;color:var(--mist)}
.empty .b{font-weight:700;font-size:18px;color:var(--ink);margin:10px 0 5px}

/* El aviso vive en <body>, FUERA de #app, para que repintar la app no lo
   recree ni lo obligue a reaparecer (ver toast() en app.js).

   El centrado se hace con `left:50%` más un desplazamiento en X, y la
   animación mueve el eje Y. Las dos cosas viajan en la misma propiedad
   `transform`, así que unos keyframes que sólo escribieran `translateY`
   borrarían el centrado y el aviso saltaría a la derecha a media entrada.
   Por eso el `-50%` se repite dentro de cada fotograma. */
.toast{position:fixed;bottom:calc(100px + var(--safe-b));left:50%;transform:translate(-50%,0);z-index:300;
  background:var(--ink);color:var(--paper);padding:12px 20px;border-radius:99px;font-size:13.5px;font-weight:500;
  box-shadow:var(--shadow-lg);max-width:88vw;text-align:center;opacity:0}
.toast.on{animation:toastEntra .26s var(--ease) forwards}
.toast.saliendo{animation:toastSale .24s var(--ease) forwards}
@keyframes toastEntra{from{opacity:0;transform:translate(-50%,14px) scale(.97)}
                      to{opacity:1;transform:translate(-50%,0) scale(1)}}
@keyframes toastSale{from{opacity:1;transform:translate(-50%,0) scale(1)}
                     to{opacity:0;transform:translate(-50%,8px) scale(.98)}}

.fab-install{
  position:fixed;left:16px;right:16px;bottom:calc(100px + var(--safe-b));z-index:150;
  background:var(--ink);color:var(--paper);border-radius:var(--r);padding:13px 15px;
  display:flex;align-items:center;gap:11px;box-shadow:var(--shadow-lg);animation:up .3s var(--ease);
}
.fab-install b{font-size:13.5px;display:block}
.fab-install span{font-size:11.5px;opacity:.6}
.fab-install button.close{margin-left:auto;opacity:.6;padding:4px}

/* La portada guarda proporción en vez de una altura fija.
   Con `height:170px` la caja quedaba de 1100×170 en escritorio —una
   franja de 6.5:1— y `cover` tenía que ampliar la foto muchísimo para
   llenarla, recortando arriba y abajo: se veía como un zoom sobre un
   trozo cualquiera de la imagen. Con `aspect-ratio` la caja se parece a
   la foto, así que casi no hay que ampliar nada; el `max-height` evita
   que en un monitor ancho se coma la pantalla. */
.club-cover{
  aspect-ratio:16/9; max-height:300px; min-height:160px;
  border-radius:var(--r-lg);background-size:cover;background-position:center;
  display:flex;align-items:flex-end;padding:14px;border:1px solid var(--sand);
}
.club-cover .cover-btn{width:auto;cursor:pointer}

/* ── Paneles de club / plataforma — mobile-first, funcionan igual en
   teléfono que en escritorio (es la base de la futura app móvil) ──── */
.desktop-wrap{max-width:1160px;margin:0 auto;padding:10px 0 40px}
.panel{background:var(--paper);border:1px solid var(--sand);border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow)}
/* Cabecera del panel: fondo neutro, no una banda de color.
   Era una franja morada a todo lo ancho, y a pantalla completa esa banda
   se comía la primera pantalla entera sin decir nada que el contenido no
   dijera ya. El panel es una herramienta de trabajo: el color se guarda
   para lo que hay que atender —una reserva por confirmar, un margen en
   rojo— y no para el marco. Sólo el avatar conserva el morado, que basta
   para saber en qué club estás parado. */
.ptop{background:var(--paper);color:var(--ink);padding:16px;display:flex;align-items:center;gap:12px;
  flex-wrap:wrap;border-bottom:1px solid var(--sand)}
.ptop .who b{font-size:17px;font-weight:800;display:block;letter-spacing:-.01em}
.ptop .who small{font-size:12px;color:var(--mist)}
.ptop .live{margin-left:auto;display:flex;align-items:center;gap:6px;font-size:11.5px;
  color:var(--mist);background:var(--bone);padding:6px 11px;border-radius:99px;white-space:nowrap}
.ptop .live i{width:7px;height:7px;border-radius:50%;background:var(--pine);animation:pulse 1.8s infinite;flex-shrink:0}
.pnav{display:flex;gap:2px;border-bottom:1px solid var(--sand);padding:0 10px;overflow-x:auto;scrollbar-width:none}
.pnav::-webkit-scrollbar{display:none}
.pnav button{padding:12px 13px;font-size:13px;font-weight:600;color:var(--mist);border-bottom:2px solid transparent;white-space:nowrap;flex-shrink:0}
.pnav button.on{color:var(--ink);border-color:var(--pine);font-weight:700}
.pbody{padding:16px}
.grid{display:grid;gap:11px}
.g4{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}
.g2{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}
.stat{border:1px solid var(--sand);border-radius:var(--r);padding:14px}
.stat .k{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--mist);font-weight:700}
/* El `>` es lo que arregla los renglones. Esta regla describe el número
   grande de un bloque de estadística, pero escrita como descendiente
   alcanzaba TAMBIÉN a los `.v` de cada `.line` anidada dentro de un
   `.stat` — y esos son valores de renglón, de 14px. Por eso en las
   tarjetas de paquete se leía "sin datos todavía" a 28px, del tamaño de
   un titular. El número grande de verdad vive en `.kpi .v`, que es el
   componente hecho para eso. */
.stat > .v{font-weight:800;font-size:25px;margin-top:5px;line-height:1}
.stat .s{font-size:12px;color:var(--pine-soft);margin-top:5px}
.tw{overflow-x:auto;-webkit-overflow-scrolling:touch}
table{width:100%;border-collapse:collapse;font-size:13px}
th{text-align:left;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--mist);padding:9px 10px;border-bottom:1px solid var(--sand);font-weight:700;white-space:nowrap}
td{padding:12px 10px;border-bottom:1px solid var(--sand);vertical-align:middle;white-space:nowrap}
tr:last-child td{border:none}

/* ── A partir de tablet/escritorio: más aire, scroll de página normal
   en vez del app-shell fijo de teléfono ──────────────────────────── */
@media (min-width:860px){
  body{overflow:auto}
  #app{position:static;min-height:100vh;display:block}
  .desktop-wrap{padding:28px 20px 60px}
  .ptop{padding:16px 22px;gap:14px}
  .ptop .who b{font-size:18px}
  .ptop .who small{font-size:11.5px}
  .ptop .live{font-size:12px;padding:6px 12px}
  .pnav{padding:0 14px}
  .pnav button{padding:13px 15px;font-size:13.5px}
  .pbody{padding:22px}
  .grid{gap:13px}
  .g4{grid-template-columns:repeat(auto-fit,minmax(178px,1fr))}
  .g2{grid-template-columns:repeat(auto-fit,minmax(310px,1fr))}
  .stat{padding:15px}
  .stat > .v{font-size:28px}   /* mismo motivo que arriba: sólo el hijo directo */
  table{font-size:13.5px}
  td{white-space:normal}
  .app-phone-preview{max-width:400px;margin:0 auto}
}
@media (max-width:859px){
  .desktop-only{display:none!important}
}

/* ═══════════════════════════════════════════════════════════════════
   ESCRITORIO — la vista de socio
   Hasta aquí, la app del socio era un shell de teléfono estirado: en una
   pantalla de 1500px cada tarjeta, cada botón y cada renglón de texto
   ocupaba el ancho completo, y la barra de pestañas quedaba tirada al
   final del documento. Este bloque la convierte en una página web
   normal: columna centrada, navegación arriba y listas en dos columnas.
   Nada de esto toca el teléfono — todo vive dentro del media query.
   ═══════════════════════════════════════════════════════════════════ */
@media (min-width:860px){

  /* El shell sigue siendo flex para poder reordenar: en escritorio la
     navegación va ARRIBA (donde se busca) y no abajo (donde alcanza el
     pulgar). Es el mismo HTML, solo cambia el orden visual.
     El `:has(> .screen)` acota la regla a la vista de socio: en #app
     también se monta el panel de club y el de plataforma, que tienen
     otra estructura (.desktop-wrap) y ya traen su propio tratamiento de
     escritorio. Volverlos flex sin querer les cambiaría el centrado. */
  #app:has(> .screen){display:flex;flex-direction:column;min-height:100vh;background:var(--paper)}
  /* Respaldo por si :has() no está disponible: en columna flex, un hijo
     con max-width sigue centrándose bien si declara su ancho. */
  .desktop-wrap{width:100%}
  .topbar{order:1}
  .tabbar{order:2}
  .screen{order:3}
  .sheet,.sheet-bg,.toast,.fab-install{order:9}

  /* Fondo a todo lo ancho, contenido alineado a la misma columna que el
     resto. El padding calculado evita tener que meter un div extra solo
     para centrar. */
  .topbar{
    padding:18px max(24px,calc((100% - var(--ancho))/2)) 16px;
    border-bottom:1px solid var(--sand);
  }
  .topbar-logo{height:34px}

  /* La navegación se queda fija al hacer scroll: con cien clases en la
     lista, perderla de vista obliga a volver hasta arriba. La que se va
     es la barra de marca, que no hace falta mientras exploras. */
  .tabbar{
    position:sticky;top:0;z-index:55;
    margin:0;padding:0 max(24px,calc((100% - var(--ancho))/2));
    background:var(--paper);border:none;border-bottom:1px solid var(--sand);
    border-radius:0;box-shadow:none;gap:2px;
  }
  .tabbar button{
    flex:0 0 auto;flex-direction:row;gap:9px;
    font-size:14px;font-weight:600;color:var(--mist);
    padding:15px 16px;border-radius:0;
    border-bottom:2px solid transparent;margin-bottom:-1px;
  }
  .tabbar button:hover{color:var(--ink)}
  .tabbar button.on{background:transparent;color:var(--pine);border-bottom-color:var(--pine);font-weight:700}
  .tabbar .ic{width:19px;height:19px;stroke:currentColor}
  /* El globo del contador colgaba de la esquina de un botón vertical; en
     fila se vuelve una pastilla al lado de la palabra. */
  .tabbar .badge{position:static;margin-left:2px}

  /* La página scrollea sola: el contenedor deja de ser un panel con
     scroll propio (eso, en escritorio, produce dos barras y una rueda
     del ratón que no obedece). */
  /* Mismo cálculo de padding que la barra de marca y la navegación: si
     una usa `max-width + margin:auto` y las otras padding calculado, el
     contenido queda desalineado respecto al encabezado por el ancho del
     gutter. Con la regla idéntica en las tres, las tres coinciden a
     cualquier ancho de ventana. */
  .screen{
    overflow:visible;flex:none;width:100%;max-width:none;
    padding:0 max(24px,calc((100% - var(--ancho))/2));
  }
  .screen-pad{padding-bottom:72px}
  .h-page{font-size:32px;margin:26px 0 18px}

  /* Tarjetas en tantas columnas como quepan, no en dos fijas. Con 1080px
     de ancho, dos columnas dejaban cada tarjeta de clase a ~530px: una
     tira larguísima con el nombre a la izquierda y el costo perdido en la
     otra punta. Con `auto-fill` salen tres de ~350px, que es la medida a
     la que la tarjeta se lee de un vistazo — y en una ventana angosta
     vuelve sola a dos. */
  .lista-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:13px;align-items:start}
  .lista-cards > .card{margin-bottom:0}

  /* En teléfono las pastillas se salen del margen para poder arrastrarse
     de borde a borde. Aquí el margen lateral es un canal centrado, no un
     relleno de 20px: manteniendo aquel tirón negativo, el renglón de
     filtros arrancaba 20px a la izquierda de todo lo demás. */
  .chips{margin:0;padding-left:0;padding-right:0}

  /* El carrusel sangra hasta el borde del contenedor, no del navegador. */
  .hscroll{margin:0 -24px 4px;padding:0 24px 6px}
  .carousel-card{flex:0 0 190px}
  .cc-photo{width:190px;height:170px}

  /* Textos y bloques de una sola columna: se limitan para que el renglón
     no cruce la pantalla entera. */
  /* Ancho de los bloques de la pantalla.
     Por defecto TODO lo que cuelga directo de la pantalla se limita a una
     medida de lectura cómoda: son piezas de una sola columna (la tarjeta
     de saldo, un renglón de movimiento, un aviso) y estiradas a 1080px
     dejan la etiqueta en un extremo y su dato en el otro, obligando a
     barrer la pantalla con la vista para emparejarlos.
     Luego se exceptúa lo que sí gana con el ancho completo.
     El orden es a propósito —tope general primero, excepciones después—
     porque la lista de piezas que necesitan tope crece con cada pantalla
     nueva, y la de las que no, casi nunca. */
  .screen > *{max-width:720px}
  .screen > .lista-cards,
  .screen > .hscroll,
  .screen > .sec-head,
  .screen > .inicio-top,
  .screen > .h-page{max-width:none}

  /* ── Inicio en dos columnas ──────────────────────────────────────
     El saldo y el plan se van a un riel lateral que se queda fijo al
     hacer scroll —es la información que quieres tener a la vista
     mientras decides— y lo que está pasando ahora ocupa la columna
     principal. Sin esto, Inicio era una tira de bloques apilados
     pegada a la izquierda con medio monitor en blanco al lado. */
  .inicio-top{
    display:grid;grid-template-columns:minmax(0,1fr) minmax(300px,340px);
    gap:26px;align-items:start;margin-bottom:8px;
  }
  .it-main{order:1;min-width:0}
  .it-rail{order:2;position:sticky;top:88px}
  .it-rail .wallet-card{max-width:none}
  /* El primer rótulo de la columna principal no lleva el margen
     superior de los demás: ya lo separa la rejilla. */
  .it-main > .eyebrow:first-child{margin-top:0}
  /* Y también el contenedor que ENVUELVE una rejilla de tarjetas: los
     resultados de Explorar se repintan solos dentro de
     #resultadosExplorar, así que la rejilla no es hija directa y heredaba
     el tope de 720px de su envoltorio — dos columnas de 360px en una
     pantalla de 1080. */
  .screen > *:has(.lista-cards){max-width:none}
  .search-bar{max-width:620px}

  .card,.carousel-card,.chip{cursor:pointer}

  /* ── Los paneles ocupan la pantalla ───────────────────────────────
     El de club y el de plataforma son herramientas de trabajo y se usan
     desde una computadora: recepción confirmando reservas, la plataforma
     revisando cortes y precios. Ahí el ancho no es lujo, es cuántas
     columnas de una tabla se ven sin barrer de lado.

     Estaban encajonados por DOS topes que se sumaban: el canal centrado
     de `.screen` (220px de margen a cada lado) y la regla general
     `.screen > *{max-width:720px}`, que también alcanzaba al envoltorio
     del panel. Resultado medido en una ventana de 1536px: el cuerpo del
     panel quedaba en 678px — menos de la mitad de la pantalla, con una
     tarjeta flotando en medio de dos franjas vacías.

     Ahora van a sangre. El `:has()` acota el cambio a las pantallas que
     de verdad llevan panel; la vista de socio conserva su canal centrado,
     que ahí sí ayuda a leer. */
  .screen:has(.panel){padding-left:0;padding-right:0;padding-bottom:0}
  .screen > .desktop-wrap{max-width:none;padding:0}

  /* Deja de ser una tarjeta: sin borde, sin esquinas ni sombra, y
     cubriendo el alto de la ventana para que no termine a media pantalla
     dejando un vacío debajo. */
  .panel{
    border:none;border-radius:0;box-shadow:none;
    min-height:calc(100vh - 60px);display:flex;flex-direction:column;
  }
  .ptop{padding:20px 32px}
  .pbody{padding:26px 32px 72px;flex:1}

  /* Las pestañas se quedan pegadas arriba al hacer scroll. En una tabla
     de cortes con cincuenta renglones, perderlas de vista obliga a subir
     hasta el principio sólo para cambiar de sección. */
  .pnav{
    position:sticky;top:0;z-index:20;
    background:var(--paper);padding:0 24px;
  }
  .pnav button{padding:14px 15px;font-size:13.5px}

  /* Con el ancho real disponible, las rejillas del panel pueden respirar:
     los KPI dejan de apilarse de dos en dos y las tablas se leen enteras. */
  .grid{gap:14px}
  .g4{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
  .g2{grid-template-columns:repeat(auto-fit,minmax(330px,1fr))}

  /* La pantalla de acceso también se centra: un formulario de correo y
     contraseña alineado a la izquierda de un monitor se ve abandonado. */
  .auth{max-width:420px;margin:0 auto;padding-top:8vh}
}

/* ═══════════════════════════════════════════════════════════════════
   PANELES v2 — piezas compartidas por el panel de club y el de
   plataforma. Mobile-first igual que el resto: todo apila en teléfono y
   solo a partir de 860px se abre a dos columnas.
   ═══════════════════════════════════════════════════════════════════ */

/* El textarea no heredaba el estilo de campo (la regla vieja iba
   calificada por tag y solo cubría input/select) — se veía como un
   textarea crudo del navegador dentro de un formulario ya diseñado. */
textarea.field-input{
  width:100%;padding:12px 13px;border:1px solid var(--sand);border-radius:var(--r-sm);
  background:var(--paper);resize:vertical;min-height:76px;line-height:1.5;
}
textarea.field-input:focus{outline:none;border-color:var(--pine-soft)}
input.field-input:disabled,select.field-input:disabled,textarea.field-input:disabled{
  background:var(--bone);color:var(--mist);cursor:not-allowed
}

/* ── Cabecera de panel ─────────────────────────────────────────────── */
/* El avatar es lo único que conserva el morado: es la marca de en qué
   club estás parado, y sobre fondo blanco necesita color propio — el
   translúcido de antes contaba con la banda de color detrás. */
.pavatar{
  width:38px;height:38px;border-radius:12px;flex-shrink:0;background-size:cover;background-position:center;
  background-color:var(--pine);display:grid;place-items:center;font-weight:800;font-size:16px;color:#fff;
}
.ptop-actions{margin-left:auto;display:flex;align-items:center;gap:9px;flex-wrap:wrap}
/* Los botones eran blancos translúcidos porque flotaban sobre la banda
   de color. Sin banda, ese blanco sobre blanco desaparecía. */
.ptop-btn{
  display:flex;align-items:center;gap:7px;background:var(--paper);color:var(--ink);
  border:1px solid var(--sand);
  padding:8px 14px;border-radius:99px;font-size:12.5px;font-weight:700;white-space:nowrap;transition:.15s;
}
.ptop-btn:hover{background:var(--bone);border-color:var(--sand-deep)}
.ptop-btn:active{transform:scale(.97)}
.ptop-btn svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2;flex-shrink:0}

/* ── Título de sección dentro del panel ────────────────────────────── */
.sec-title h3{font-size:19px;font-weight:800;letter-spacing:-.01em}
.sec-title p{font-size:13px;color:var(--mist);line-height:1.5;margin-top:3px;max-width:64ch}
.sec-title{margin-bottom:16px}
.micro{font-size:12px;color:var(--mist);line-height:1.5;margin:8px 0 0}

/* ── Mosaico de KPI ────────────────────────────────────────────────── */
.kpi{border:1px solid var(--sand);border-radius:var(--r);padding:14px;background:var(--paper)}
.kpi .k{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--mist);font-weight:700}
.kpi .v{font-weight:800;font-size:26px;margin-top:6px;line-height:1;letter-spacing:-.02em}
.kpi .v-sub{font-size:15px;font-weight:700;color:var(--mist)}
.kpi .s{font-size:12px;color:var(--mist);margin-top:6px;line-height:1.4}
.kpi.t-ok{border-color:var(--pine-pale);background:linear-gradient(180deg,var(--pine-pale),var(--paper) 62%)}
.kpi.t-ok .v{color:var(--pine)}
.kpi.t-alerta{border-color:#F3C6C6;background:linear-gradient(180deg,var(--clay-pale),var(--paper) 62%)}
.kpi.t-alerta .v{color:var(--clay)}

/* ── Banda de alerta accionable ────────────────────────────────────── */
.alerta{
  margin-top:14px;background:var(--ink);color:var(--paper);border-radius:var(--r);
  padding:14px 16px;cursor:pointer;transition:.15s;display:block;
}
.alerta:active{transform:scale(.99)}
.alerta b{display:block;font-size:14.5px;font-weight:700}
.alerta span{display:block;font-size:12.5px;opacity:.66;margin-top:3px;line-height:1.45}

/* ── Gráfica de barras sin librería ────────────────────────────────── */
/* La tarjeta se estira para igualar a la de dinero que va a su lado; las
   barras crecen con ella en vez de quedarse pegadas arriba dejando un
   hueco blanco. */
.chart{border:1px solid var(--sand);border-radius:var(--r);padding:15px 15px 11px;height:100%;
  display:flex;flex-direction:column}
.chart-head{display:flex;justify-content:space-between;align-items:baseline;gap:10px;margin-bottom:14px}
.chart-head span{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--mist);font-weight:700}
.chart-head b{font-size:12px;color:var(--ink);font-weight:700;white-space:nowrap}
.chart-bars{display:flex;align-items:flex-end;gap:5px;flex:1;min-height:132px}
.cbar{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%;min-width:0}
.cbar i{display:block;width:100%;max-width:26px;background:var(--pine);border-radius:5px 5px 2px 2px;transition:height .4s var(--ease)}
.cbar-n{font-size:10px;font-weight:700;color:var(--mist);margin-bottom:4px;min-height:13px}
.cbar-d{font-size:9.5px;color:var(--mist);margin-top:6px;text-transform:uppercase;font-weight:700}

/* ── Barra de ocupación de una clase ───────────────────────────────── */
.occ{display:flex;align-items:center;gap:8px;flex-shrink:0;width:112px}
.occ-bar{flex:1;height:7px;border-radius:99px;background:var(--sand);overflow:hidden}
.occ-bar i{display:block;height:100%;border-radius:99px}
.occ-bar.flojo i{background:var(--sand-deep)}
.occ-bar.bien i{background:var(--pine)}
.occ-bar.lleno i{background:var(--ink)}
.occ-n{font-size:11.5px;font-weight:700;color:var(--mist);white-space:nowrap;font-family:'JetBrains Mono',monospace}

/* ── Checklist de completitud ──────────────────────────────────────── */
/* Lista de pendientes compacta: una línea por punto. La versión anterior
   daba a cada pendiente el peso de una tarjeta —título, dos renglones de
   explicación y un botón grande— y con ocho pendientes el club abría su
   panel y no veía nada más. Un checklist es una lista, no ocho tarjetas. */
.check-card{border:1px solid var(--sand);border-radius:var(--r);overflow:hidden}
.check-head{display:flex;gap:12px;align-items:center;padding:12px 14px;background:var(--pine-pale)}
.check-head b{display:block;font-size:14px;font-weight:800}
.check-head span{display:block;font-size:12px;color:#3A3A3E;margin-top:2px;line-height:1.4}
.check-ring{
  width:44px;height:44px;border-radius:50%;flex-shrink:0;display:grid;place-items:center;
  background:conic-gradient(var(--pine) calc(var(--p)*1%), rgba(255,255,255,.6) 0);
}
.check-ring span{
  width:33px;height:33px;border-radius:50%;background:var(--paper);display:grid;place-items:center;
  font-size:11px;font-weight:800;color:var(--pine);
}
.check-list{padding:0 14px}
.check-item{display:flex;align-items:center;gap:9px;padding:2px 0;border-bottom:1px solid var(--sand)}
.check-item:last-child{border:none}
.check-item b{font-size:13.5px;font-weight:650;line-height:1.3}
.check-dot{width:7px;height:7px;border-radius:50%;border:2px solid var(--clay);flex-shrink:0}
/* Acción secundaria: se lee como enlace, pero conserva un área de toque
   de 40px de alto — de ahí el padding vertical y no un margen. */
.arreglar{
  margin-left:auto;flex-shrink:0;padding:11px 10px;
  font-size:12.5px;font-weight:700;color:var(--pine);border-radius:8px;
}
.arreglar:active{background:var(--pine-pale)}
@media (hover:hover){ .arreglar:hover{background:var(--pine-pale)} }
.check-done{
  border:1px solid var(--pine-pale);background:var(--pine-pale);border-radius:var(--r);padding:14px 16px;
}
.check-done b{display:block;font-size:14.5px;font-weight:800}
.check-done span{display:block;font-size:12.5px;color:#3A3A3E;margin-top:2px}

/* Dónde aterrizó el botón "Arreglar". Después de cambiar de pestaña y
   bajar dos mil píxeles, el ojo necesita que algo le diga cuál de los
   veinte campos del formulario era. Se apaga solo a los 2.2s: un
   resaltado permanente se volvería parte del fondo.
   `outline` y no `border`: no empuja el layout ni un píxel, así que el
   destello no mueve de sitio lo que estabas por leer. */
.resaltado{
  outline:2px solid var(--pine); outline-offset:4px;
  border-radius:6px; animation:aterrizar 2.2s var(--ease);
}
@keyframes aterrizar{
  0%   {outline-color:var(--pine); background:var(--pine-pale)}
  70%  {outline-color:var(--pine); background:transparent}
  100% {outline-color:transparent; background:transparent}
}
@media (prefers-reduced-motion:reduce){
  .resaltado{animation:none}
}

/* ── Dos columnas en escritorio, apiladas en teléfono ──────────────── */
.two-col{display:grid;grid-template-columns:1fr;gap:13px;margin-top:14px}
.dos,.tres{display:grid;grid-template-columns:1fr;gap:0 11px}

/* ── Tarjeta de dinero ─────────────────────────────────────────────── */
.money-card{border:1px solid var(--sand);border-radius:var(--r);padding:15px}
.money-card .k{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--mist);font-weight:700}
.money-v{font-size:31px;font-weight:800;letter-spacing:-.02em;margin:6px 0 12px;line-height:1}

/* ── Renglón compacto (agenda, pagos, staff) ───────────────────────── */
.row-item{
  display:flex;align-items:center;gap:12px;padding:12px 13px;border:1px solid var(--sand);
  border-radius:var(--r-sm);margin-bottom:8px;background:var(--paper);flex-wrap:wrap;
}
.row-item[onclick]{cursor:pointer;transition:.15s}
.row-item[onclick]:active{transform:scale(.99);border-color:var(--pine-soft)}
.row-item.pasada{opacity:.5}
.ri-hora{font-size:14px;font-weight:600;color:var(--ink);flex-shrink:0;min-width:46px}
.ri-main{flex:1;min-width:120px}
.ri-main b{display:block;font-size:14.5px;font-weight:700}
.ri-main small{display:block;font-size:12px;color:var(--mist);margin-top:1px}

/* ── Ranking con barra proporcional ────────────────────────────────── */
.rankbars{display:flex;flex-direction:column;gap:9px}
.rank{display:flex;align-items:center;gap:11px;font-size:13px}
.rank-n{flex:0 0 34%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
.rank-bar{flex:1;height:9px;border-radius:99px;background:var(--bone);overflow:hidden;min-width:40px}
.rank-bar i{display:block;height:100%;background:var(--pine);border-radius:99px;transition:width .4s var(--ease)}
.rank b{flex-shrink:0;font-weight:700;font-size:12.5px;min-width:46px;text-align:right}

/* ── Renglón de club en el panel de plataforma ─────────────────────── */
.club-row{
  display:flex;align-items:center;gap:13px;padding:13px;border:1px solid var(--sand);
  border-radius:var(--r);margin-bottom:10px;cursor:pointer;transition:.15s;background:var(--paper);flex-wrap:wrap;
}
.club-row:hover{border-color:var(--pine-soft);box-shadow:var(--shadow-sm)}
.club-row:active{transform:scale(.995)}
.cr-photo{width:54px;height:54px;border-radius:14px;flex-shrink:0;background-size:cover;background-position:center}
.cr-main{flex:1;min-width:150px}
.cr-title{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.cr-title b{font-size:16px;font-weight:700}
.cr-sub{font-size:12.5px;color:var(--mist);margin-top:2px}
.cr-warn{font-size:11.5px;color:var(--clay);font-weight:600;margin-top:5px}
.cr-stats{display:flex;gap:16px;flex-shrink:0}
.cr-stats div{text-align:right}
.cr-stats b{display:block;font-size:14px;font-weight:700;line-height:1.2}
.cr-stats span{display:block;font-size:9.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--mist);font-weight:700;margin-top:2px}
.cr-chev{width:18px;height:18px;stroke:var(--sand-deep);fill:none;stroke-width:2;flex-shrink:0}

/* ── Chips de selección múltiple (deportes, amenidades) ────────────── */
.pick{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:6px}
.pick-chip{
  border:1px solid var(--sand);border-radius:99px;padding:9px 15px;font-size:13.5px;font-weight:600;
  background:var(--paper);transition:.15s;
}
.pick-chip:active{transform:scale(.97)}
.pick-chip.on{background:var(--ink);color:var(--paper);border-color:var(--ink)}

/* ── Interruptor dentro de formulario ──────────────────────────────── */
.sw{display:flex;align-items:flex-start;gap:12px;padding:13px 14px;border:1px solid var(--sand);
  border-radius:var(--r-sm);cursor:pointer;margin-bottom:13px}
.sw input{position:absolute;opacity:0;width:0;height:0}
.sw-box{width:42px;height:25px;border-radius:99px;background:var(--sand-deep);flex-shrink:0;position:relative;transition:.2s var(--ease);margin-top:1px}
.sw-box::after{content:'';position:absolute;top:3px;left:3px;width:19px;height:19px;border-radius:50%;background:#fff;transition:.2s var(--ease)}
.sw input:checked + .sw-box{background:var(--pine)}
.sw input:checked + .sw-box::after{transform:translateX(17px)}
.sw input:focus-visible + .sw-box{outline:2px solid var(--pine);outline-offset:2px}
.sw-txt b{display:block;font-size:14px;font-weight:700}
.sw-txt small{display:block;font-size:12px;color:var(--mist);margin-top:2px;line-height:1.45}

/* ── Permisos de una persona del equipo ────────────────────────────── */
.perm-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:13px}
.perm{display:flex;align-items:center;gap:8px;font-size:12.5px;font-weight:600;color:var(--ink);cursor:pointer;margin:0}
.perm input{width:17px;height:17px;accent-color:var(--pine);flex-shrink:0}

/* ── Barra de guardado al pie del formulario ───────────────────────── */
.save-bar{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:22px;padding:15px;
  border:1px solid var(--sand);border-radius:var(--r);background:var(--bone);
}
.save-bar b{display:block;font-size:14px;font-weight:700}
.save-bar span{display:block;font-size:12px;color:var(--mist);margin-top:2px}
.save-bar .btn{margin-left:auto}

/* ── Portada + logo del club ───────────────────────────────────────── */
.club-cover{position:relative;justify-content:space-between}
.cover-logo{
  width:60px;height:60px;border-radius:16px;background:var(--paper);background-size:cover;background-position:center;
  border:2px solid var(--paper);box-shadow:var(--shadow);display:grid;place-items:center;
  font-weight:800;font-size:24px;color:var(--ink);flex-shrink:0;
}
.cover-btns{display:flex;gap:8px;flex-wrap:wrap;align-items:flex-end}
.cover-btns .btn.ghost{background:rgba(255,255,255,.92)}

/* ── Corregir asistencia desde la lista de una sesión ──────────────── */
.asis-btns{display:flex;gap:7px;flex-shrink:0;flex-wrap:wrap}

/* ── Enlace discreto dentro de un formulario ("¿olvidaste tu…?") ───── */
.link-sm{font-size:12.5px;font-weight:600;color:var(--pine);padding:4px 0}
.link-sm:hover{text-decoration:underline}

/* ── Perfil público del club ───────────────────────────────────────── */
.volver{display:flex;align-items:center;gap:5px;font-size:13.5px;font-weight:700;color:var(--ink);padding:12px 0 6px}
.volver svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:2.2}
/* La misma proporción que `.club-cover`, y por una razón concreta: el
   panel promete "esto es exactamente lo que ve un socio". Si la vista
   previa del club recorta distinto que la ficha real, la promesa es
   falsa y el club encuadra su foto para una caja que no existe. */
.cp-hero{
  aspect-ratio:16/9; max-height:300px; min-height:160px;
  border-radius:var(--r-lg);background-size:cover;background-position:center;
  display:flex;align-items:flex-end;padding:14px;border:1px solid var(--sand);
}
.cp-logo{
  width:64px;height:64px;border-radius:18px;background:var(--paper);background-size:cover;background-position:center;
  border:2px solid var(--paper);box-shadow:var(--shadow);display:grid;place-items:center;
  font-weight:800;font-size:26px;color:var(--ink);
}
.cp-meta{display:flex;align-items:center;gap:7px;font-size:13.5px;color:var(--mist);flex-wrap:wrap}
.cp-meta b{color:var(--ink);font-weight:700}
.cp-desc{font-size:15px;line-height:1.55;color:#3A3A3E;margin-top:12px}

.stars{letter-spacing:1px;font-size:14px;color:var(--sand-deep);white-space:nowrap}
.stars .on{color:#F5A623}

.amen-grid{display:grid;grid-template-columns:1fr 1fr;gap:9px}
.amen{display:flex;align-items:center;gap:9px;font-size:13.5px;font-weight:600;
  border:1px solid var(--sand);border-radius:var(--r-sm);padding:11px 13px}
.amen span{font-size:17px;line-height:1}

.respuesta{margin-top:11px;padding:11px 13px;background:var(--bone);border-radius:var(--r-sm);border-left:3px solid var(--pine)}
.respuesta b{display:block;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--mist)}
.respuesta p{font-size:13.5px;line-height:1.5;margin-top:4px}

/* ── Calificar ─────────────────────────────────────────────────────── */
.rate-row{display:flex;align-items:center;gap:3px;margin-top:11px}
.rate-row span{font-size:12px;color:var(--mist);margin-left:8px}
.rate-star{font-size:24px;color:var(--sand-deep);line-height:1;padding:2px;transition:.12s}
.rate-star:hover,.rate-star:hover ~ .rate-star{color:#F5A623}
.rate-big{display:flex;justify-content:center;gap:8px}
.rate-big button{font-size:42px;color:var(--sand-deep);line-height:1;transition:.12s}
.rate-big button.on{color:#F5A623;transform:scale(1.06)}
.rate-label{text-align:center;font-size:14px;font-weight:700;margin-top:8px;min-height:21px}

@media (min-width:600px){ .amen-grid{grid-template-columns:repeat(3,1fr)} }

/* ── Cabecera de la hoja de detalle de club ────────────────────────── */
.sheet-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
/* Las pestañas dentro de una hoja no salen a sangre como las del panel. */
.sheet .pnav{margin:12px 0 16px;padding:0}

@media (min-width:860px){
  /* La hoja modal nació para teléfono: pegada abajo, con su agarradera
     para arrastrarla. En escritorio eso no significa nada —no hay gesto
     que arrastrar— y un cajón que sube desde el borde inferior de un
     monitor se lee como un error. Se convierte en un diálogo centrado. */
  .sheet{
    max-width:540px;
    left:50%;right:auto;top:50%;bottom:auto;
    transform:translate(-50%,-50%);
    border-radius:24px;max-height:86vh;
    padding:26px 28px;box-shadow:var(--shadow-lg);
    animation:aparece .22s var(--ease);
  }
  .sheet.cerrando{animation:saleDialogo .17s var(--ease) forwards}
  .sheet .grip{display:none}
  .two-col{grid-template-columns:1fr 1fr;gap:16px}
  .dos{grid-template-columns:1fr 1fr}
  .tres{grid-template-columns:1fr 1fr 1fr}
  .kpi{padding:16px}
  .kpi .v{font-size:29px}
  .chart-bars{height:150px}
  .sec-title h3{font-size:21px}
  .perm-grid{grid-template-columns:repeat(4,1fr)}
}
@media (max-width:600px){
  /* ── Tarjeta de clase en teléfono ──────────────────────────────────
     En 374px de pantalla, al cuerpo de la tarjeta le quedan ~236px
     después de la miniatura y los rellenos, y la pastilla del costo se
     comía otros 82. Con eso, "Reformer Intermedio" partía en dos
     renglones, el nombre del club en otros dos, y la fila de datos
     desbordaba dejando un punto separador huérfano al final del primer
     renglón. Se recupera espacio de donde no duele —miniatura, rellenos
     y separaciones— y se obliga a cada dato a caber en su línea. */
  .sesion-card{gap:10px;padding:13px}
  .sc-thumb{width:50px;height:50px;border-radius:12px}
  .sc-top{gap:8px}
  .sesion-card h4{font-size:15.5px;line-height:1.25}
  /* El nombre del club se recorta con puntos suspensivos en vez de
     partirse: la distancia que va al final ("· 5.9 km") es lo primero
     que sobra cuando no cabe. */
  .sesion-card .club{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .sesion-card .cost{font-size:12px;padding:4px 9px}
  /* Sin wrap: los tres datos caben en un renglón al reducir la
     separación, y así ya no queda ningún punto colgando. */
  .card .meta{gap:7px}
  .sesion-card .meta{flex-wrap:nowrap;font-size:11.5px;overflow:hidden}
  .sesion-card .meta > span:not(.dot){white-space:nowrap}

  /* En teléfono los KPI del club/plataforma van de dos en dos: cuatro
     tarjetas apiladas obligarían a hacer scroll para leer un resumen. */
  .g4{grid-template-columns:1fr 1fr}
  .kpi .v{font-size:22px}
  .cr-stats{width:100%;justify-content:space-between;gap:8px;padding-top:4px;border-top:1px solid var(--sand)}
  .cr-stats div{text-align:left}
  .cr-chev{display:none}
  .occ{width:96px}
}

/* ═══════════════════════════════════════════════════════════════════
   SISTEMA DE INTERACCIÓN
   Todo lo que se puede tocar responde igual en toda la app: se levanta
   al pasar el puntero, se hunde al presionar y se recupera al soltar.

   Dos decisiones que importan:

   1. Las transiciones nombran las propiedades una por una en vez de
      usar el atajo `transition:.15s`. Ese atajo anima TODO —incluidos
      colores de fondo que cambian al repintar— y en esta app la
      pantalla se repinta cada segundo cuando hay una reserva
      pendiente, así que animar de más se convierte en parpadeo.

   2. El hover vive detrás de `@media (hover:hover) and (pointer:fine)`.
      En una pantalla táctil, `:hover` se queda PEGADO después de tocar
      —el botón se ve resaltado hasta que tocas otra cosa— y eso es
      justo lo que hace sentir una interfaz "rara" en el teléfono.
   ═══════════════════════════════════════════════════════════════════ */

.btn,.btn-pill,.card,.chip,.pick-chip,
.tabbar button,.user-menu button,.alerta,.club-row,.row-item[onclick],
.carousel-card,.rate-star,.link-sm,.ptop-btn{
  transition:transform var(--release) var(--ease),
             box-shadow var(--release) var(--ease),
             background-color var(--release) var(--ease),
             border-color var(--release) var(--ease),
             color var(--release) var(--ease);
}

/* Al presionar, todo se acelera: la respuesta tiene que ser inmediata. */
.btn:active,.btn-pill:active,.card:active,
.chip:active,.pick-chip:active,.tabbar button:active,.user-menu button:active,
.alerta:active,.club-row:active,.row-item[onclick]:active,
.carousel-card:active,.ptop-btn:active{
  transition-duration:var(--press);
}

/* ── Presionado ─────────────────────────────────────────────────────
   Aplica en teléfono y en escritorio. En teléfono es especialmente
   necesario porque el reset global apaga `-webkit-tap-highlight-color`,
   o sea que el destello que el navegador da por su cuenta al tocar no
   existe: si no ponemos nosotros un estado visible, tocar no se ve. */
/* Los botones sólidos descansan con una sombra suave, no planos.
   Es la corrección que hace que dejen de sentirse "duros": cuando el
   estado de reposo no tiene profundidad, el hover tiene que INVENTAR una
   sombra desde cero y el ojo lo lee como un salto, no como un
   movimiento. Con una sombra en reposo, pasar el cursor sólo la agranda
   —el botón sube— y presionar la aplasta. Es la misma pieza cambiando de
   altura, que es lo que se siente como material.

   Los fantasma se quedan sin sombra a propósito: son secundarios y
   levantarlos los pondría al mismo nivel que la acción principal. */
.btn:not(.ghost):not(:disabled){box-shadow:0 2px 8px -3px rgba(15,15,15,.28)}

/* `.btn-pill` recibe el mismo trato: es el botón que más se ve dentro de
   la app ya con sesión —el de la tarjeta de saldo— y se había quedado
   fuera, con sólo un cambio de fondo al pasar el cursor. Los sólidos son
   los que llevan sombra; el fantasma sigue plano. */
.btn-pill.dark,.btn-pill.blue{box-shadow:0 2px 8px -3px rgba(15,15,15,.28)}
.btn-pill.dark:active,.btn-pill.blue:active{box-shadow:0 1px 3px -1px rgba(15,15,15,.3)}

.btn:active{transform:scale(.975)}
.btn:not(.ghost):not(:disabled):active{box-shadow:0 1px 3px -1px rgba(15,15,15,.3)}
.btn.green:active{background:var(--green-deep)}
.btn:not(.ghost):not(.green):not(.danger):active{background:var(--ink-hover)}
.btn.ghost:active{background:var(--bone);box-shadow:none}
.card:active{transform:scale(.985);border-color:var(--pine-soft);box-shadow:none}
.chip:active,.pick-chip:active{transform:scale(.95)}
.btn-pill:active{transform:scale(.97)}
.carousel-card:active{transform:scale(.97)}
.tabbar button:active{background:var(--sand)}
.user-menu button:active{background:var(--sand)}

/* ── Puntero fino: hover ────────────────────────────────────────── */
@media (hover:hover) and (pointer:fine){
  /* Sube 2px y la sombra crece y se abre. Antes era 1px con una sombra
     corta y oscura: el movimiento apenas se percibía y la sombra, al ser
     tan cerrada, parecía un borde en vez de profundidad. */
  .btn:not(.ghost):not(:disabled):hover{transform:translateY(-2px);box-shadow:0 10px 22px -8px rgba(15,15,15,.36)}
  .btn.ghost:not(:disabled):hover{transform:translateY(-1px)}
  .btn:not(.ghost):not(.green):not(.danger):hover{background:var(--ink-hover)}
  .btn.green:hover{background:var(--green-deep)}
  .btn.ghost:hover{background:var(--bone);border-color:var(--sand-deep);box-shadow:none}
  .btn.ghost.danger:hover{background:var(--clay-pale);border-color:var(--clay)}
  .btn.danger:not(.ghost):hover{background:#C93B3B}
  .btn:disabled:hover{transform:none;box-shadow:none}

  .card:hover{border-color:var(--sand-deep);box-shadow:var(--shadow);transform:translateY(-2px)}
  .chip:hover{border-color:var(--ink);background:var(--bone)}
  .more-dots:hover{background:var(--bone);color:var(--ink)}
  .tip-banner:hover{background:#EBD6FF}   /* un paso más saturado que --pine-pale */
  .chip.on:hover{background:var(--ink-hover)}
  .carousel-card:hover{transform:translateY(-3px)}
  .user-menu button:hover{background:var(--bone)}

  /* Las pastillas del monedero son un botón sólido de color, no una
     tarjeta. `filter:brightness` no sirve aquí: sobre el negro casi puro
     de --ink un 8% más de brillo es invisible. Cada variante necesita su
     color de hover explícito. */
  .btn-pill:hover{transform:translateY(-1px);box-shadow:0 6px 16px -6px rgba(15,15,15,.4)}
  .btn-pill.dark:hover{background:var(--ink-hover)}
  .btn-pill.blue:hover{background:var(--green-deep)}
  /* Mismo gesto que en `.btn`: sube y la sombra se abre. */
  .btn-pill.dark:hover,.btn-pill.blue:hover{transform:translateY(-2px);box-shadow:0 10px 22px -8px rgba(15,15,15,.36)}
}
