/* =============================================================================
   PLANILLA — Sistema visual de Gym Manager
   -----------------------------------------------------------------------------
   Tesis: la interfaz se lee como la planilla de sala del gimnasio — una retícula
   de registro donde cada fila es una repetición del negocio (una serie, un día,
   una cuota) y el progreso se ve en la estructura, no en la decoración.

   Reglas del sistema
   1. La identidad la sostiene la ESTRUCTURA (reglas, índices, marcas de serie),
      nunca el color. El color de marca es de cada gimnasio y puede ser cualquiera.
   2. Los datos numéricos viven en monoespaciada tabular. El texto, en Archivo.
   3. Nada flota. No hay tarjetas con sombra: hay registros separados por reglas.
   4. El radio es funcional: 0 en estructura y datos, 3px en controles.
   5. El color semántico (ok / pendiente / vencido) nunca actúa solo: siempre lo
      acompaña texto o forma, para daltonismo y para lectura a distancia.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* --- Superficies: papel de planilla, cálido, no blanco puro --- */
  --paper:        #f4f1ea;  /* fondo de la aplicación */
  --paper-raised: #fffdf8;  /* registro / superficie de trabajo */
  --paper-sunken: #eae5d9;  /* cabecera de tabla, banda de sección */
  --paper-inset:  #e2dccd;  /* huecos, pistas de progreso */

  /* --- Tinta --- */
  --ink:      #16181c;  /* texto principal  — 15.8:1 sobre --paper */
  --ink-2:    #52565e;  /* texto secundario —  7.1:1 sobre --paper */
  --ink-3:    #74797f;  /* etiquetas, ayudas — 4.6:1 sobre --paper */
  --ink-soft: #9aa0a6;  /* solo para trazos y marcas vacías, nunca texto */

  /* --- Reglas --- */
  --rule:        #d6cfbf;
  --rule-strong: #b3aa96;
  --rule-ink:    #16181c;

  /* --- Marca del gimnasio (inyectada por el tenant; este es el respaldo) --- */
  --brand: #1f5c46;
  /* Derivadas: se recalculan más abajo con color-mix cuando hay soporte. */
  --brand-ink:  var(--brand); /* marca legible sobre papel */
  --brand-wash: var(--paper-sunken);
  --brand-on:   #ffffff;      /* texto sobre relleno de marca */

  /* --- Semántica de estado --- */
  --ok:       #1f6b3f;  /* completado, al día, ingreso cobrado */
  --ok-wash:  #e2ece3;
  --warn:     #8a5a08;  /* por vencer, requiere seguimiento */
  --warn-wash:#f6ecd8;
  --danger:   #a32218;  /* vencido, error, destructivo */
  --danger-wash:#f6e2e0;
  --info:     #1f4d6b;
  --info-wash:#e0eaf0;

  /* --- Dinero: la misma escala semántica, nombrada por función --- */
  --money-in:      var(--ok);      /* cobrado */
  --money-pending: var(--warn);    /* pendiente */
  --money-overdue: var(--danger);  /* vencido */

  /* --- Tipografía --- */
  --font-text: 'Archivo', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-data: 'IBM Plex Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;

  /* Escala tipográfica — saltos intencionales, no una progresión plana */
  --t-display: clamp(2.25rem, 7vw, 3.75rem); /* la respuesta dominante de la pantalla */
  --t-title:   clamp(1.5rem, 3.4vw, 1.875rem);
  --t-lead:    1.125rem;
  --t-body:    0.9375rem;
  --t-small:   0.8125rem;
  --t-micro:   0.6875rem;  /* etiquetas de registro, en mono y versalitas */

  --t-data-xl: clamp(2rem, 5.5vw, 3rem);  /* importes, totales */
  --t-data-lg: 1.375rem;
  --t-data-md: 1rem;

  /* --- Espaciado: base 4, con saltos usables en mano y en escritorio --- */
  --sp-1: 0.25rem;  --sp-2: 0.5rem;   --sp-3: 0.75rem;  --sp-4: 1rem;
  --sp-5: 1.25rem;  --sp-6: 1.5rem;   --sp-8: 2rem;     --sp-10: 2.5rem;
  --sp-12: 3rem;    --sp-16: 4rem;    --sp-20: 5rem;

  /* --- Radios: limitados y justificados --- */
  --r-control: 3px;  /* botones, campos: acusan que se pueden tocar */
  --r-mark:    1px;  /* marcas de serie */
  --r-media:   2px;  /* fotos de personas: ficha, no burbuja */

  /* --- Medidas --- */
  --rail-w: 232px;
  --tap: 44px;      /* área táctil mínima */
  --measure: 68ch;  /* longitud de línea legible */

  --shadow-overlay: 0 24px 48px -24px rgba(22, 24, 28, 0.45);

  --dur-1: 120ms;
  --dur-2: 200ms;
  --ease: cubic-bezier(0.2, 0, 0.1, 1);

  color-scheme: light;
}

/* Derivadas de la marca. Se calculan solo si el navegador soporta color-mix,
   de modo que un gimnasio con un color muy claro u oscuro siga siendo legible. */
@supports (color: color-mix(in oklab, red, blue)) {
  :root {
    --brand-ink:  color-mix(in oklab, var(--brand) 72%, #101214);
    --brand-wash: color-mix(in oklab, var(--brand) 12%, var(--paper-raised));
  }
}

/* Contrapartida oscura: los mismos tokens, tinta invertida. La estructura no
   cambia, así que la identidad se mantiene idéntica en ambos esquemas. */
@media (prefers-color-scheme: dark) {
  :root {
    --paper:        #16171a;
    --paper-raised: #1d1f23;
    --paper-sunken: #25282d;
    --paper-inset:  #2e3238;

    --ink:      #f2efe8;
    --ink-2:    #b3b6bb;
    --ink-3:    #8d9197;
    --ink-soft: #5b6067;

    --rule:        #33373d;
    --rule-strong: #4a4f57;
    --rule-ink:    #f2efe8;

    --ok:        #6fc08a;  --ok-wash:     #1c2b22;
    --warn:      #dda63f;  --warn-wash:   #2e2617;
    --danger:    #ef8078;  --danger-wash: #2f1d1c;
    --info:      #7fb6d6;  --info-wash:   #1a2630;

    --brand-on: #101214;
    color-scheme: dark;
  }

  @supports (color: color-mix(in oklab, red, blue)) {
    :root {
      --brand-ink:  color-mix(in oklab, var(--brand) 62%, #f2efe8);
      --brand-wash: color-mix(in oklab, var(--brand) 18%, var(--paper-raised));
      --brand-on:   #101214;
    }
  }
}

/* -----------------------------------------------------------------------------
   2. BASE
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: var(--t-body);
  line-height: 1.55;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  margin: 0;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

p { margin: 0 0 var(--sp-3); max-width: var(--measure); }
p:last-child { margin-bottom: 0; }

a { color: var(--ink); text-decoration-color: var(--rule-strong); text-underline-offset: 3px; }
a:hover { text-decoration-color: currentColor; }

img { max-width: 100%; height: auto; display: block; }

hr { border: 0; border-top: 1px solid var(--rule); margin: var(--sp-6) 0; }

/* Un solo anillo de foco en toda la aplicación: visible sobre cualquier fondo. */
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: 1px;
}
@media (prefers-color-scheme: dark) {
  :focus-visible { outline-color: var(--ink); }
}

::selection { background: var(--brand); color: var(--brand-on); }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: var(--sp-2); top: -100px; z-index: 200;
  background: var(--ink); color: var(--paper);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-control);
  font-weight: 600; text-decoration: none;
}
.skip-link:focus { top: var(--sp-2); }

/* -----------------------------------------------------------------------------
   3. VOZ TIPOGRÁFICA
   -------------------------------------------------------------------------- */

/* La etiqueta de registro: versalitas monoespaciadas. Es la voz de la planilla
   y aparece en cada sección de la aplicación. */
.label {
  font-family: var(--font-data);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  display: block;
}
.label--ink { color: var(--ink); }

/* Todo número que se compara verticalmente usa cifras tabulares. */
.data {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
  letter-spacing: -0.01em;
}
.data--xl { font-size: var(--t-data-xl); font-weight: 600; line-height: 1; letter-spacing: -0.03em; }
.data--lg { font-size: var(--t-data-lg); font-weight: 600; line-height: 1.1; }
.data--md { font-size: var(--t-data-md); font-weight: 500; }
.data--sm { font-size: var(--t-small); font-weight: 500; }

.display {
  font-size: var(--t-display);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 0.98;
}

.title    { font-size: var(--t-title); font-weight: 700; }
.lead     { font-size: var(--t-lead); color: var(--ink-2); font-weight: 400; }
.muted    { color: var(--ink-2); }
.dim      { color: var(--ink-3); }
.small    { font-size: var(--t-small); }
.micro    { font-size: var(--t-micro); }
.strong   { font-weight: 700; }
.nowrap   { white-space: nowrap; }

.money            { font-family: var(--font-data); font-variant-numeric: tabular-nums; font-weight: 600; }
.money--in        { color: var(--money-in); }
.money--pending   { color: var(--money-pending); }
.money--overdue   { color: var(--money-overdue); }

/* -----------------------------------------------------------------------------
   4. FIRMA VISUAL
   -------------------------------------------------------------------------- */

/* 4.1 — LA MARCA DE SERIE.
   Trazos discretos e inclinados, como las marcas de conteo de una planilla.
   Codifica cantidades pequeñas y contables: series hechas, ejercicios
   completados, semanas de una cuota, cuotas de un ciclo. Es el recurso que se
   repite en toda la aplicación. */
.tally {
  display: inline-flex;
  align-items: flex-end;
  gap: 3px;
  line-height: 0;
}
.tally__i {
  display: block;
  width: 3px;
  height: 16px;
  border-radius: var(--r-mark);
  background: var(--ink-soft);
  transform: skewX(-12deg);
  transform-origin: bottom;
  transition: background-color var(--dur-2) var(--ease), height var(--dur-2) var(--ease);
}
.tally__i--done  { background: var(--ink); height: 18px; }
.tally__i--brand { background: var(--brand); height: 18px; }
.tally__i--ok    { background: var(--ok); height: 18px; }
.tally__i--miss  { background: var(--danger); height: 18px; }

.tally--sm .tally__i { width: 2px; height: 11px; gap: 2px; }
.tally--sm .tally__i--done, .tally--sm .tally__i--brand,
.tally--sm .tally__i--ok   { height: 13px; }
.tally--lg .tally__i { width: 4px; height: 26px; }
.tally--lg .tally__i--done, .tally--lg .tally__i--brand,
.tally--lg .tally__i--ok   { height: 30px; }

/* 4.2 — EL ÍNDICE.
   Toda secuencia (día, bloque, ejercicio, cuota) se numera a dos cifras. */
.idx {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  font-feature-settings: 'tnum' 1;
}
.idx--lg { font-size: var(--t-data-lg); color: var(--ink); letter-spacing: -0.02em; }

/* 4.3 — LA REGLA MARCADA.
   Un filete con la marca de tinta en el extremo izquierdo: es el renglón de la
   planilla y encabeza cada bloque del sistema. */
.rule-tick {
  height: 2px;
  border: 0;
  margin: 0;
  background:
    linear-gradient(to right, var(--rule-ink) 0 28px, transparent 28px) no-repeat,
    linear-gradient(to right, var(--rule) 0 100%) no-repeat;
  background-size: 100% 2px, 100% 1px;
  background-position: 0 0, 0 0;
}
.rule-tick--brand {
  background:
    linear-gradient(to right, var(--brand) 0 28px, transparent 28px) no-repeat,
    linear-gradient(to right, var(--rule) 0 100%) no-repeat;
  background-size: 100% 2px, 100% 1px;
}

/* 4.4 — LA PISTA SEGMENTADA.
   Para magnitudes continuas (período de una cuota transcurrido). Segmentada,
   no una barra lisa, para que se lea como una progresión contable. */
.track {
  display: flex;
  gap: 2px;
  height: 8px;
  background: transparent;
}
.track__seg {
  flex: 1;
  background: var(--paper-inset);
  border-radius: var(--r-mark);
}
.track__seg--on   { background: var(--ink); }
.track__seg--warn { background: var(--warn); }
.track__seg--over { background: var(--danger); }

/* -----------------------------------------------------------------------------
   5. ESTRUCTURA DE LA APLICACIÓN
   -------------------------------------------------------------------------- */
.shell {
  min-height: 100vh;
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
}
/* Login, cambio de clave forzado y páginas de error: sin carril ni barra. */
.shell--anon { grid-template-columns: minmax(0, 1fr); }
.content--anon {
  max-width: 520px;
  margin-inline: auto;
  padding-block: var(--sp-12) var(--sp-16);
}

/* Los iconos heredan el color del texto y nunca se comprimen en un flex. */
.ico { flex: none; }

/* 5.1 — Carril de navegación (escritorio).
   Rótulo del gimnasio arriba, secciones del rol, identidad y salida abajo. */
.rail {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--paper-raised);
  border-right: 1px solid var(--rule);
  padding: var(--sp-5) 0 var(--sp-4);
}

.rail__brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 0 var(--sp-5) var(--sp-5);
  text-decoration: none;
  color: var(--ink);
}
.rail__logo {
  width: 32px; height: 32px;
  object-fit: contain;
  border-radius: var(--r-media);
  flex: none;
}
.rail__name {
  display: block;
  font-weight: 800;
  font-size: 1rem;
  letter-spacing: -0.02em;
  line-height: 1.15;
  overflow-wrap: anywhere;
}
.rail__role {
  display: block;
  margin-top: 2px;
  font-family: var(--font-data);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.rail__nav { display: flex; flex-direction: column; padding: 0 var(--sp-3); }

.rail__section {
  padding: var(--sp-5) var(--sp-2) var(--sp-2);
  font-family: var(--font-data);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.rail__link {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-3);
  min-height: var(--tap);
  color: var(--ink-2);
  text-decoration: none;
  font-weight: 500;
  border-left: 2px solid transparent;
  transition: background-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.rail__link svg { width: 18px; height: 18px; flex: none; stroke-width: 1.75; }
.rail__link:hover { background: var(--paper-sunken); color: var(--ink); }
.rail__link[aria-current="page"] {
  color: var(--ink);
  font-weight: 700;
  border-left-color: var(--brand);
  background: var(--brand-wash);
}
.rail__count {
  margin-left: auto;
  font-family: var(--font-data);
  font-size: var(--t-micro);
  font-weight: 600;
  color: var(--ink-3);
}

.rail__foot {
  margin-top: auto;
  padding: var(--sp-4) var(--sp-5) 0;
  border-top: 1px solid var(--rule);
}

/* 5.2 — Área de contenido */
.content {
  min-width: 0;
  padding: var(--sp-10) var(--sp-8) var(--sp-20);
  max-width: 1180px;
}

/* 5.3 — Cabecera de página.
   No es un hero: es el encabezado de una planilla. Etiqueta de contexto, el dato
   dominante, y las acciones alineadas a la derecha. */
.page-head { margin-bottom: var(--sp-8); }
.page-head__top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-6);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}
.page-head__titles { min-width: 0; }
.page-head__actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

/* 5.4 — Barra inferior (móvil). Solo aparece bajo 900px. */
.tabbar { display: none; }

/* 5.5 — Cabecera móvil */
.topbar { display: none; }

/* -----------------------------------------------------------------------------
   6. REGISTRO — el contenedor base del sistema
   No es una tarjeta: no flota, no tiene sombra ni esquinas redondeadas. Es un
   bloque de planilla delimitado por reglas.
   -------------------------------------------------------------------------- */
.register {
  background: var(--paper-raised);
  border: 1px solid var(--rule);
  border-radius: 0;
}
.register + .register { margin-top: var(--sp-6); }

.register__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--rule);
  background: var(--paper-sunken);
}
.register__title { font-size: 1rem; font-weight: 700; letter-spacing: -0.01em; }
.register__body { padding: var(--sp-5); }
.register__body--flush { padding: 0; }
.register__foot {
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--rule);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
}

/* 6.1 — Renglón: la unidad de lectura. Separado por reglas, nunca por cajas. */
.row {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--rule);
  min-height: 60px;
}
.row:last-child { border-bottom: 0; }
.row--link {
  text-decoration: none;
  color: inherit;
  transition: background-color var(--dur-1) var(--ease);
}
.row--link:hover { background: var(--paper-sunken); }
.row--link:focus-visible { outline-offset: -2px; }
.row__main { min-width: 0; flex: 1; }
.row__title { font-weight: 600; letter-spacing: -0.01em; overflow-wrap: anywhere; }
.row__meta {
  font-size: var(--t-small);
  color: var(--ink-2);
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
  align-items: center;
}
.row__end { display: flex; align-items: center; gap: var(--sp-4); flex: none; }
.row__chevron { color: var(--ink-3); flex: none; }

/* 6.2 — Bandas de atención. El borde izquierdo grueso marca prioridad sin
   convertir el renglón en una caja de color. */
.row--attn      { border-left: 3px solid var(--warn); }
.row--overdue   { border-left: 3px solid var(--danger); }
.row--done      { border-left: 3px solid var(--ok); }

/* -----------------------------------------------------------------------------
   7. CIFRAS — el bloque de dato dominante
   No es una "métrica de dashboard": es la respuesta a una pregunta concreta,
   con su comparación al lado.
   -------------------------------------------------------------------------- */
.figures {
  display: grid;
  gap: 0;
  border: 1px solid var(--rule);
  background: var(--paper-raised);
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.figure {
  padding: var(--sp-5);
  border-right: 1px solid var(--rule);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-width: 0;
}
.figure:last-child { border-right: 0; }
.figure__value { font-size: var(--t-data-xl); }
.figure__note {
  font-size: var(--t-small);
  color: var(--ink-2);
  display: flex;
  align-items: center;
  gap: var(--sp-1);
}
.figure__note svg { width: 14px; height: 14px; flex: none; }
.figure__note--up   { color: var(--ok); }
.figure__note--down { color: var(--danger); }

/* 7.1 — TIRA SEMANAL DE COBROS.
   Sustituye al gráfico de líneas: siete columnas, la cifra de cada día visible.
   El propietario necesita el número, no la curva — y evita cargar una librería
   de gráficos para representar siete valores. */
.week {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}
.week__day {
  background: var(--paper-raised);
  padding: var(--sp-3) var(--sp-2);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}
.week__label {
  font-family: var(--font-data);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  white-space: nowrap;
}
.week__track {
  width: 100%;
  height: 64px;
  background: var(--paper-inset);
  display: flex;
  align-items: flex-end;
}
.week__fill { width: 100%; background: var(--ink); min-height: 2px; }
.week__day--today .week__fill { background: var(--brand); }
.week__day--today .week__label { color: var(--ink); }
.week__value {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-micro);
  font-weight: 600;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* -----------------------------------------------------------------------------
   8. SESIÓN DE ENTRENAMIENTO — la pantalla del alumno
   -------------------------------------------------------------------------- */

/* 8.1 — Ejercicio: un renglón de planilla ampliado, pensado para leerse de pie,
   a un brazo de distancia, y operarse con una sola mano. */
.exercise {
  border-bottom: 1px solid var(--rule);
  background: var(--paper-raised);
}
.exercise:last-child { border-bottom: 0; }
.exercise__head {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  padding: var(--sp-5);
}
.exercise__idx {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--ink-3);
  line-height: 1;
  padding-top: 2px;
  flex: none;
  min-width: 2.2ch;
}
.exercise__name {
  font-size: var(--t-lead);
  font-weight: 700;
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
  margin-bottom: var(--sp-2);
}
.exercise__grid {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-5);
  align-items: baseline;
}
.exercise__stat { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.exercise__stat .label { margin-bottom: 1px; }
.exercise__note {
  margin: 0 var(--sp-5) var(--sp-5);
  padding: var(--sp-3) var(--sp-4);
  background: var(--paper-sunken);
  border-left: 2px solid var(--rule-strong);
  font-size: var(--t-small);
  color: var(--ink-2);
}
.exercise__note strong { color: var(--ink); font-weight: 600; }
.exercise--done { background: var(--paper); }
.exercise--done .exercise__name { color: var(--ink-2); }

/* 8.2 — Contador de series táctil: botones grandes, uno por serie. */
.sets {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
  padding: 0 var(--sp-5) var(--sp-5);
}
.set-btn {
  min-width: var(--tap);
  min-height: var(--tap);
  padding: 0 var(--sp-3);
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-control);
  background: var(--paper-raised);
  color: var(--ink-2);
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-data-md);
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease);
}
.set-btn:hover { border-color: var(--ink); color: var(--ink); }
.set-btn[aria-pressed="true"] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper-raised);
}

/* -----------------------------------------------------------------------------
   9. CONTROLES
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--tap);
  padding: 0 var(--sp-5);
  border: 1px solid transparent;
  border-radius: var(--r-control);
  background: var(--ink);
  color: var(--paper-raised);
  font-family: var(--font-text);
  font-size: var(--t-body);
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease);
}
.btn svg { width: 17px; height: 17px; flex: none; stroke-width: 2; }
.btn:hover { background: #000; }
@media (prefers-color-scheme: dark) { .btn:hover { background: #fff; } }
.btn:active { transform: translateY(1px); }
.btn[disabled], .btn[aria-disabled="true"] {
  opacity: 0.45; cursor: not-allowed; pointer-events: none;
}

.btn--ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--rule-strong);
}
.btn--ghost:hover { background: var(--paper-sunken); border-color: var(--ink); }

.btn--brand { background: var(--brand); color: var(--brand-on); }
.btn--brand:hover { background: var(--brand-ink); }

.btn--danger { background: transparent; color: var(--danger); border-color: var(--danger); }
.btn--danger:hover { background: var(--danger-wash); }

.btn--sm { min-height: 34px; padding: 0 var(--sp-3); font-size: var(--t-small); }
.btn--sm svg { width: 15px; height: 15px; }
.btn--block { width: 100%; }

/* Botón de icono: mantiene el área táctil aunque el icono sea pequeño. */
.btn-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--tap); height: var(--tap);
  border: 1px solid transparent; border-radius: var(--r-control);
  background: transparent; color: var(--ink-2); cursor: pointer;
  transition: background-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.btn-icon:hover { background: var(--paper-sunken); color: var(--ink); }
.btn-icon svg { width: 18px; height: 18px; }

/* -----------------------------------------------------------------------------
   10. FORMULARIOS
   -------------------------------------------------------------------------- */
.form { display: flex; flex-direction: column; gap: var(--sp-5); }
.form-grid {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.field { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.field__label {
  font-family: var(--font-data);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.field__req { color: var(--danger); font-family: var(--font-text); }
.field__hint { font-size: var(--t-small); color: var(--ink-3); }
.field__error {
  font-size: var(--t-small);
  color: var(--danger);
  font-weight: 600;
  display: flex; align-items: center; gap: var(--sp-1);
}
.field__error svg { width: 14px; height: 14px; flex: none; }

.input, .select, .textarea {
  width: 100%;
  min-height: var(--tap);
  padding: var(--sp-3) var(--sp-3);
  background: var(--paper-raised);
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-control);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: var(--t-body);
  line-height: 1.4;
  transition: border-color var(--dur-1) var(--ease);
}
/* Campos numéricos: mono tabular, para que las columnas se alineen al leerlas. */
.input--data, input[type="number"].input { font-family: var(--font-data); font-variant-numeric: tabular-nums; }
.textarea { min-height: 96px; resize: vertical; }
.select {
  appearance: none;
  padding-right: var(--sp-8);
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-2) 50%),
                    linear-gradient(135deg, var(--ink-2) 50%, transparent 50%);
  background-position: calc(100% - 18px) 52%, calc(100% - 13px) 52%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.input:hover, .select:hover, .textarea:hover { border-color: var(--ink-2); }
.input:focus, .select:focus, .textarea:focus { border-color: var(--ink); }
.input::placeholder, .textarea::placeholder { color: var(--ink-3); }
.input[aria-invalid="true"], .select[aria-invalid="true"], .textarea[aria-invalid="true"] {
  border-color: var(--danger);
  border-width: 2px;
}
.input[disabled], .select[disabled], .textarea[disabled] {
  background: var(--paper-sunken); color: var(--ink-3); cursor: not-allowed;
}

/* Grupo de campo con acción adosada (por ejemplo, peso + guardar). */
.field-inline { display: flex; gap: var(--sp-2); align-items: stretch; }
.field-inline .input { flex: 1; min-width: 0; }

.check {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  min-height: var(--tap); cursor: pointer;
}
.check input { width: 20px; height: 20px; margin-top: 2px; accent-color: var(--ink); flex: none; }

.fieldset { border: 0; padding: 0; margin: 0; }
.fieldset__legend {
  font-family: var(--font-data);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 0 0 var(--sp-3);
  width: 100%;
  border-bottom: 1px solid var(--rule);
  margin-bottom: var(--sp-5);
}

.form-actions {
  display: flex; gap: var(--sp-3); flex-wrap: wrap;
  padding-top: var(--sp-5); border-top: 1px solid var(--rule);
}

/* -----------------------------------------------------------------------------
   11. TABLAS — planilla propiamente dicha
   -------------------------------------------------------------------------- */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-body);
}
.table th {
  text-align: left;
  padding: var(--sp-3) var(--sp-4);
  background: var(--paper-sunken);
  border-bottom: 1px solid var(--rule-strong);
  font-family: var(--font-data);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
  white-space: nowrap;
}
.table td {
  padding: var(--sp-4);
  border-bottom: 1px solid var(--rule);
  vertical-align: middle;
}
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--paper-sunken); }
.table .num {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.table th.num { text-align: right; }
.table .actions { text-align: right; white-space: nowrap; }

/* -----------------------------------------------------------------------------
   12. ESTADOS
   -------------------------------------------------------------------------- */

/* 12.1 — Estado de un dato. El punto es una forma, no solo color, y siempre
   va acompañado por texto. */
.state {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-family: var(--font-data);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px var(--sp-2) 3px var(--sp-2);
  border: 1px solid currentColor;
  border-radius: var(--r-control);
  white-space: nowrap;
}
.state::before {
  content: '';
  width: 6px; height: 6px;
  background: currentColor;
  flex: none;
}
.state--ok      { color: var(--ok); background: var(--ok-wash); }
.state--warn    { color: var(--warn); background: var(--warn-wash); }
.state--danger  { color: var(--danger); background: var(--danger-wash); }
.state--info    { color: var(--info); background: var(--info-wash); }
.state--muted   { color: var(--ink-3); background: transparent; }
/* La forma diferencia el estado sin depender del color. */
.state--ok::before     { border-radius: 50%; }
.state--warn::before   { transform: rotate(45deg); }
.state--danger::before { clip-path: polygon(50% 0, 100% 100%, 0 100%); }

/* 12.2 — Aviso en línea */
.notice {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: 1px solid var(--rule);
  border-left-width: 3px;
  background: var(--paper-raised);
  font-size: var(--t-small);
}
.notice svg { width: 18px; height: 18px; flex: none; margin-top: 1px; }
.notice__body { min-width: 0; }
.notice__title { font-weight: 700; font-size: var(--t-body); margin-bottom: 2px; }
.notice--ok     { border-left-color: var(--ok);     background: var(--ok-wash);     color: var(--ok); }
.notice--warn   { border-left-color: var(--warn);   background: var(--warn-wash);   color: var(--warn); }
.notice--danger { border-left-color: var(--danger); background: var(--danger-wash); color: var(--danger); }
.notice--info   { border-left-color: var(--info);   background: var(--info-wash);   color: var(--info); }
.notice--ok .notice__body,
.notice--warn .notice__body,
.notice--danger .notice__body,
.notice--info .notice__body { color: var(--ink); }

/* 12.3 — Estado vacío. Dice qué falta y cuál es el siguiente paso; no ilustra. */
.empty {
  padding: var(--sp-10) var(--sp-5);
  text-align: left;
  border: 1px dashed var(--rule-strong);
  background: transparent;
  max-width: 52ch;
}
.empty__mark { margin-bottom: var(--sp-4); }
.empty__title { font-size: var(--t-lead); font-weight: 700; margin-bottom: var(--sp-2); }
.empty__text { color: var(--ink-2); font-size: var(--t-small); margin-bottom: var(--sp-5); }
.empty--center { margin-inline: auto; text-align: center; }
.empty--center .empty__mark { display: flex; justify-content: center; }

/* 12.4 — Carga. Bloques de planilla que laten, no ruedas girando. */
.skeleton {
  background: linear-gradient(90deg, var(--paper-sunken) 0%, var(--paper-inset) 50%, var(--paper-sunken) 100%);
  background-size: 200% 100%;
  animation: skeleton 1.4s linear infinite;
  border-radius: 1px;
}
@keyframes skeleton { to { background-position: -200% 0; } }
.skeleton--line { height: 12px; margin-bottom: var(--sp-2); }
.skeleton--title { height: 22px; width: 45%; margin-bottom: var(--sp-4); }

.is-busy { position: relative; pointer-events: none; opacity: 0.6; }

/* -----------------------------------------------------------------------------
   13. PERSONAS
   -------------------------------------------------------------------------- */
/* Ficha, no burbuja: cuadrada, como una foto de planilla de socios. */
.avatar {
  width: 40px; height: 40px;
  border-radius: var(--r-media);
  background: var(--paper-sunken);
  border: 1px solid var(--rule);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-data);
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--ink-2);
  text-transform: uppercase;
  flex: none;
  overflow: hidden;
  letter-spacing: 0;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar--lg { width: 64px; height: 64px; font-size: var(--t-data-md); }
.avatar--sm { width: 28px; height: 28px; font-size: var(--t-micro); }

.person { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.person__body { min-width: 0; }
.person__name { font-weight: 600; overflow-wrap: anywhere; }
.person__meta { font-size: var(--t-small); color: var(--ink-3); }

/* -----------------------------------------------------------------------------
   14. PANEL LATERAL / DIÁLOGO
   -------------------------------------------------------------------------- */
dialog.sheet {
  border: 1px solid var(--rule);
  border-radius: 0;
  background: var(--paper-raised);
  color: var(--ink);
  padding: 0;
  width: min(560px, calc(100vw - 2rem));
  box-shadow: var(--shadow-overlay);
}
dialog.sheet::backdrop { background: rgba(22, 24, 28, 0.5); }
.sheet__head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--rule);
  background: var(--paper-sunken);
}
.sheet__body { padding: var(--sp-5); }
.sheet__foot {
  padding: var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--rule);
  display: flex; gap: var(--sp-3); justify-content: flex-end; flex-wrap: wrap;
}

/* -----------------------------------------------------------------------------
   15. UTILIDADES — mínimas y con nombre funcional
   -------------------------------------------------------------------------- */
.stack     { display: flex; flex-direction: column; gap: var(--sp-4); }
.stack--sm { gap: var(--sp-2); }
.stack--lg { gap: var(--sp-8); }
.cluster   { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; }
.cluster--tight { gap: var(--sp-2); }
.spread    { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.push      { margin-left: auto; }
.split {
  display: grid;
  gap: var(--sp-6);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 1040px) {
  .split--main-aside { grid-template-columns: minmax(0, 1.7fr) minmax(280px, 1fr); }
  .split--even { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.section { margin-bottom: var(--sp-10); }
.section__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-3);
}
.section__title { font-size: 1.0625rem; font-weight: 700; letter-spacing: -0.01em; }

/* -----------------------------------------------------------------------------
   16. RESPONSIVE — el móvil tiene composición propia, no una pila del escritorio
   -------------------------------------------------------------------------- */
@media (max-width: 899px) {
  .shell { grid-template-columns: minmax(0, 1fr); }

  .rail { display: none; }

  /* Cabecera móvil: identidad del gimnasio + salida. Compacta y fija. */
  .topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    background: var(--paper-raised);
    border-bottom: 1px solid var(--rule);
    position: sticky; top: 0; z-index: 40;
  }
  .topbar__brand { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; text-decoration: none; color: var(--ink); }
  .topbar__brand img { width: 26px; height: 26px; object-fit: contain; border-radius: var(--r-media); flex: none; }
  .topbar__name { font-weight: 800; font-size: 0.9375rem; letter-spacing: -0.02em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  .content { padding: var(--sp-6) var(--sp-4) calc(var(--tap) + var(--sp-16)); }

  /* Barra inferior: destinos del rol, alcanzables con el pulgar. */
  .tabbar {
    display: flex;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    background: var(--paper-raised);
    border-top: 1px solid var(--rule);
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  .tabbar__link {
    flex: 1;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px;
    min-height: 56px;
    padding: var(--sp-2) var(--sp-1);
    color: var(--ink-3);
    text-decoration: none;
    font-size: var(--t-micro);
    font-weight: 600;
    border-top: 2px solid transparent;
    margin-top: -1px;
  }
  .tabbar__link svg { width: 21px; height: 21px; stroke-width: 1.75; }
  .tabbar__link[aria-current="page"] { color: var(--ink); border-top-color: var(--brand); }

  /* La cifra dominante crece en móvil: se lee de un vistazo, en la mano. */
  .figures { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .figure { border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
  .figure:nth-child(2n) { border-right: 0; }

  .register__head, .register__body, .row, .exercise__head { padding-left: var(--sp-4); padding-right: var(--sp-4); }
  .sets { padding-left: var(--sp-4); padding-right: var(--sp-4); }
  .exercise__note { margin-left: var(--sp-4); margin-right: var(--sp-4); }

  .page-head__actions { width: 100%; }
  .page-head__actions .btn { flex: 1; }

  /* En pantalla táctil el botón compacto recupera el área mínima: en el
     escritorio lo maneja un puntero preciso, en el mostrador un pulgar. */
  .btn--sm { min-height: var(--tap); padding-inline: var(--sp-4); }

  /* Las tablas densas se convierten en renglones legibles en pantalla estrecha. */
  .table--stack thead { display: none; }
  .table--stack tbody tr {
    display: block;
    border-bottom: 1px solid var(--rule);
    padding: var(--sp-4) 0;
  }
  .table--stack tbody tr:last-child { border-bottom: 0; }
  .table--stack tbody td {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--sp-4);
    border: 0;
    padding: var(--sp-1) var(--sp-4);
    text-align: left;
  }
  .table--stack tbody td::before {
    content: attr(data-label);
    font-family: var(--font-data);
    font-size: var(--t-micro);
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-3);
    flex: none;
  }
  .table--stack tbody td.num { text-align: right; }
  .table--stack tbody td[data-label=""]::before { content: none; }
  .table--stack .actions { justify-content: flex-end; padding-top: var(--sp-3); }
}

@media (max-width: 520px) {
  .figures { grid-template-columns: minmax(0, 1fr); }
  .figure { border-right: 0; }
  .exercise__grid { gap: var(--sp-4); }
}

/* -----------------------------------------------------------------------------
   17. MOVIMIENTO
   Solo se anima lo que explica un cambio de estado: una serie que se marca, un
   panel que se abre, un dato que se actualiza.
   -------------------------------------------------------------------------- */
@keyframes mark-in {
  from { transform: skewX(-12deg) scaleY(0.2); opacity: 0; }
  to   { transform: skewX(-12deg) scaleY(1); opacity: 1; }
}
.tally__i--done, .tally__i--brand, .tally__i--ok { animation: mark-in var(--dur-2) var(--ease) both; }

@keyframes row-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
.animate-in { animation: row-in var(--dur-2) var(--ease) both; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* -----------------------------------------------------------------------------
   18. IMPRESIÓN — el propietario imprime listados de cobro; la planilla ya lo es
   -------------------------------------------------------------------------- */
@media print {
  .rail, .tabbar, .topbar, .page-head__actions, .btn, .btn-icon { display: none !important; }
  .shell { grid-template-columns: 1fr; }
  .content { padding: 0; max-width: none; }
  body { background: #fff; color: #000; }
  .register, .figures, .table { border-color: #999; }
}
