/* ===========================================================
   Evolution AGM — Sistema de tema (claro / oscuro)
   Tokens del brand board -> variables Bootstrap + componentes.
   Fuente de verdad de los colores: docs/ai/DESIGN_SYSTEM.md
   =========================================================== */

/* ───────────────────── Tipografía autohospedada ─────────────────────
   Tres familias con un trabajo cada una:

     Space Grotesk  → títulos. Geométrica con carácter: moderna sin ser fría.
     IBM Plex Sans  → cuerpo e interfaz. Hermana de la mono, así que armonizan.
     IBM Plex Mono  → cifras. Pesos, medidas, montos, folios.

   Todas locales y nunca por CDN: la app debe verse igual sin internet y sin
   exponer la IP de cada visitante a un tercero.

   Antes el cuerpo corría con 'Helvetica Neue', Helvetica, Arial — un stack del
   sistema que se resuelve distinto en cada plataforma (Liberation Sans en
   Linux, Roboto en Android, Helvetica en iOS). La aplicación se veía distinta
   en cada dispositivo, y esa era una de las causas de que no se sintiera
   terminada. */

@font-face {
    font-family: 'Space Grotesk';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('lib/fonts/space-grotesk-500-latin.woff2') format('woff2');
}

@font-face {
    font-family: 'Space Grotesk';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('lib/fonts/space-grotesk-600-latin.woff2') format('woff2');
}

@font-face {
    font-family: 'Space Grotesk';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('lib/fonts/space-grotesk-700-latin.woff2') format('woff2');
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('lib/fonts/ibm-plex-sans-400-latin.woff2') format('woff2');
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('lib/fonts/ibm-plex-sans-500-latin.woff2') format('woff2');
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('lib/fonts/ibm-plex-sans-600-latin.woff2') format('woff2');
}

@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('lib/fonts/ibm-plex-mono-500-latin.woff2') format('woff2');
}

@font-face {
    font-family: 'IBM Plex Mono';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('lib/fonts/ibm-plex-mono-600-latin.woff2') format('woff2');
}

/* ───────────────────── Escalas del sistema ─────────────────────
   Tokens que no dependen del tema: tipografía, espaciado, radios y duraciones.
   Los de color van más abajo, separados por tema. */
:root {
    --font-titulo: 'Space Grotesk', 'IBM Plex Sans', system-ui, sans-serif;
    --font-cuerpo: 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-cifra:  'IBM Plex Mono', ui-monospace, 'Cascadia Mono', monospace;

    /* Escala tipográfica. Antes había tres tamaños efectivos (h4, normal,
       small) y por eso no existía jerarquía: el título de una pantalla y el
       texto de una fila pesaban casi igual. Los tres tamaños grandes son
       fluidos para que en un teléfono no desborden y en escritorio respiren. */
    --fs-2xs:  0.6875rem;   /* 11px — micro-etiquetas */
    --fs-xs:   0.75rem;     /* 12px */
    --fs-sm:   0.8125rem;   /* 13px */
    --fs-base: 0.9375rem;   /* 15px — cuerpo de interfaz */
    --fs-md:   1.0625rem;   /* 17px */
    --fs-lg:   clamp(1.1875rem, 1.05rem + 0.7vw, 1.375rem);
    --fs-xl:   clamp(1.4375rem, 1.2rem + 1.2vw, 1.75rem);
    --fs-2xl:  clamp(1.75rem, 1.35rem + 2vw, 2.375rem);
    --fs-cifra-lg: clamp(2rem, 1.5rem + 2.5vw, 2.75rem);

    --lh-apretado: 1.18;
    --lh-titulo:   1.25;
    --lh-cuerpo:   1.6;

    /* Rastreo. Los títulos van ligeramente cerrados —Space Grotesk lo pide— y
       las micro-etiquetas muy abiertas, que es lo que las hace leerse como
       etiqueta y no como texto pequeño. */
    --track-titulo: -0.015em;
    --track-etiqueta: 0.08em;

    /* Espaciado en múltiplos de 4. */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;
    --space-8: 2rem;
    --space-10: 2.5rem;
    --space-12: 3rem;
    --space-16: 4rem;

    --radius-sm: 0.375rem;
    --radius:    0.5rem;
    --radius-lg: 0.75rem;
    --radius-xl: 1rem;
    --radius-pill: 999px;

    --dur-rapida: .15s;
    --dur-media: .25s;
    --ease-salida: cubic-bezier(.2, .8, .3, 1);

    /* Ancho de lectura del contenido. Una fila de 1600px no se lee: el ojo
       pierde el renglón al volver. */
    --ancho-contenido: 1120px;
    --ancho-estrecho: 660px;
}

html {
    font-size: 100%;
}

html, body {
    font-family: var(--font-cuerpo);
    font-size: var(--fs-base);
    line-height: var(--lh-cuerpo);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

body {
    transition: background-color .3s ease, color .3s ease;
}

/* ───────────────────────── Tokens de marca ───────────────────────── */
/* CLARO — separa con TINTA.
   La superficie apenas se levanta del lienzo (ΔL* 3.7): papel sobre papel, que
   es de donde sale la elegancia. Lo que dibuja la estructura es la línea, y por
   eso el borde se reforzó de #D8D2C7 a #CFC6B6 (ΔL* contra el lienzo pasa de
   ~11 a ~16): antes estaba en el límite de existir. */
html[data-theme="light"] {
    --bg-base:        #F7F4EF;
    --surface:        #FFFFFF;
    --surface-alt:    #EFEAE2;
    --text:           #151312;
    --text-rgb:       21, 19, 18;
    --text-muted:     #4A453E;
    --text-disabled:  #968F84;
    --border:         #CFC6B6;
    --border-suave:   #E2DCD0;
    --sidebar:        #14120F;
    --gold:           #8A602C;
    --gold-hover:     #9F773E;
    --gold-focus:     #D6B263;
    --iron:           #6E6E6E;

    /* Sombras solo en tema claro: sobre negro no se ven, solo ensucian. */
    --sombra-1: 0 1px 2px rgba(30, 24, 14, .05), 0 1px 3px rgba(30, 24, 14, .04);
    --sombra-2: 0 4px 16px rgba(30, 24, 14, .08), 0 1px 3px rgba(30, 24, 14, .05);

    /* Peso de los títulos. En claro el texto oscuro sobre fondo claro no se
       derrama, así que aguanta el peso pleno. Ver el bloque oscuro. */
    --peso-titulo: 600;
    --peso-titulo-fuerte: 700;
    --track-titulo-tema: -0.015em;
    --success: #146C43;  --success-bg: #E8F7EE;
    --info:    #2457A6;  --info-bg:    #EAF2FF;
    --warning: #B7791F;  --warning-bg: #FFF4D6;
    --error:   #B42318;  --error-bg:   #FDECEC;
    --on-accent: #FFFFFF;   /* texto sobre acentos (oscuros en claro) */

    --bs-success-rgb: 20,108,67;
    --bs-danger-rgb:  180,35,24;
    --bs-warning-rgb: 183,121,31;
    --bs-info-rgb:    36,87,166;
    --bs-primary-rgb: 138,96,44;
    --bs-secondary-rgb: 110,110,110;
}

/* OSCURO — separa con LUZ.
   Dos cambios de fondo respecto de la versión anterior:

   1. TEMPERATURA. Los grises eran azulados (#111214, #2D3035: el azul por
      encima del rojo) mientras el tema claro es cálido. Eran dos marcas
      distintas, y el dorado —cálido— flotaba encima del oscuro como algo
      pegado. Ahora toda la escala es carbón cálido (rojo > verde > azul).

   2. ESCALERA. Antes el lienzo era #080808 y la superficie #111214: una
      diferencia de ΔL* 1.6, o sea nada, así que las tarjetas dependían por
      completo del borde. Ahora hay una escalera real —rail < lienzo <
      superficie < superficie-alt— con saltos de ΔL* ~4, que es lo que hace que
      una tarjeta flote por luz propia. Y como la elevación ya trabaja, aquí el
      borde se retira a un susurro: sobre negro, un contorno marcado se ve
      barato. */
html[data-theme="dark"] {
    --sidebar:        #090807;   /* L*  2.2 — el punto más bajo */
    --bg-base:        #151312;   /* L*  6.1 */
    --surface:        #201D1A;   /* L* 10.8 */
    --surface-alt:    #2A2622;   /* L* 15.0 */
    --text:           #F4F1EC;
    --text-rgb:       244, 241, 236;
    --text-muted:     #B5AEA2;
    --text-disabled:  #8A8378;
    --border:         #3F3931;
    --border-suave:   #2E2A25;
    --gold:           #C9A253;
    --gold-hover:     #D9B66E;
    --gold-focus:     #D9B66E;
    --iron:           #A29B90;

    /* Sin sombras: sobre negro no aportan y ensucian los bordes. */
    --sombra-1: none;
    --sombra-2: none;

    /* Compensación de peso. El texto claro sobre fondo oscuro se ve
       ópticamente MÁS GRUESO —la luz se derrama sobre el fondo—, así que el
       mismo peso que en claro se lee refinado, aquí se lee pesado y con brillo.
       Los títulos bajan un escalón y el rastreo se abre un poco. Es invisible
       cuando está bien y muy notorio cuando falta. */
    --peso-titulo: 500;
    --peso-titulo-fuerte: 600;
    --track-titulo-tema: -0.005em;
    --success: #49C78A;  --success-bg: #0E2A1C;
    --info:    #5BA8FF;  --info-bg:    #0D2238;
    --warning: #F0B84B;  --warning-bg: #33250A;
    --error:   #FF6B6B;  --error-bg:   #3A1212;
    --on-accent: #080808;   /* texto sobre acentos (claros en oscuro) */

    --bs-success-rgb: 73,199,138;
    --bs-danger-rgb:  255,107,107;
    --bs-warning-rgb: 240,184,75;
    --bs-info-rgb:    91,168,255;
    --bs-primary-rgb: 196,154,74;
    --bs-secondary-rgb: 163,163,163;
}

/* ───────────────── Tokens de superficie oscura (navbar / sidebar) ─────────────────
   La barra superior es grafito en tema claro y negra en oscuro, así que sus textos
   y bordes no pueden salir de los tokens generales: siempre van sobre fondo oscuro. */
html[data-theme="light"] {
    --sb-bg:         var(--sidebar);   /* carbón cálido #14120F */
    --sb-bg-hover:   rgba(255, 250, 240, 0.07);
    --sb-bg-active:  rgba(255, 250, 240, 0.05);
    --sb-text:       #EAE5DC;
    --sb-text-muted: #A8A196;
    --sb-accent:     var(--gold-focus);
    --sb-border:     rgba(255, 250, 240, 0.10);
    --sb-brand-icon: var(--gold-focus);
}

/* En oscuro el rail ya no es negro absoluto: es el escalón más bajo de la
   escalera (#090807, por debajo del lienzo #151312). Antes era #000000 contra
   un lienzo #080808 —ΔL* 0.6, invisible— y el rail se fundía con la página,
   mientras que en claro era una franja dramática. La app se leía como dos
   arquitecturas distintas según el tema; ahora es la misma en las dos. */
html[data-theme="dark"] {
    --sb-bg:         var(--sidebar);   /* carbón cálido #090807 */
    --sb-bg-hover:   rgba(255, 250, 240, 0.05);
    --sb-bg-active:  rgba(255, 250, 240, 0.04);
    --sb-text:       #E6E1D8;
    --sb-text-muted: #8F8879;
    --sb-accent:     var(--gold);
    --sb-border:     rgba(255, 250, 240, 0.08);
    --sb-brand-icon: var(--gold);
}

/* ───────────────────── Puente a variables Bootstrap ─────────────────────
   Esta es la pieza que hace que todo Bootstrap respete el tema sin tener que
   redefinir cada componente uno por uno. */
html[data-theme="light"],
html[data-theme="dark"] {
    --bs-body-bg:          var(--bg-base);
    --bs-body-color:       var(--text);
    /* Bootstrap pinta .text-body, .text-muted y varias utilidades con
       rgba(var(--bs-body-color-rgb), α), no con --bs-body-color. Sin esta línea
       se quedaba el valor de fábrica —un gris casi negro— y cualquier
       .text-body salía ilegible sobre el tema oscuro. Se detectó renderizando
       la cabecera de /panel: el monto pendiente no se veía. */
    --bs-body-color-rgb:   var(--text-rgb);
    --bs-emphasis-color-rgb: var(--text-rgb);
    --bs-secondary-color:  var(--text-muted);
    --bs-tertiary-color:   var(--text-disabled);
    --bs-secondary-bg:     var(--surface-alt);
    --bs-tertiary-bg:      var(--surface-alt);
    --bs-emphasis-color:   var(--text);
    --bs-border-color:     var(--border);
    --bs-primary:          var(--gold);
    --bs-success:          var(--success);
    --bs-danger:           var(--error);
    --bs-warning:          var(--warning);
    --bs-info:             var(--info);
    --bs-link-color:       var(--gold);
    --bs-link-hover-color: var(--gold-hover);
    --bs-link-color-rgb:   var(--bs-primary-rgb);
    --bs-heading-color:    var(--text);

    /* Geometría y tipografía también por el puente: sin esto, Bootstrap sigue
       imponiendo su radio (.375rem) y su tamaño (1rem) a cada componente, y el
       sistema se queda a medias. */
    --bs-body-font-family:    var(--font-cuerpo);
    --bs-body-font-size:      var(--fs-base);
    --bs-body-line-height:    var(--lh-cuerpo);
    --bs-border-radius-sm:    var(--radius-sm);
    --bs-border-radius:       var(--radius);
    --bs-border-radius-lg:    var(--radius-lg);
    --bs-border-radius-xl:    var(--radius-xl);
    --bs-border-radius-pill:  var(--radius-pill);
}

/* ═══════════════════════════════════════════════════════════
   TIPOGRAFÍA
   La jerarquía sale de aquí: tamaño, peso y rastreo, no del color.
   ═══════════════════════════════════════════════════════════ */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    font-family: var(--font-titulo);
    font-weight: var(--peso-titulo);
    letter-spacing: var(--track-titulo-tema);
    line-height: var(--lh-titulo);
    color: var(--text);
}

h1, .h1 { font-size: var(--fs-2xl); line-height: var(--lh-apretado); }
h2, .h2 { font-size: var(--fs-xl); }
h3, .h3 { font-size: var(--fs-lg); }
h4, .h4 { font-size: var(--fs-md); }
h5, .h5 { font-size: var(--fs-base); font-weight: var(--peso-titulo-fuerte); }
h6, .h6 { font-size: var(--fs-sm); font-weight: var(--peso-titulo-fuerte); }

/* Título de pantalla. Es el ancla de cada página y por eso tiene su propia
   clase: el `h1.h4` que se usaba antes lo dejaba del tamaño de un subtítulo. */
.agm-titulo-pagina {
    font-family: var(--font-titulo);
    font-size: var(--fs-xl);
    font-weight: var(--peso-titulo-fuerte);
    letter-spacing: var(--track-titulo-tema);
    line-height: var(--lh-apretado);
    margin-bottom: var(--space-1);
}

/* Título de las pantallas de cuenta. Van dentro de una tarjeta de 440px, así que
   no pueden usar el tamaño de una pantalla completa, pero tampoco el `h5` que
   traían: login y registro son lo primero que ve alguien que llega, y ahí un
   título del tamaño de una etiqueta hace que la aplicación parezca un formulario
   suelto en vez de un producto. */
.agm-titulo-cuenta {
    font-family: var(--font-titulo);
    font-size: var(--fs-lg);
    font-weight: var(--peso-titulo-fuerte);
    letter-spacing: var(--track-titulo-tema);
    line-height: var(--lh-apretado);
    text-align: center;
    margin-bottom: var(--space-1);
}

/* Micro-etiqueta. Mayúsculas, pequeña y muy abierta de rastreo: así se lee como
   etiqueta y no como texto chiquito, que es la diferencia entre una interfaz
   compuesta y una apretada. */
.agm-etiqueta {
    display: block;
    font-family: var(--font-cuerpo);
    font-size: var(--fs-2xs);
    font-weight: 600;
    letter-spacing: var(--track-etiqueta);
    text-transform: uppercase;
    color: var(--text-muted);
}

/* Cifras. Todo dato numérico —pesos, repeticiones, medidas, montos, folios,
   días restantes— va en mono con numerales tabulares: las columnas se alinean
   y un número deja de empujar el renglón al cambiar de valor. */
.agm-cifra,
.agm-dias-restantes,
.agm-monto-grande,
.agm-total-monto,
.agm-panel-cifra-valor,
.agm-medida-valor,
.agm-escala-valor {
    font-family: var(--font-cifra);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    letter-spacing: -0.01em;
}

/* Tablas y listas de datos: numerales tabulares aunque el texto sea normal. */
.table,
.agm-datos dd {
    font-variant-numeric: tabular-nums;
}

/* Sin !important, y es la parte importante de esta regla. Con él, .small ganaba
   —va después de Bootstrap en el orden de las hojas— a cualquier clase de color
   puesta en el mismo elemento, y un class="text-danger small" salía gris: así se
   perdían TODOS los mensajes de validación de los formularios, que es justo el
   texto que no se puede perder. .small es una utilidad de TAMAÑO; el color lo
   pone la clase de color, y quien no traiga ninguna cae igual aquí.

   Quitarlo no cambia ningún color existente: para .text-muted, Bootstrap ya
   resuelve al mismo valor porque --bs-secondary-color apunta a --text-muted
   más abajo en esta misma hoja. */
.text-muted,
.small,
small {
    color: var(--text-muted);
}

.small, small { font-size: var(--fs-sm); }

/* ───────────────────────── Superficies ─────────────────────────
   La tarjeta se separa distinto en cada tema, y esa asimetría es deliberada:
   en claro la dibuja el borde (la superficie casi no se levanta del lienzo),
   en oscuro la dibuja la elevación (el borde se retira a --border-suave).
   Producen la misma sensación de orden con mecanismos opuestos. */
.card {
    --bs-card-bg: var(--surface);
    --bs-card-border-color: var(--border);
    --bs-card-color: var(--text);
    --bs-card-cap-bg: var(--surface);
    --bs-card-border-radius: var(--radius-lg);
    --bs-card-inner-border-radius: calc(var(--radius-lg) - 1px);
    --bs-card-spacer-y: var(--space-5);
    --bs-card-spacer-x: var(--space-5);
    box-shadow: var(--sombra-1);
}

html[data-theme="dark"] .card {
    --bs-card-border-color: var(--border-suave);
}

.card-header,
.card-footer {
    border-color: var(--border-suave);
    padding-inline: var(--space-5);
}

.list-group {
    --bs-list-group-bg: var(--surface);
    --bs-list-group-border-color: var(--border-suave);
    --bs-list-group-color: var(--text);
    --bs-list-group-border-radius: var(--radius-lg);
}

.table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--text);
    --bs-table-border-color: var(--border-suave);
    margin-bottom: 0;
}

.table > :not(caption) > * > * {
    padding: var(--space-3) var(--space-4);
}

/* Encabezado de tabla theme-aware (reemplaza .table-light, que es color fijo).
   Va como micro-etiqueta: pequeño, abierto y en mayúsculas, para que la fila
   de encabezados no compita con los datos. */
.agm-thead th {
    background-color: transparent;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border);
    font-family: var(--font-cuerpo);
    font-size: var(--fs-2xs);
    font-weight: 600;
    letter-spacing: var(--track-etiqueta);
    text-transform: uppercase;
    white-space: nowrap;
}

.modal-content,
.dropdown-menu {
    background-color: var(--surface);
    color: var(--text);
    border-color: var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--sombra-2);
}

html[data-theme="dark"] .modal-content,
html[data-theme="dark"] .dropdown-menu {
    background-color: var(--surface-alt);
    border-color: var(--border);
}

/* El scrim tiene que aislar de verdad el contenido de arriba. */
.modal-backdrop.show { opacity: .55; }

/* ConfirmDialog se pinta a mano —no usa el JS de Bootstrap— así que lleva su
   propio velo. Antes era un rgba negro escrito en un atributo style; ahora sale
   del tema, porque sobre el crema del tema claro un negro al 50% pesa más de lo
   necesario. */
.agm-modal {
    background-color: color-mix(in srgb, var(--sidebar) 55%, transparent);
    padding: var(--space-4);
}

.agm-modal .modal-footer,
.agm-modal .modal-header {
    border-color: var(--border-suave);
}

/* En teléfono los dos botones se apilan y ocupan la línea: uno al lado del otro
   quedan estrechos, y aquí se está confirmando algo que a veces no se deshace. */
@media (max-width: 575.98px) {
    .agm-modal .modal-footer {
        flex-direction: column-reverse;
        align-items: stretch;
    }

    .agm-modal .modal-footer > .btn {
        width: 100%;
        margin: 0;
    }

    .agm-modal .modal-footer > .btn + .btn {
        margin-bottom: var(--space-2);
    }
}

/* ── Tabla adaptable ──
   /pagos tiene siete columnas: en un teléfono eso es scroll horizontal, que es
   justo lo que no debe pasar en la pantalla que más se usa. Debajo del umbral
   cada fila se convierte en una tarjeta apilada, con el nombre de la columna
   como micro-etiqueta a la izquierda; por encima vuelve a ser tabla.
   Un solo marcado para las dos formas: las etiquetas viajan en data-etiqueta.

   El umbral es 1024px y no 768px, y eso es una corrección: siete columnas —tres
   de ellas con text-nowrap— no caben en una tablet, así que entre 768 y 1024 la
   tabla desbordaba y su contenedor se llevaba el deslizamiento horizontal. Peor
   aún, con la página desbordada el riel lateral se corría con ella y parecía
   cambiar de tamaño. En tablet se ven tarjetas, que caben y se leen; la tabla
   solo aparece en escritorio, que es donde hay ancho para ella. */
@media (max-width: 1023.98px) {
    .agm-tabla-adaptable thead {
        /* clip y no display:none: display:none la saca del árbol de
           accesibilidad y las celdas se quedan sin encabezado asociado. */
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .agm-tabla-adaptable,
    .agm-tabla-adaptable tbody,
    .agm-tabla-adaptable tr,
    .agm-tabla-adaptable td {
        display: block;
        width: 100%;
    }

    .agm-tabla-adaptable tr {
        padding: var(--space-4);
        border-bottom: 1px solid var(--border-suave);
    }

    .agm-tabla-adaptable tr:last-child {
        border-bottom: 0;
    }

    .agm-tabla-adaptable td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: var(--space-4);
        padding: var(--space-1) 0;
        border: 0;
        text-align: right;
    }

    .agm-tabla-adaptable td[data-etiqueta]::before {
        content: attr(data-etiqueta);
        font-size: var(--fs-2xs);
        font-weight: 600;
        letter-spacing: var(--track-etiqueta);
        text-transform: uppercase;
        color: var(--text-muted);
        text-align: left;
        flex-shrink: 0;
    }

    /* La primera celda es el título de la tarjeta: sin etiqueta y alineada a la
       izquierda, porque el nombre del cliente es lo que identifica la fila. */
    .agm-tabla-adaptable td:first-child {
        display: block;
        text-align: left;
        padding-bottom: var(--space-2);
    }

    .agm-tabla-adaptable td:first-child::before {
        content: none;
    }

    /* La acción va al final, ancha y cómoda para el pulgar. */
    .agm-tabla-adaptable .agm-celda-accion {
        display: block;
        padding-top: var(--space-3);
    }

    .agm-tabla-adaptable .agm-celda-accion .btn {
        width: 100%;
    }

    /* Sin scroll horizontal: ya no hay nada que desbordar. */
    .agm-tabla-adaptable ~ *,
    .table-responsive:has(.agm-tabla-adaptable) {
        overflow-x: visible;
    }
}

/* ───────────────────────── Formularios ─────────────────────────
   Los campos van sobre --surface-alt y no sobre --surface: dentro de una
   tarjeta, un campo del mismo color que la tarjeta solo se distingue por el
   borde, y eso en oscuro casi no se ve. Hundido, se lee como campo en los dos
   temas sin depender del contorno. */
.form-control,
.form-select,
.form-control:disabled {
    background-color: var(--surface-alt);
    border-color: var(--border);
    color: var(--text);
    border-radius: var(--radius);
    padding: .625rem .875rem;
    /* 16px reales en móvil: por debajo de eso iOS hace zoom al enfocar el campo
       y descuadra la pantalla. */
    font-size: 1rem;
    transition: border-color var(--dur-rapida) ease, box-shadow var(--dur-rapida) ease;
}

/* form-control-sm existe para caber en tres columnas —Series, Reps y Peso— pero
   su tamaño de fuente es justo el que dispara el zoom de iOS al enfocar, y eso
   pasa en la pantalla que la clienta usa con el teléfono en la mano. En móvil
   se queda compacto de alto pero con la letra a 16px reales; de tablet para
   arriba recupera su tamaño chico. */
.form-control-sm,
.form-select-sm {
    font-size: 1rem;
    padding: .4rem .6rem;
    border-radius: var(--radius-sm);
}

@media (min-width: 768px) {
    .form-control,
    .form-select {
        font-size: var(--fs-base);
    }

    .form-control-sm,
    .form-select-sm {
        font-size: var(--fs-sm);
    }
}

.form-label {
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--text-muted);
    margin-bottom: var(--space-1);
}

.form-control::placeholder { color: var(--text-disabled); }

.form-control:focus,
.form-select:focus,
.form-check-input:focus {
    border-color: var(--gold-focus);
    box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--gold-focus) 35%, transparent);
}

.form-check-input:checked {
    background-color: var(--gold);
    border-color: var(--gold);
}

.darker-border-checkbox.form-check-input { border-color: var(--border); }

.form-floating > .form-control-plaintext::placeholder,
.form-floating > .form-control::placeholder { color: var(--text-disabled); text-align: end; }
.form-floating > .form-control-plaintext:focus::placeholder,
.form-floating > .form-control:focus::placeholder { text-align: start; }

/* ───────────────────────── Botones ─────────────────────────
   Altura mínima de 44px: es el objetivo táctil que piden tanto Apple como
   Material, y esta aplicación se usa sobre todo con el pulgar en el gimnasio.
   Con el padding anterior varios botones quedaban en 38px. */
.btn {
    --bs-btn-border-radius: var(--radius);
    --bs-btn-font-size: var(--fs-base);
    --bs-btn-font-weight: 500;
    --bs-btn-padding-y: .625rem;
    --bs-btn-padding-x: 1rem;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
    transition: background-color var(--dur-rapida) ease,
                border-color var(--dur-rapida) ease,
                color var(--dur-rapida) ease,
                transform var(--dur-rapida) var(--ease-salida);
}

/* Respuesta al toque: la retroalimentación tiene que llegar en menos de 100ms
   y no puede mover el layout, por eso es transform y no tamaño. */
.btn:active:not(:disabled) {
    transform: scale(.97);
}

.btn-sm {
    --bs-btn-font-size: var(--fs-sm);
    --bs-btn-padding-y: .375rem;
    --bs-btn-padding-x: .75rem;
    --bs-btn-border-radius: var(--radius-sm);
    min-height: 36px;
}

/* Los botones de solo icono siguen siendo cuadrados y alcanzables. */
.btn-sm > i:only-child {
    min-width: 1.1em;
}

.btn:disabled,
.btn.disabled {
    opacity: .45;
}

.btn:focus-visible {
    box-shadow: 0 0 0 .25rem color-mix(in srgb, var(--gold-focus) 40%, transparent);
}

@media (prefers-reduced-motion: reduce) {
    .btn { transition: none; }
    .btn:active:not(:disabled) { transform: none; }
}

.btn-primary {
    --bs-btn-bg: var(--gold);
    --bs-btn-border-color: var(--gold);
    --bs-btn-color: var(--on-accent);
    --bs-btn-hover-bg: var(--gold-hover);
    --bs-btn-hover-border-color: var(--gold-hover);
    --bs-btn-hover-color: var(--on-accent);
    --bs-btn-active-bg: var(--gold-hover);
    --bs-btn-active-border-color: var(--gold-hover);
    --bs-btn-active-color: var(--on-accent);
    --bs-btn-disabled-bg: var(--gold);
    --bs-btn-disabled-border-color: var(--gold);
    --bs-btn-disabled-color: var(--on-accent);
}

.btn-success {
    --bs-btn-bg: var(--success);
    --bs-btn-border-color: var(--success);
    --bs-btn-color: var(--on-accent);
    --bs-btn-hover-bg: color-mix(in srgb, var(--success) 88%, #000);
    --bs-btn-hover-border-color: color-mix(in srgb, var(--success) 88%, #000);
    --bs-btn-hover-color: var(--on-accent);
    --bs-btn-active-bg: color-mix(in srgb, var(--success) 80%, #000);
    --bs-btn-active-color: var(--on-accent);
    --bs-btn-disabled-bg: var(--success);
    --bs-btn-disabled-border-color: var(--success);
    --bs-btn-disabled-color: var(--on-accent);
}

.btn-danger {
    --bs-btn-bg: var(--error);
    --bs-btn-border-color: var(--error);
    --bs-btn-color: var(--on-accent);
    --bs-btn-hover-bg: color-mix(in srgb, var(--error) 88%, #000);
    --bs-btn-hover-border-color: color-mix(in srgb, var(--error) 88%, #000);
    --bs-btn-hover-color: var(--on-accent);
    --bs-btn-active-bg: color-mix(in srgb, var(--error) 80%, #000);
    --bs-btn-active-color: var(--on-accent);
    --bs-btn-disabled-bg: var(--error);
    --bs-btn-disabled-border-color: var(--error);
    --bs-btn-disabled-color: var(--on-accent);
}

.btn-outline-primary {
    --bs-btn-color: var(--gold);
    --bs-btn-border-color: var(--gold);
    --bs-btn-hover-bg: var(--gold);
    --bs-btn-hover-border-color: var(--gold);
    --bs-btn-hover-color: var(--on-accent);
    --bs-btn-active-bg: var(--gold);
    --bs-btn-active-border-color: var(--gold);
    --bs-btn-active-color: var(--on-accent);
}

.btn-outline-secondary {
    --bs-btn-color: var(--text-muted);
    --bs-btn-border-color: var(--border);
    --bs-btn-hover-bg: var(--surface-alt);
    --bs-btn-hover-border-color: var(--border);
    --bs-btn-hover-color: var(--text);
    --bs-btn-active-bg: var(--surface-alt);
    --bs-btn-active-color: var(--text);
}

.btn-outline-danger {
    --bs-btn-color: var(--error);
    --bs-btn-border-color: var(--error);
    --bs-btn-hover-bg: var(--error);
    --bs-btn-hover-border-color: var(--error);
    --bs-btn-hover-color: var(--on-accent);
    --bs-btn-active-bg: var(--error);
    --bs-btn-active-color: var(--on-accent);
}

/* Se usa sobre la barra superior oscura, que es oscura en ambos temas. */
.btn-outline-light {
    --bs-btn-color: var(--sb-text-muted);
    --bs-btn-border-color: var(--sb-border);
    --bs-btn-hover-bg: var(--sb-bg-hover);
    --bs-btn-hover-border-color: var(--sb-accent);
    --bs-btn-hover-color: var(--sb-text);
    --bs-btn-active-bg: var(--sb-bg-hover);
    --bs-btn-active-color: var(--sb-text);
}

/* ─────────────── Badges de estado (estilo "suave" del board) ───────────────
   Píldora, micro-etiqueta y un punto de color al frente. El punto no es adorno:
   el estado no puede quedar codificado solo por color, y así se distingue
   también en escala de grises o con daltonismo. */
.badge {
    border-radius: var(--radius-pill);
    font-family: var(--font-cuerpo);
    font-size: var(--fs-2xs);
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    padding: .3rem .6rem;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    line-height: 1.4;
}

.agm-badge-success::before,
.agm-badge-warning::before,
.agm-badge-danger::before,
.agm-badge-info::before,
.agm-badge-gold::before,
.agm-badge-neutral::before {
    content: "";
    width: .375rem;
    height: .375rem;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

.agm-badge-success { background-color: var(--success-bg); color: var(--success); }
.agm-badge-warning { background-color: var(--warning-bg); color: var(--warning); }
.agm-badge-danger  { background-color: var(--error-bg);   color: var(--error); }
.agm-badge-info    { background-color: var(--info-bg);    color: var(--info); }
.agm-badge-gold    { background-color: color-mix(in srgb, var(--gold) 18%, transparent); color: var(--gold); }
.agm-badge-neutral { background-color: var(--surface-alt); color: var(--text-muted); }

/* ─────────────── Colocación de los avisos ───────────────
   En teléfono van abajo y a todo el ancho: arriba a la derecha taparían la
   barra pegajosa —con su hamburguesa— y encima quedan lejos del pulgar. De
   tablet para arriba vuelven a la esquina superior derecha. */
.agm-toasts {
    z-index: 1080;
    bottom: 0;
    left: 0;
    right: 0;
    /* Por encima de la barra de gestos del teléfono. */
    padding-bottom: calc(var(--space-3) + env(safe-area-inset-bottom, 0px)) !important;
}

.agm-toasts .toast {
    width: 100%;
    max-width: 100%;
    border-radius: var(--radius-lg);
    box-shadow: var(--sombra-2);
}

@media (min-width: 768px) {
    .agm-toasts {
        top: 0;
        bottom: auto;
        left: auto;
        right: 0;
    }

    .agm-toasts .toast {
        width: auto;
        max-width: 24rem;
    }
}

/* ─────────────── Toasts (color de texto con contraste) ─────────────── */
.text-bg-success, .text-bg-danger, .text-bg-warning, .text-bg-info, .text-bg-secondary {
    color: var(--on-accent) !important;
}

/* ───────────────────── Alertas (estilo suave del board) ───────────────────── */
.alert-success { --bs-alert-color: var(--success); --bs-alert-bg: var(--success-bg); --bs-alert-border-color: color-mix(in srgb, var(--success) 30%, transparent); }
.alert-danger  { --bs-alert-color: var(--error);   --bs-alert-bg: var(--error-bg);   --bs-alert-border-color: color-mix(in srgb, var(--error) 30%, transparent); }
.alert-warning { --bs-alert-color: var(--warning); --bs-alert-bg: var(--warning-bg); --bs-alert-border-color: color-mix(in srgb, var(--warning) 30%, transparent); }
.alert-info    { --bs-alert-color: var(--info);    --bs-alert-bg: var(--info-bg);    --bs-alert-border-color: color-mix(in srgb, var(--info) 30%, transparent); }

/* ───────────────────────── Detalles finos ─────────────────────────
   Lo que casi nadie nota por separado y que junto es la diferencia entre una
   interfaz correcta y una terminada. */

/* Enlaces del cuerpo: subrayado fino y separado de la letra, no el subrayado
   pegado del navegador. */
a {
    text-decoration-thickness: 1px;
    text-underline-offset: .18em;
}

/* Los enlaces de las barras y las tarjetas no se subrayan solos; el resto sí,
   porque el color por sí solo no basta para señalar que algo es un enlace. */
a.btn,
a.agm-sb-link,
a.nav-link,
a.agm-panel-hero,
a.agm-checkin,
a.text-decoration-none {
    text-decoration: none;
}

/* Foco visible y consistente en todo lo que se puede alcanzar con el teclado.
   Nunca se quita el anillo: se reemplaza por uno mejor. */
:focus-visible {
    outline: 2px solid var(--gold-focus);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* Marcas de posición de carga (Bootstrap .placeholder) con el token que toca:
   por default usan currentColor y en oscuro salían casi blancas. */
.placeholder {
    background-color: var(--text-muted);
    opacity: .18;
    border-radius: var(--radius-sm);
}

/* Selección de texto en dorado tenue, en los dos temas. */
::selection {
    background-color: color-mix(in srgb, var(--gold) 28%, transparent);
    color: var(--text);
}

/* Barras de scroll acordes al tema: en oscuro, las del sistema salen claras y
   cortan la pantalla por la mitad. */
* {
    scrollbar-color: var(--border) transparent;
    scrollbar-width: thin;
}

::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background-color: var(--border);
    border-radius: var(--radius-pill);
    border: 2px solid transparent;
    background-clip: content-box;
}

::-webkit-scrollbar-thumb:hover {
    background-color: var(--text-disabled);
}

/* La barra del navegador y el color de la interfaz del sistema siguen al tema. */
html[data-theme="light"] { color-scheme: light; }
html[data-theme="dark"]  { color-scheme: dark; }

/* Las alertas también entran al sistema de radios y espaciado. */
.alert {
    border-radius: var(--radius-lg);
    padding: var(--space-4);
    font-size: var(--fs-base);
}

/* Separadores: el <hr> de Bootstrap usa currentColor con opacidad y en oscuro
   quedaba casi invisible. */
hr {
    border-top: 1px solid var(--border-suave);
    opacity: 1;
}

/* ───────────────────────── Validación ───────────────────────── */
.valid.modified:not([type=checkbox]) { outline: 1px solid var(--success); }
.invalid { outline: 1px solid var(--error); }
.validation-message { color: var(--error); }

/* Venía del andamiaje con su rojo propio, que era el único literal hex que
   quedaba en toda la hoja y no respetaba el tema. */
.blazor-error-boundary {
    background: var(--error);
    padding: var(--space-4);
    border-radius: var(--radius-lg);
    color: var(--on-accent);
}

.blazor-error-boundary::after { content: "Ha ocurrido un error."; }

/* ───────────── Cortina de carga (#agm-carga, marcado en App.razor) ─────────────
   Tapa el tramo entre el HTML servido y la aplicación ya viva. Se pinta desde el
   primer byte y la levanta el script del final del <body> poniendo data-cargado
   en el <html>.

   Todo sale de los tokens del tema, así que hereda el claro o el oscuro que el
   script anti-destello ya dejó puesto en data-theme: nunca hay un destello del
   tema contrario. Los fallbacks de var() son los valores del tema oscuro, que es
   el default, y solo se usarían si esta hoja llegara antes que sus propias
   variables. */
#agm-carga {
    position: fixed;
    inset: 0;
    z-index: 2000;   /* por encima de todo, incluido el modal de reconexión */
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-base, #151312);
}

.agm-carga-caja {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-4, 1rem);
}

.agm-carga-logo {
    width: 88px;
    height: 88px;
    object-fit: contain;
    border-radius: 12px;
}

/* El anillo: la pista en el borde del tema y solo un cuarto en oro, que es lo
   que hace legible el giro. */
.agm-carga-anillo {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 3px solid var(--border, #3F3931);
    border-top-color: var(--gold, #C9A253);
    animation: agm-carga-giro .8s linear infinite;
}

@keyframes agm-carga-giro {
    to { transform: rotate(360deg); }
}

/* La regla global de movimiento reducido del final de esta hoja apaga TODA
   animación con !important. Para lo decorativo está bien; para este anillo no:
   es un indicador de progreso, y uno congelado no dice "cargando", dice
   "colgado". Se le devuelve el giro, más lento y sin el tirón del arranque.

   Gana sobre la regla global aunque vaya antes porque entre dos !important
   decide la especificidad, y una clase pesa más que el selector universal. */
@media (prefers-reduced-motion: reduce) {
    .agm-carga-anillo {
        animation-name: agm-carga-giro !important;
        animation-duration: 1.6s !important;
        animation-iteration-count: infinite !important;
        animation-timing-function: linear !important;
    }
}

/* El texto tampoco es decorativo: acompaña al anillo y es lo que se lee. */
.agm-carga-texto {
    margin: 0;
    font-size: var(--fs-sm, 0.8125rem);
    letter-spacing: var(--track-etiqueta, 0.08em);
    text-transform: uppercase;
    color: var(--text-muted, #B5AEA2);
}

/* Levantada. Con visibility además de opacity para que no siga capturando
   clics durante el desvanecido, y con el retardo en la transición de
   visibility para que ese cambio ocurra al final y no al principio. */
html[data-cargado] #agm-carga {
    opacity: 0;
    visibility: hidden;
    transition: opacity .25s ease, visibility 0s linear .25s;
}

/* ───────────── Indicador de carga dentro de una pantalla (<Cargando />) ─────────────
   Lo mismo que la cortina de arriba, a menor escala y sin tapar nada: ocupa el
   hueco de la pantalla mientras llegan sus datos. Comparte el anillo y su
   animación a propósito — que la espera del arranque y la de una consulta se
   vean iguales es justamente el punto. */
.agm-cargando {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    padding-block: var(--space-12);
}

.agm-cargando-logo {
    width: 56px;
    height: 56px;
    object-fit: contain;
    border-radius: 10px;
    opacity: .9;
}

.agm-cargando-anillo {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 3px solid var(--border);
    border-top-color: var(--gold);
    animation: agm-carga-giro .8s linear infinite;
}

/* Misma excepción que el anillo de la cortina: la regla global de movimiento
   reducido apaga toda animación, y un indicador de progreso congelado no dice
   "cargando", dice "colgado". */
@media (prefers-reduced-motion: reduce) {
    .agm-cargando-anillo {
        animation-name: agm-carga-giro !important;
        animation-duration: 1.6s !important;
        animation-iteration-count: infinite !important;
        animation-timing-function: linear !important;
    }
}

/* ---------------------------------------------------------------------------
   Botón "Descargar recibo" mientras el servidor genera el PDF.

   El recibo se arma al vuelo con QuestPDF y no se guarda en ningún lado, así
   que el endpoint tarda: entre el clic y el archivo la pantalla se quedaba
   muda y parecía caída. js/descarga-recibo.js pide el archivo con fetch y se
   limita a poner aria-busy en el enlace; TODO el cambio visual vive aquí.

   Por qué así y no cambiando el contenido desde JS: uno de los dos botones
   está en /pagos/{id}, que es InteractiveServer, y ahí el DOM lo posee Blazor.
   Tocarle los hijos por debajo le rompe la reconciliación. Los dos rótulos ya
   vienen renderizados desde el servidor y aquí solo se conmuta cuál se ve, así
   que el JS nunca crea ni quita un nodo.

   Y el rótulo se oculta con display:none, no con visibility: así el que está
   escondido también sale del árbol de accesibilidad y el nombre accesible del
   botón pasa a ser "Generando recibo…" sin necesidad de un aria-live. */
.agm-descarga-ocupado {
    display: none;
}

[data-agm-descarga][aria-busy="true"] > .agm-descarga-ocupado {
    display: inline;
}

[data-agm-descarga][aria-busy="true"] > .agm-descarga-rotulo,
[data-agm-descarga][aria-busy="true"] > i {
    display: none;
}

/* ---------------------------------------------------------------------------
   Botones de las pantallas de cuenta mientras el servidor responde.

   Las pantallas de cuenta son SSR estático a propósito, así que sus envíos son
   POST de página completa: entre el clic en "Entrar" y la pantalla siguiente no
   se pintaba nada mientras el servidor cotejaba la contraseña. Ese silencio es
   el que el modal de "Reconectando…" venía llenando por accidente. Lo llevan los
   seis formularios POST del sistema, que son todos los de AccountLayout.

   Mismo reparto que el botón de descargar recibo: js/envio-cuenta.js solo pone
   aria-busy, y todo el cambio visual vive aquí. Los dos rótulos ya vienen
   renderizados desde el servidor, así que el script no crea ni quita nodos, y
   el que se esconde lo hace con display:none —no visibility— para que salga
   también del árbol de accesibilidad y el nombre del botón sea uno solo.

   El > svg está por el botón de Google, cuyo logotipo es un SVG en línea y no
   un icono de fuente como el resto. */
.agm-enviando-ocupado {
    display: none;
}

[data-agm-enviando][aria-busy="true"] > .agm-enviando-ocupado {
    display: inline;
}

[data-agm-enviando][aria-busy="true"] > .agm-enviando-rotulo,
[data-agm-enviando][aria-busy="true"] > svg,
[data-agm-enviando][aria-busy="true"] > i {
    display: none;
}

.agm-cargando-texto {
    margin: 0;
    font-size: var(--fs-sm);
    letter-spacing: var(--track-etiqueta);
    text-transform: uppercase;
    color: var(--text-muted);
}

/* ───────────── Aviso de error no controlado del circuito ─────────────
   El marcado de #blazor-error-ui vive siempre en MainLayout y es Blazor quien
   le pone display:block cuando algo revienta en el circuito. Nunca lo vuelve a
   ocultar: da por hecho que el CSS lo trae oculto de fábrica. Sin este
   display:none el aviso se ve en todas las pantallas desde el primer render,
   como si la aplicación estuviera caída sin estarlo. */
#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    z-index: 1080;   /* por encima de los toasts, debajo del modal de reconexión */
    padding: .7rem 1.25rem;
    background: var(--error-bg);
    color: var(--error);
    border-top: 1px solid color-mix(in srgb, var(--error) 30%, transparent);
    box-shadow: 0 -2px 8px rgb(0 0 0 / .25);
}

#blazor-error-ui .reload { color: inherit; font-weight: 600; }

#blazor-error-ui .dismiss {
    cursor: pointer;
    float: right;
    line-height: 1;
}

/* ───────────── Alternancia de logo por tema (oscuro / claro) ─────────────
   El logo no se distingue sobre un fondo de su mismo tono, así que hay dos
   archivos y se muestra el que corresponde al tema activo. */
/* Logo de marca en las pantallas de cuenta (login, registro, cerrar sesión). */
.agm-account-logo {
    width: 120px;
    height: 120px;
    object-fit: contain;
    border-radius: 12px;
}

.agm-logo-light { display: none; }
.agm-logo-dark  { display: inline-block; }

html[data-theme="light"] .agm-logo-dark  { display: none; }
html[data-theme="light"] .agm-logo-light { display: inline-block; }

html[data-theme="dark"] .agm-logo-dark  { display: inline-block; }
html[data-theme="dark"] .agm-logo-light { display: none; }

/* El contenedor .content —ancho, centrado y márgenes por breakpoint— vive en
   MainLayout.razor.css, que es donde está el elemento. Aquí solo quedaba un
   padding-top duplicado. */

h1:focus {
    outline: none;
}

/* ═══════════════════════════════════════════════════════════
   SIDEBAR — grafito en tema claro, negro en oscuro (tokens --sb-*)
   Los estilos van aquí y no en NavMenu.razor.css porque el ancho lo
   controla .sidebar, que vive en MainLayout: son dos componentes y el
   CSS con ámbito no cruza de uno a otro.
   ═══════════════════════════════════════════════════════════ */
.sidebar {
    background: var(--sb-bg, #14120F);
    transition: background .3s ease, border-color .3s ease, width .25s ease, flex .25s ease;
    display: flex;
    flex-direction: column;
    overflow-x: hidden;
}

/* En teléfono el riel es una barra superior pegajosa: su separación va abajo,
   no a la derecha. */
@media (max-width: 767.98px) {
    .sidebar {
        border-bottom: 1px solid var(--sb-border);
    }
}

@media (min-width: 768px) {
    .sidebar {
        border-right: 1px solid var(--sb-border);
    }
}

.agm-sb-brand {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: 1.1rem 19px 1rem;
    border-bottom: 1px solid var(--sb-border);
    min-height: 62px;
}

.agm-sb-logo {
    width: 34px;
    height: 34px;
    object-fit: contain;
    border-radius: 6px;
    flex-shrink: 0;
    border: 1px solid var(--sb-border);
}

.agm-sb-brand-name {
    font-family: var(--font-titulo);
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--sb-text);
    letter-spacing: -0.01em;
    white-space: nowrap;
}

.agm-sb-nav {
    flex: 1;
    padding: .5rem 0;
}

.agm-sb-link,
.agm-sb-user,
.agm-sb-theme-btn {
    display: flex;
    align-items: center;
    gap: .6rem;
    width: calc(100% - .9rem);
    margin: .08rem .45rem;
    padding: .7rem .5rem .7rem 1rem;
    border-radius: var(--radius);
    font-size: var(--fs-base);
    font-weight: 500;
    min-width: 0;
    min-height: 44px;   /* objetivo táctil: en móvil esto es el menú principal */
    transition: background var(--dur-rapida) ease, color var(--dur-rapida) ease;
}

.agm-sb-link {
    position: relative;
    color: var(--sb-text) !important;
    text-decoration: none !important;
    cursor: pointer;
}

.agm-sb-link:hover {
    background: var(--sb-bg-hover);
}

/* El activo se marca con una barra dorada fina al borde del riel, no con un
   bloque dorado de fondo. Es más contenido y más editorial, y se lee igual en
   los dos temas porque el dorado contrasta con el carbón en ambos. */
.agm-sb-link.active {
    background: var(--sb-bg-active);
    color: var(--sb-accent) !important;
    font-weight: 600;
}

.agm-sb-link.active::before {
    content: "";
    position: absolute;
    left: calc(-1 * var(--space-2));
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 1.5rem;
    border-radius: 0 3px 3px 0;
    background: var(--sb-accent);
}

.agm-sb-icon {
    font-size: 1.1rem;
    width: 1.15rem;
    text-align: center;
    flex-shrink: 0;
}

.agm-sb-divider {
    height: 1px;
    background: var(--sb-border);
    margin: .3rem .8rem;
}

.agm-sb-footer {
    flex-shrink: 0;
    padding-bottom: .6rem;
}

.agm-sb-user {
    color: var(--sb-text-muted);
    font-size: .82rem;
}

.agm-sb-user span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.agm-sb-theme-btn {
    border: none;
    background: transparent;
    color: var(--sb-text-muted);
    font-size: .85rem;
    cursor: pointer;
    text-align: left;
}

.agm-sb-theme-btn:hover {
    background: var(--sb-bg-hover);
    color: var(--sb-text);
}

/* ── Riel de solo iconos (default en escritorio) ──
   Las etiquetas se ocultan con max-width y no con display:none para que la
   transición de ancho se vea, y para que sigan existiendo para un lector de
   pantalla mientras el riel está colapsado. */
@media (min-width: 768px) {
    .agm-sb-link span,
    .agm-sb-user span,
    .agm-sb-theme-btn span,
    .agm-sb-brand-name {
        max-width: 0;
        overflow: hidden;
        opacity: 0;
        visibility: hidden;
        white-space: nowrap;
        transition: opacity .12s ease .12s, max-width .2s ease;
    }

    .agm-sb-link,
    .agm-sb-user,
    .agm-sb-theme-btn {
        gap: 0;
        padding-left: calc((72px - 1.15rem) / 2 - .45rem);
    }

    /* Expandido. La clase la pone NavMenu sobre <body>, porque el ancho lo
       controla .sidebar y desde el menú no se puede alcanzar a su contenedor. */
    body.agm-sb-open .sidebar {
        width: 250px;
        flex: 0 0 250px;
    }

    body.agm-sb-open .agm-sb-link span,
    body.agm-sb-open .agm-sb-user span,
    body.agm-sb-open .agm-sb-theme-btn span,
    body.agm-sb-open .agm-sb-brand-name {
        max-width: 170px;
        opacity: 1;
        visibility: visible;
    }

    body.agm-sb-open .agm-sb-link,
    body.agm-sb-open .agm-sb-user,
    body.agm-sb-open .agm-sb-theme-btn {
        gap: .6rem;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Pantallas de negocio
   Todo sale de los tokens de arriba: ni un literal hex aquí abajo, para que
   cualquier ajuste de paleta se haga en un solo lugar y valga para los dos temas.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ───────────── Encabezado y contenedores de lista ─────────────
   El ancho ya lo gobierna .content (MainLayout.razor.css), así que aquí no va
   ningún max-width propio: tenerlo dejaba /pagos más angosta que las demás sin
   ninguna razón. */
/* Encabezado de pantalla: título, subtítulo y —cuando la hay— la acción
   principal. Antes cada pantalla lo repetía con su propia cadena de utilidades
   de Bootstrap, así que cinco pantallas tenían cinco encabezados ligeramente
   distintos. Se llamaba .agm-pagos-header por dónde nació; no era de pagos. */
.agm-encabezado {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--space-4);
    margin-bottom: var(--space-6);
}

/* En teléfono la acción principal cae debajo del título, y ahí un botón a su
   ancho natural se ve suelto y se toca peor. Ocupa la línea completa. */
@media (max-width: 575.98px) {
    .agm-encabezado > .btn,
    .agm-encabezado > a.btn {
        width: 100%;
    }
}

.agm-pagos-lista {
    display: grid;
    gap: var(--space-4);
}

/* Formularios y detalles: una columna angosta se lee mejor que una fila ancha.
   Se centra, porque pegada a la izquierda de una pantalla grande se ve
   abandonada. */
.agm-form-estrecho {
    max-width: var(--ancho-estrecho);
    margin-inline: auto;
}

/* Los filtros hacen scroll horizontal en móvil en vez de partirse en dos
   renglones: así la fila de estados se lee de un vistazo. */
.agm-filtros {
    display: flex;
    gap: var(--space-2);
    overflow-x: auto;
    padding-bottom: var(--space-1);
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}

.agm-filtros::-webkit-scrollbar { display: none; }

.agm-filtros > * { flex-shrink: 0; }

@media (min-width: 768px) {
    .agm-filtros {
        flex-wrap: wrap;
        overflow-x: visible;
    }
}

/* ───────────── Servicio activo ───────────── */
.agm-servicio-activo {
    border-left: 3px solid var(--success);
}

.agm-dias-restantes {
    font-size: var(--fs-cifra-lg);
    font-weight: 700;
    line-height: 1;
    color: var(--gold);
}

.agm-monto-grande {
    font-size: var(--fs-xl);
    font-weight: 700;
    line-height: 1.2;
}

/* Descripción del plan en la lista de precios. Reserva dos renglones aunque
   sobre uno: las tarjetas van apiladas y del mismo ancho, así que la que
   tuviera la descripción más larga —auto-entreno— quedaba más alta que las
   otras dos y la fila se veía despareja. Reservando el alto, las tres miden
   igual sin recortar el texto de nadie.

   La altura de línea se fija aquí en vez de heredarla: el alto reservado se
   calcula con ella, y la heredada no coincidía con la real —Bootstrap conserva
   la del cuerpo aunque .small baje el tamaño de letra—, así que sobraban tres
   píxeles justo en la tarjeta que se quería emparejar. */
.agm-precio-descripcion {
    line-height: 1.5;
    min-height: 3em; /* dos renglones a esa altura de línea */
}

/* ───────────── Listas de definición (detalle) ───────────── */
.agm-datos dt {
    font-weight: 500;
    color: var(--text-muted);
    padding-bottom: .35rem;
}

.agm-datos dd {
    padding-bottom: .35rem;
    margin-bottom: 0;
}

/* ───────────── Estado vacío ───────────── */
/* Estado vacío. El icono va dentro de un disco en vez de suelto a 2.5rem: un
   icono grande y gris flotando en el centro de una tarjeta se lee como un error
   de carga, mientras que dentro de su disco se lee como una ilustración.
   Diez pantallas lo repetían con su propia cadena de utilidades. */
.agm-vacio-icono {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3.5rem;
    height: 3.5rem;
    margin-bottom: var(--space-4);
    border-radius: 50%;
    background-color: var(--surface-alt);
    color: var(--text-disabled);
    font-size: 1.5rem;
    line-height: 1;
}

/* ───────────── Selección de servicio (radios como tarjetas) ───────────── */
.agm-opcion-servicio {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}

.agm-opcion-servicio + .agm-opcion-servicio {
    margin-top: var(--space-3);
}

.agm-opcion-servicio:hover {
    border-color: var(--gold-focus);
}

.agm-opcion-activa {
    border-color: var(--gold);
    background-color: color-mix(in srgb, var(--gold) 8%, transparent);
}

.agm-opcion-servicio .form-check-label {
    flex: 1;
    cursor: pointer;
}

.agm-opciones-revision .form-check-label {
    cursor: pointer;
}

/* ───────────── Días de entrenamiento ─────────────
   Mismo lenguaje que la selección de servicio de arriba: lo elegido se dice con el dorado y el
   borde, sin introducir un color nuevo.

   Los siete van SIEMPRE en un solo renglón: una semana que se parte deja de leerse como semana. Se
   intentó al revés —envolver antes que bajar de 2.75rem de ancho— y en un teléfono de 390px el
   resultado era seis chicos arriba y el domingo solo abajo, estirado a lo ancho de la fila. Lo que
   se cede es ancho, no alto: los 2.75rem de PULIDO_UX se conservan en min-height, que es la medida
   que importa cuando el objetivo se toca con el pulgar. */
.agm-dias-selector {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--space-1);
}

.agm-dia-chip {
    display: flex;

    /* Base 0 y min-width 0: reparten el renglón en siete partes iguales y pueden encogerse por
       debajo de su contenido. Con una base de 2.75rem el séptimo no cabía y se iba abajo. */
    flex: 1 1 0;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.15rem;
    min-width: 0;
    min-height: 2.75rem;
    padding: var(--space-2) var(--space-1);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background-color: var(--surface);
    color: var(--text-muted);
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}

.agm-dia-chip:hover:not(:disabled) {
    border-color: var(--gold-focus);
}

.agm-dia-chip-activo {
    border-color: var(--gold);
    background-color: color-mix(in srgb, var(--gold) 12%, transparent);
    color: var(--text);
}

.agm-dia-chip:disabled {
    cursor: default;
    opacity: .55;
}

/* La palomita del día elegido. Ocupa su hueco siempre, encendida o no, para que marcar un día no
   mueva la fila entera. */
.agm-dia-chip-marca {
    font-size: .7rem;
    line-height: 1;
}

.agm-dia-chip:not(.agm-dia-chip-activo) .agm-dia-chip-marca {
    visibility: hidden;
}

/* En el armador de rutinas: el día que el cliente pidió al contratar. Es una nota, no una regla —
   se puede prescribir en cualquier otro. */
.agm-dia-pedido {
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--gold);
}

/* ───────────── Total a pagar ───────────── */
.agm-total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: var(--space-4);
    border-radius: var(--radius-lg);
    background-color: var(--surface-alt);
}

.agm-total-monto {
    font-size: var(--fs-xl);
    font-weight: 600;
    color: var(--gold);
}

/* ───────────── Archivo seleccionado ───────────── */
.agm-archivo {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius);
    background-color: var(--surface-alt);
    font-size: var(--fs-sm);
    overflow: hidden;
}

/* ───────────── Comprobante y bloque de revisión ───────────── */
.agm-comprobante-vista {
    display: block;
    max-width: 100%;
    max-height: 420px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    object-fit: contain;
}

.agm-card-revision {
    border-color: var(--warning);
}

/* ───────────── Autocomplete remoto ─────────────
   La lista va en position:absolute sobre un contenedor relativo: dentro del flujo empujaría
   el formulario hacia abajo cada vez que alguien escribe. */
.agm-autocomplete {
    position: relative;
}

.agm-autocomplete-lista {
    position: absolute;
    top: calc(100% + .25rem);
    left: 0;
    right: 0;
    z-index: 1055;
    max-height: 18rem;
    overflow-y: auto;
    background-color: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
}

.agm-autocomplete-lista .list-group-item {
    background-color: transparent;
    border-color: var(--border);
    color: var(--text);
    text-align: left;
}

.agm-autocomplete-lista .list-group-item-action:hover {
    background-color: var(--surface-alt);
}

/* ───────────── Armador de semana ───────────── */
.agm-dia {
    border: 1px solid var(--border-suave);
    border-radius: var(--radius-lg);
    margin-bottom: var(--space-3);
    overflow: hidden;
}

.agm-dia-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background-color: var(--surface-alt);
}

.agm-dia-descanso .agm-dia-cabecera {
    opacity: .7;
}

.agm-dia-cuerpo {
    padding: var(--space-4);
}

.agm-ejercicio {
    border: 1px solid var(--border-suave);
    border-radius: var(--radius);
    padding: var(--space-4);
    background-color: var(--surface);
}

.agm-ejercicio + .agm-ejercicio {
    margin-top: var(--space-3);
}

.agm-ejercicio-cabecera {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

/* El número de orden va en la fuente de cifras: es un dato, no una etiqueta. Ancho mínimo y no
   fijo: en una bi serie lleva letra ("3A") y una bolita redonda la aplastaba. */
.agm-ejercicio-orden {
    flex: none;
    min-width: 1.75rem;
    height: 1.75rem;
    padding: 0 .4rem;
    display: grid;
    place-items: center;
    border-radius: 1rem;
    background-color: var(--surface-alt);
    color: var(--text-muted);
    font-family: var(--font-cifra);
    font-size: var(--fs-xs);
    font-weight: 600;
}

/* El interruptor de bi serie va en la cabecera del ejercicio, entre el autocompletado y los
   botones; sin el margen inferior de Bootstrap se alinea con ellos. */
.agm-biserie-switch {
    flex: none;
    white-space: nowrap;
}

/* La segunda mitad de una bi serie: anidada dentro de la tarjeta del principal, con una regla a la
   izquierda para que se lea como "dentro de" y no como el ejercicio siguiente. */
.agm-ejercicio-secundario {
    margin-top: var(--space-3);
    padding: var(--space-3);
    padding-left: var(--space-4);
    border-left: 3px solid var(--border-suave);
    border-radius: 0 var(--radius) var(--radius) 0;
    background-color: var(--surface-alt);
}

.agm-ejercicio-secundario .agm-ejercicio-cabecera {
    margin-bottom: var(--space-2);
}

/* ───────────── Sesiones del cliente ───────────── */

/* Lo que toca hoy, arriba de la lista. Realce de borde como .agm-servicio-activo, en dorado:
   no es una alerta, es el punto de entrada del día. */
/* La tarjeta de "lo que toca hoy". Es lo primero que la clienta ve al abrir la
   aplicación y lo que decide si entrena, así que lleva el acento dorado. */
.agm-hoy {
    border-color: var(--gold);
}

.agm-hoy-icono {
    font-size: 1.75rem;
    color: var(--gold);
    opacity: .55;
}

/* Acción principal dentro de una tarjeta: en teléfono ocupa la línea completa.
   A su ancho natural queda suelta bajo el texto y se toca peor con el pulgar. */
@media (max-width: 575.98px) {
    .agm-cta-movil {
        width: 100%;
    }
}

.agm-semana {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    margin-bottom: var(--space-4);
    overflow: hidden;
    background-color: var(--surface);
    box-shadow: var(--sombra-1);
}

html[data-theme="dark"] .agm-semana {
    border-color: var(--border-suave);
}

/* 48px de alto: la cabecera de la semana es lo que la clienta toca para
   desplegar, y es de lo primero que ve al entrar. */
.agm-semana-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    min-height: 48px;
    background-color: var(--surface-alt);
}

/* La cabecera es un <summary>: el plegado va con HTML nativo para no volver interactiva una
   pantalla que es SSR estático a propósito. Se le quita el triángulo del navegador —que no
   respeta la tipografía ni el color del tema— y se usa el chevron de Bootstrap Icons, que ya
   es el que marca "esto se abre" en el resto de la aplicación. */
summary.agm-semana-cabecera {
    cursor: pointer;
    list-style: none;
}

summary.agm-semana-cabecera::-webkit-details-marker {
    display: none;
}

summary.agm-semana-cabecera:focus-visible {
    outline: 2px solid var(--gold-focus);
    outline-offset: -2px;
}

.agm-semana-chevron {
    color: var(--text-muted);
    transition: transform .18s ease;
}

details[open] > summary .agm-semana-chevron {
    transform: rotate(90deg);
}

/* Las semanas futuras se ven, pero no se abren: el cliente sabe a qué se comprometió sin poder
   adelantarse. Atenuadas y no como ausentes, que parecería contenido faltante. */
.agm-semana-futura {
    opacity: .55;
}

.agm-sesion {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-3) var(--space-4);
    min-height: 56px;
    border: 0;
    border-top: 1px solid var(--border-suave);
    background-color: transparent;
    color: var(--text);
    text-align: left;
}

.agm-sesion:not(:disabled):hover {
    background-color: var(--surface-alt);
}

.agm-sesion:disabled {
    color: var(--text-disabled);
}

.agm-sesion-autocompletada {
    color: var(--text-muted);
}

/* ───────────── Ejercicio dentro de una sesión ───────────── */
.agm-registro {
    border: 1px solid var(--border-suave);
    border-radius: var(--radius-lg);
    padding: var(--space-4);
    background-color: var(--surface);
}

.agm-registro + .agm-registro {
    margin-top: var(--space-3);
}

.agm-registro-hecho {
    border-color: var(--success);
}

/* El ejercicio que se está haciendo ahora. Es el único con campos abiertos mientras dure, así que
   se marca con el dorado —el acento del sistema— para que la vista aterrice ahí al volver el
   teléfono a la mano. */
.agm-registro-activo {
    border-color: var(--gold);
    box-shadow: 0 0 0 1px var(--gold);
}

/* Los demás, mientras uno está en curso. Atenuados y no ocultos: la persona tiene que seguir
   viendo qué le falta del día y en qué orden viene. */
.agm-registro-bloqueado {
    opacity: .6;
}

/* Una bi serie: la tarjeta es el bloque y dentro van sus dos mitades, separadas por una regla y
   no por otra tarjeta, para que se lean como partes de lo mismo. */
.agm-bloque-cabecera {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.agm-bloque-titulo {
    font-weight: 600;
}

.agm-registro-miembro + .agm-registro-miembro {
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px dashed var(--border-suave);
}

/* "3A", "3B": la etiqueta del bloque y de sus mitades, en la fuente de cifras como el número de
   orden del armador. */
.agm-miembro-etiqueta {
    display: inline-grid;
    place-items: center;
    min-width: 1.75rem;
    height: 1.75rem;
    padding: 0 .4rem;
    margin-right: var(--space-2);
    border-radius: 1rem;
    background-color: var(--surface-alt);
    color: var(--text-muted);
    font-family: var(--font-cifra);
    font-size: var(--fs-xs);
    font-weight: 600;
    vertical-align: middle;
}

.agm-ejercicio-bloqueado {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1);
    font-size: var(--fs-sm);
    color: var(--text-muted);
}

.agm-sugerido {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-4);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius);
    background-color: var(--surface-alt);
    font-size: var(--fs-sm);
}

/* ───────────── Captura serie por serie ─────────────
   Un renglón por serie: el número a la izquierda, los campos en medio y el
   botón de guardar a la derecha, siempre en la misma posición para que el
   pulgar lo encuentre sin mirar. En teléfono los campos se reparten en tres
   columnas iguales; de tablet para arriba caben con más aire. */
.agm-unidad-ejercicio {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.agm-serie {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-2);
    padding: var(--space-2) 0;
    border-top: 1px solid var(--border-suave);
}

/* El "Serie N" del renglón. Ocupa la fila entera para no robarle ancho a los tres
   campos, que en un teléfono ya van justos. */
.agm-serie-titulo {
    flex: 0 0 100%;
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--text-muted);
}

.agm-serie-hecha-marca {
    margin-left: var(--space-1);
    font-weight: 500;
    color: var(--success);
}

/* La serie que todavía no toca: se ve que existe y cuántas faltan, pero sin campos
   ni botón. Atenuada y no oculta — esconderla haría parecer que el ejercicio tiene
   menos series de las que tiene. */
.agm-serie-bloqueada {
    opacity: .55;
}

.agm-serie-espera {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
    flex: 1;
    min-width: 0;
    font-size: var(--fs-sm);
}

.agm-serie-numero {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 1.75rem;
    height: 1.75rem;
    margin-bottom: .35rem;
    border-radius: 50%;
    background-color: var(--surface-alt);
    color: var(--text-muted);
    font-size: var(--fs-xs);
    font-weight: 600;
}

/* La serie ya registrada se marca en su número y no con un fondo entero: el
   renglón sigue siendo editable, y pintarlo de verde diría que está cerrado. */
.agm-serie-hecha .agm-serie-numero {
    background-color: var(--success);
    color: var(--surface);
}

.agm-serie-campos {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-2);
    flex: 1;
    min-width: 0;
}

/* 44px de alto: es el objetivo táctil del sistema, y este botón se pulsa con
   las manos cansadas entre serie y serie. */
.agm-serie-boton {
    flex-shrink: 0;
    min-width: 2.75rem;
    min-height: 2.75rem;
}

/* El selector de unidad dentro del grupo de peso: lo justo para "kg" o "lb",
   sin robarle ancho al número. */
.agm-select-unidad {
    max-width: 5rem;
    flex: 0 0 auto;
}

/* El "última vez": referencia discreta, nunca al nivel de la prescripción. Las
   series se separan con un punto medio para que se lean como una progresión
   —"40 × 12 · 40 × 10 · 37.5 × 8"— y no como una lista de datos sueltos. */
.agm-peso-anterior {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-2);
    align-items: baseline;
    margin-bottom: var(--space-2);
    font-size: var(--fs-sm);
}

.agm-peso-anterior-serie + .agm-peso-anterior-serie::before {
    content: "·";
    margin-right: var(--space-2);
    color: var(--text-muted);
}

/* ── Barra del descanso entre series ──
   La crea y la destruye SesionDetalle.razor.js, colgada de <body> y fuera del
   DOM de Blazor. Los colores salen de los tokens --sb-*, los mismos de las
   superficies oscuras del riel: la barra tiene que leerse igual en tema claro y
   en oscuro, y sobre grafito los tokens de texto normales serían ilegibles. */
.agm-descanso {
    position: fixed;
    left: 50%;
    bottom: var(--space-4);
    transform: translateX(-50%);
    z-index: 1080;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    max-width: calc(100vw - var(--space-6));
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--sb-border);
    border-radius: var(--radius-lg);
    background: var(--sb-bg);
    color: var(--sb-text);
    box-shadow: var(--sombra-2);
}

.agm-descanso-etiqueta {
    font-size: var(--fs-2xs);
    letter-spacing: var(--track-etiqueta);
    text-transform: uppercase;
    color: var(--sb-text-muted);
}

.agm-descanso-cuenta {
    font-family: var(--font-titulo);
    font-size: var(--fs-lg);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    min-width: 3.5rem;
    text-align: center;
}

/* Al llegar a cero cambia el color, no el tamaño: en el gimnasio la barra se
   mira de reojo, y un salto de altura mueve todo lo que tiene al lado. */
.agm-descanso-listo .agm-descanso-cuenta {
    color: var(--sb-accent);
}

/* Sesión concluida o pendiente: las series se leen, no se escriben. */
.agm-series-lectura {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: var(--fs-sm);
}

.agm-series-lectura li {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-1) 0;
    border-top: 1px solid var(--border-suave);
}

.agm-series-lectura li:first-child {
    border-top: 0;
}

/* ───────────── Mediciones ───────────── */
.agm-medidas {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
    gap: var(--space-3);
}

.agm-medida {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-3);
    border-radius: var(--radius);
    background-color: var(--surface-alt);
}

.agm-medida-etiqueta {
    font-size: var(--fs-2xs);
    font-weight: 600;
    letter-spacing: var(--track-etiqueta);
    text-transform: uppercase;
    color: var(--text-muted);
}

.agm-medida-valor {
    font-size: var(--fs-md);
    font-weight: 600;
}

.agm-medida-valor small {
    font-size: var(--fs-xs);
    font-weight: 400;
    color: var(--text-muted);
}

/* Sin verde ni rojo a propósito: el sistema no sabe si subir o bajar es lo que la persona busca. */
.agm-medida-delta {
    font-size: var(--fs-xs);
    color: var(--text-muted);
}

/* ───────────── Check-ins ─────────────
   Los deslizadores de 1 a 10 se fueron con las escalas: los tres del check-in
   diario y los dos del semanal son opciones cerradas, y reutilizan el mismo
   control que la selección de servicio (.agm-opcion-servicio). */

/* Fila de lista dentro de una tarjeta. Se usa en clientes, check-ins y demás
   listados. El separador va en --border-suave: dentro de una tarjeta, una línea
   al mismo peso que el contorno la trocea en cajitas. */
.agm-checkin {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-top: 1px solid var(--border-suave);
    transition: background-color var(--dur-rapida) ease;
}

.agm-checkin:first-of-type {
    border-top: 0;
}

.agm-checkin:hover {
    background-color: color-mix(in srgb, var(--text) 3%, transparent);
}

/* El nombre de cada fila es un enlace, pero subrayarlo en una lista donde TODAS
   las filas lo son convierte la tarjeta en un bloque de texto rayado. Se apoya
   en el color y recupera el subrayado al pasar por encima o al enfocar, que es
   cuando de verdad hace falta saber que se puede pulsar. */
.agm-checkin a {
    text-decoration: none;
    font-weight: 500;
}

.agm-checkin a:hover,
.agm-checkin a:focus-visible {
    text-decoration: underline;
}

/* Con flex, una celda de dos datos —"Solo rutina" y "2 semanas"— se repartía en
   tres columnas junto a su etiqueta y rompía el eje que forman las celdas de un
   solo dato. Con grid de dos columnas, la etiqueta ocupa la primera y TODO el
   contenido se apila en la segunda, tenga una pieza o cinco. */
@media (max-width: 767.98px) {
    .agm-tabla-adaptable td[data-etiqueta] {
        display: grid;
        grid-template-columns: max-content 1fr;
        column-gap: var(--space-4);
        row-gap: 0;
        align-items: baseline;
        /* justify-items al final: sin esto un hijo se estira a lo ancho de su
           columna, y un badge de estado ocupaba la fila entera como si fuera
           una barra. */
        justify-items: end;
        text-align: right;
    }

    .agm-tabla-adaptable td[data-etiqueta]::before {
        grid-column: 1;
        justify-self: start;
    }

    .agm-tabla-adaptable td[data-etiqueta] > * {
        grid-column: 2;
    }

    /* La primera celda es el título de la tarjeta y va a la izquierda. Esta
       regla repite la de arriba a propósito: la primera celda también lleva
       data-etiqueta, así que sin volver a declararla aquí —después— el grid le
       ganaría y el nombre del cliente se iría a la derecha. */
    .agm-tabla-adaptable td:first-child {
        display: block;
        text-align: left;
        padding-bottom: var(--space-2);
    }
}

@media (min-width: 768px) {
    .agm-checkin {
        padding-inline: var(--space-5);
    }
}

/* ═══════════════════════════════════════════════════════════
   LOS DOS MOMENTOS
   El resto del sistema es tranquilo a propósito. La energía se concentra aquí
   y en ningún otro lado: concluir una sesión —lo único que la clienta hace de
   principio a fin— y la cifra que abre el panel de la dueña.
   ═══════════════════════════════════════════════════════════ */

/* ── Cierre de sesión: el avance se ve ── */
.agm-cierre {
    border-color: var(--gold);
}

.agm-cierre-avance {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

.agm-cierre-conteo {
    font-size: var(--fs-xl);
    font-weight: 600;
    line-height: 1;
    color: var(--text);
}

.agm-cierre-total {
    font-size: var(--fs-md);
    color: var(--text-muted);
}

.agm-barra {
    height: .5rem;
    border-radius: var(--radius-pill);
    background-color: var(--surface-alt);
    overflow: hidden;
}

.agm-barra-relleno {
    height: 100%;
    border-radius: var(--radius-pill);
    background: linear-gradient(90deg, var(--gold), var(--gold-focus));
    /* Solo transform/width sobre un elemento aislado: no reflota el layout. */
    transition: width var(--dur-media) var(--ease-salida);
}

/* ── Sesión concluida: se celebra, no se avisa ── */
.agm-logro {
    border-color: var(--success);
    background-color: var(--success-bg);
}

.agm-logro-marca {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3.5rem;
    height: 3.5rem;
    margin-bottom: var(--space-3);
    border-radius: 50%;
    background-color: var(--success);
    color: var(--surface);
    font-size: 1.75rem;
    animation: agm-logro-entra .4s var(--ease-salida) both;
}

html[data-theme="dark"] .agm-logro-marca {
    color: var(--bg-base);
}

@keyframes agm-logro-entra {
    from { opacity: 0; transform: scale(.6); }
    to   { opacity: 1; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
    .agm-logro-marca { animation: none; }
    .agm-barra-relleno { transition: none; }
}

/* ── La cifra que abre el panel ──
   Primer punto de lectura de la pantalla: la dueña tiene que saber si hay
   trabajo pendiente antes de leer un solo título. */
.agm-panel-hero {
    display: flex;
    align-items: center;
    gap: var(--space-5);
    padding: var(--space-5);
    margin-bottom: var(--space-6);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background-color: var(--surface);
    box-shadow: var(--sombra-1);
}

.agm-panel-hero-activo {
    border-color: var(--gold);
}

.agm-panel-hero-valor {
    font-family: var(--font-cifra);
    font-variant-numeric: tabular-nums;
    font-size: var(--fs-cifra-lg);
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--text);
}

.agm-panel-hero-activo .agm-panel-hero-valor {
    color: var(--gold);
}

.agm-panel-hero-texto {
    min-width: 0;
    color: var(--text);
}

.agm-panel-hero:hover {
    border-color: var(--gold);
    background-color: var(--surface-alt);
}

/* En teléfono la cifra manda: se apila arriba y el texto debajo. */
@media (max-width: 480px) {
    .agm-panel-hero {
        flex-wrap: wrap;
        gap: var(--space-3);
    }

    .agm-panel-hero .bi-chevron-right {
        display: none;
    }
}

/* ───────────── Contraseña temporal ─────────────
   Grande y monoespaciada: se dicta o se copia a mano, así que la legibilidad importa más que
   la elegancia. */
.agm-contrasena-temporal {
    display: inline-block;
    margin-top: .35rem;
    padding: .35rem .6rem;
    border-radius: var(--radius);
    background-color: var(--surface-alt);
    color: var(--text);
    font-size: var(--fs-md);
    letter-spacing: .08em;
    user-select: all;
}


/* ============================================================
   Avatar de persona (AvatarPersona)
   ------------------------------------------------------------
   Un solo tamaño de estilo para foto e iniciales: el lado y la
   tipografía los pone el componente por atributo, porque varian
   entre el menu (32) y el expediente (96) y no vale la pena una
   clase por medida.
   ============================================================ */
.agm-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    border-radius: 50%;
    object-fit: cover;              /* la foto llena el circulo sin deformarse */
    background-color: var(--surface-alt);
    border: 1px solid var(--border);
    overflow: hidden;
}

.agm-avatar-iniciales {
    font-weight: 600;
    line-height: 1;
    letter-spacing: .02em;
    color: var(--text-muted);
    user-select: none;
}

/* Sobre el sidebar, que es oscuro en los dos temas: --border y --text-muted
   serian ilegibles ahi en tema claro. */
.agm-sb-user .agm-avatar {
    background-color: var(--sb-surface-alt, rgba(255, 255, 255, .08));
    border-color: var(--sb-border, rgba(255, 255, 255, .16));
}

.agm-sb-user .agm-avatar-iniciales {
    color: var(--sb-text, #F7F7F5);
}

/* ---------------------------------------------------------------------------
   Panel de Dueño y SuperAdmin (/panel)

   Las clases agm-panel-inicio y agm-panel-eyebrow que usaba el panel anterior nunca existieron en
   esta hoja: el marcado las pedía y no pintaban nada. Se reemplazan por lo de abajo.
   --------------------------------------------------------------------------- */

/* Dos columnas en teléfono —una sola deja tarjetas larguísimas y obliga a
   scrollear para ver seis cifras— y luego se acomodan solas. */
.agm-panel-cifras {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-3);
}

@media (min-width: 560px) {
    .agm-panel-cifras {
        grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
    }
}

.agm-panel-cifra {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-4);
    border: 1px solid var(--border-suave);
    border-radius: var(--radius-lg);
    background-color: var(--surface);
    box-shadow: var(--sombra-1);
}

/* Marca lo que pide una acción hoy. Es un realce de borde, no un color de alarma: un cero en estos
   mismos campos es buena noticia y se queda neutro. */
.agm-panel-cifra-activa {
    border-color: var(--gold);
    background-color: var(--surface-alt);
}

.agm-panel-cifra-icono {
    font-size: var(--fs-md);
    color: var(--text-disabled);
    margin-bottom: var(--space-1);
}

.agm-panel-cifra-activa .agm-panel-cifra-icono {
    color: var(--gold);
}

.agm-panel-cifra-valor {
    font-size: var(--fs-xl);
    font-weight: 600;
    line-height: 1.1;
}

/* La etiqueta va como micro-etiqueta, igual que en el resto del sistema: es lo
   que la distingue de un texto pequeno cualquiera. */
.agm-panel-cifra-etiqueta {
    font-size: var(--fs-2xs);
    font-weight: 600;
    letter-spacing: var(--track-etiqueta);
    text-transform: uppercase;
    color: var(--text-muted);
}

.agm-panel-cifra-detalle {
    font-family: var(--font-cifra);
    font-variant-numeric: tabular-nums;
    font-size: var(--fs-xs);
    color: var(--text-muted);
}

/* Una cifra que lleva a su lista ya filtrada. El realce al pasar por encima es el mismo del héroe
   —borde dorado y superficie alterna—, para que las dos formas de "esto se pulsa" se lean igual. */
a.agm-panel-cifra {
    position: relative;
    color: inherit;
    text-decoration: none;
    transition: border-color var(--dur-rapida) var(--ease-salida),
                background-color var(--dur-rapida) var(--ease-salida);
}

a.agm-panel-cifra:hover,
a.agm-panel-cifra:focus-visible {
    border-color: var(--gold);
    background-color: var(--surface-alt);
}

/* Arriba a la derecha y en posición absoluta: dentro del flujo empujaría la cifra o la etiqueta, y
   estas tarjetas van de dos en dos en un teléfono. */
.agm-panel-cifra-chevron {
    position: absolute;
    top: var(--space-4);
    right: var(--space-4);
    font-size: var(--fs-xs);
    color: var(--text-disabled);
}

a.agm-panel-cifra:hover .agm-panel-cifra-chevron {
    color: var(--gold);
}

/* ───────────── Movimiento reducido ─────────────
   Quien lo pide en su sistema operativo suele hacerlo por vértigo o mareo con el movimiento en
   pantalla, no por gusto. Esta aplicación anima el cambio de tema, el ancho del sidebar, el
   chevron de las semanas y el pulso de los esqueletos de carga.

   Va al final de la hoja y con !important a propósito: tiene que ganarle a cualquier transición
   declarada arriba, a las de Bootstrap y a las de los .razor.css con ámbito. No se ponen en 0 sino
   en 0.01ms porque un 0 impide que se dispare `transitionend`, y hay código que se cuelga
   esperándolo. Es la receta estándar. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
}

/* Tercera excepción de la misma familia que las dos de arriba (el anillo de la cortina y el de
   <Cargando />), y por el mismo motivo: la regla global de aquí encima apaga TODA animación, y eso
   incluye los spinners de Bootstrap que van dentro de un botón. Un indicador de progreso congelado
   no dice "trabajando", dice "colgado" — que es justo lo que el botón está ahí para desmentir.

   No es teórico: se detectó con las animaciones de Windows desactivadas (MinAnimate = 0), que es
   como Chrome resuelve prefers-reduced-motion en Windows. Con eso, TODOS los spinners de botón de
   la aplicación se veían como un aro estático.

   Gana sobre la regla global aunque vaya después porque entre dos !important decide la
   especificidad, y una clase pesa más que el selector universal.

   Solo se devuelven las dos propiedades que la regla global pisa —duración e iteraciones—; el
   nombre y la curva de la animación no los toca nadie, así que siguen siendo los de Bootstrap. Y
   1.5s en vez de .75s es la velocidad reducida que el propio Bootstrap declara para este caso. */
@media (prefers-reduced-motion: reduce) {
    .spinner-border,
    .spinner-grow {
        animation-duration: 1.5s !important;
        animation-iteration-count: infinite !important;
    }
}

/* Controles de página de las listas (Paginador.razor). */
.agm-paginador {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: var(--space-5);
    gap: var(--space-4);
    margin-top: 1rem;
}

.agm-paginador-estado {
    font-size: var(--fs-sm);
    color: var(--text);
}

/* ═════════════ Historial de entrenamiento del cliente (personal) ═════════════
   Tres <details> anidados —plan, semana, día—, así que lo único que hace falta aquí es que cada
   nivel se distinga del de arriba sin encerrarse en otra caja. Los dos primeros reutilizan
   .agm-semana y el día reutiliza .agm-sesion; esto solo ajusta el anidamiento — la separación entre
   ejercicios, por ejemplo, ya la da .agm-registro + .agm-registro y no hace falta repetirla. */
.agm-historial-cuerpo {
    padding: var(--space-3) var(--space-4) var(--space-2);
}

/* La semana dentro del plan: sin sombra propia, que a dos niveles de profundidad se lee como
   suciedad, y sin el margen de una tarjeta suelta. */
.agm-historial-semana {
    box-shadow: none;
    margin-bottom: var(--space-3);
}

.agm-historial-semana:last-child {
    margin-bottom: 0;
}

/* El día es un <summary> que reutiliza .agm-sesion, así que necesita lo mismo que la cabecera de
   la semana: fuera el triángulo del navegador, que ni respeta el tema ni casa con el chevron.

   Acotado a .agm-historial-dia y no escrito como summary.agm-sesion a secas: .agm-sesion es la
   fila de sesión de media aplicación, y hoy solo es un <summary> aquí. Con el selector suelto, el
   primero que la use dentro de un <details> en cualquier otra pantalla se lleva estas tres reglas
   sin haberlas pedido. */
.agm-historial-dia > summary {
    cursor: pointer;
    list-style: none;
}

.agm-historial-dia > summary::-webkit-details-marker {
    display: none;
}

.agm-historial-dia > summary:focus-visible {
    outline: 2px solid var(--gold-focus);
    outline-offset: -2px;
}

/* Un día sin registrar no se abre: se atenúa, pero sigue legible. Es información —las semanas que
   no entrenó son las que explican por qué dejó de venir—, no contenido faltante. */
.agm-historial-dia-bloqueado {
    color: var(--text-muted);
}

.agm-historial-series {
    padding: var(--space-3) var(--space-4) var(--space-4);
    background-color: var(--surface-alt);
    border-top: 1px solid var(--border-suave);
}

/* Las tres cifras se comparan entre series de un mismo ejercicio, así que la columna manda sobre
   la fila: encabezados discretos y números que no bailan de ancho al cambiar de renglón. */
.agm-historial-tabla th {
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--text-muted);
    white-space: nowrap;
}

.agm-historial-tabla td {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
