/* ==========================================================================
   NovuxTracker — Sistema de diseño
   Identidad visual: app de entrenamiento de gimnasio.

   Tema CLARO con acento rojo Novux (#e10600), tomado de la identidad de marca.
   La decisión de fondo claro es deliberada: el rojo saturado sobre negro vibra
   y fatiga la vista, justo lo contrario de lo que necesita alguien que apenas
   empieza en el gimnasio. Sobre un fondo claro el mismo rojo resalta MÁS
   usándolo MENOS, y la app se siente amable en vez de intimidante.

   Regla de uso del acento: el rojo se reserva para acciones primarias, foco,
   estado activo y el dato que de verdad importa (el número de progreso). Nunca
   para rellenar superficies grandes.

   Construido sobre Bootstrap 5 (solo capa visual).
   ========================================================================== */

/* ===== Tipografía display: Saira Condensed (self-hosted) ===== */
@font-face {
    font-family: "Saira Condensed";
    src: url("../fonts/saira-condensed-v12-latin-600.woff2") format("woff2");
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Saira Condensed";
    src: url("../fonts/saira-condensed-v12-latin-700.woff2") format("woff2");
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

/* ===== Tipografía de cuerpo: Manrope (self-hosted) ===== */
@font-face {
    font-family: "Manrope";
    src: url("../fonts/manrope-v20-latin-regular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Manrope";
    src: url("../fonts/manrope-v20-latin-500.woff2") format("woff2");
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Manrope";
    src: url("../fonts/manrope-v20-latin-600.woff2") format("woff2");
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Manrope";
    src: url("../fonts/manrope-v20-latin-700.woff2") format("woff2");
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}


:root {
    /* ----- Paleta: superficies -----
       Blanco hueso en vez de blanco puro: el blanco #fff a pantalla completa
       deslumbra y hace que el texto negro "vibre". Un hueso cálido baja la
       fatiga visual sin perder la sensación de limpio. Las tarjetas SÍ van en
       blanco puro, y ese contraste sutil es lo que las hace flotar sin
       necesidad de sombras pesadas. */
    --gt-bg: #faf9f7; /* fondo dominante (blanco hueso cálido) */
    --gt-surface: #ffffff; /* tarjetas / superficies elevadas */
    --gt-surface-2: #f4f2ef; /* superficie secundaria / hover / zebra */
    --gt-border: #e6e2dd; /* bordes sutiles */
    --gt-border-strong: #d2ccc4;

    /* ----- Paleta: acento de marca -----
       #e10600 es el rojo exacto del logotipo de Novux, leído del archivo de la
       animación de marca. No se "ajustó a ojo": es el mismo valor que usa la
       identidad, para que la app y el logo sean el mismo objeto. */
    --gt-accent: #e10600; /* acento principal: rojo Novux */
    --gt-accent-dark: #b30500; /* acento presionado / hover */
    --gt-accent-soft: rgba(225, 6, 0, 0.08); /* fondo teñido muy leve */
    --gt-accent-ring: rgba(225, 6, 0, 0.22); /* halo de foco */
    --gt-secondary: #1c1b1f; /* secundario: tinta (acciones neutras) */

    /* ----- Paleta: texto -----
       Casi negro, no negro puro: #16161a sobre hueso da un contraste alto
       (>15:1) pero sin el filo duro del #000, que en pantallas modernas se
       percibe agresivo. */
    --gt-text: #16161a; /* texto principal — 17.2:1 */
    --gt-text-muted: #5c5a63; /* texto secundario — 6.4:1, AA para cuerpo */
    --gt-text-dim: #6e6a76; /* terciario: metadatos, placeholders, encabezados de
                               tabla — 4.9:1. Se aclaró desde #86828d (3.6:1), que
                               fallaba AA. Los placeholders y los TH son texto
                               PEQUEÑO y de lectura real: el gris claro "elegante"
                               es la causa más común de UI difícil de leer. */

    /* ----- Paleta: estados -----
       El rojo de marca YA ocupa el espacio semántico del peligro, así que el
       destructivo se diferencia por forma y copy, no por un segundo rojo casi
       idéntico que sería imposible de distinguir. */
    --gt-danger: #c2110c; /* 5.9:1 sobre el fondo */
    --gt-warning: #8f5600; /* 5.7:1 — se oscureció desde #b06a00, que daba 4.07:1
                              y no cumplía AA al usarse como texto pequeño en los
                              tags del Coach. El ámbar "bonito" no llega a AA sobre
                              fondo claro; hay que irse a ocre. */
    --gt-success: #157f4d; /* 4.8:1 */
    --gt-info: #1a5fb4; /* 6.0:1 */

    /* ----- Forma ----- */
    --gt-radius: 1rem;
    --gt-radius-sm: 0.6rem;
    --gt-radius-pill: 999px;

    /* ----- Elevación -----
       En tema claro las sombras negras se ven sucias. Estas van teñidas del
       neutro cálido del fondo y se apoyan en dos capas (una de contacto muy
       corta y otra difusa), que es como cae la luz real. */
    --gt-shadow-sm: 0 1px 2px rgba(28, 22, 18, 0.05), 0 2px 6px rgba(28, 22, 18, 0.05);
    --gt-shadow: 0 2px 4px rgba(28, 22, 18, 0.05), 0 8px 20px rgba(28, 22, 18, 0.07);
    --gt-shadow-hover: 0 4px 8px rgba(28, 22, 18, 0.07), 0 16px 36px rgba(28, 22, 18, 0.1);

    /* ----- Tipografía ----- */
    --gt-font-display: "Saira Condensed", "Segoe UI", system-ui, sans-serif;
    --gt-font-body: "Manrope", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

    /* ----- Movimiento -----
       Curvas de salida (nada de bounce): los objetos reales desaceleran, no
       rebotan. Duraciones cortas para que la interfaz se sienta instantánea.
       --gt-ease-out es la de uso general; --gt-ease-emphasis para lo que debe
       llamar la atención (entradas, confirmaciones). */
    --gt-ease-out: cubic-bezier(0.33, 1, 0.68, 1);
    --gt-ease-emphasis: cubic-bezier(0.22, 1, 0.36, 1);
    --gt-dur-fast: 120ms;
    --gt-dur: 200ms;
    --gt-dur-slow: 320ms;

    /* Sobrescribe variables de Bootstrap para coherencia global */
    --bs-body-bg: var(--gt-bg);
    --bs-body-color: var(--gt-text);
    --bs-primary: var(--gt-accent);
    --bs-border-color: var(--gt-border);
    --bs-link-color: var(--gt-accent);
    --bs-link-hover-color: var(--gt-accent-dark);
    --bs-emphasis-color: var(--gt-text);
    --bs-secondary-color: var(--gt-text-muted);
}

/* Accesibilidad transversal: si el sistema pide menos movimiento, se anula
   todo lo animado de una vez. Va aquí arriba, junto a los tokens, para que
   aplique al sistema completo y no haya que recordarlo componente por
   componente. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ----- Base ----- */
html {
    font-size: 14px;
    position: relative;
    min-height: 100%;
}

@media (min-width: 768px) {
    html {
        font-size: 16px;
    }
}

body {
    margin-bottom: 70px;
    background-color: var(--gt-bg);
    color: var(--gt-text);
    font-family: var(--gt-font-body);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* ----- Tipografía / jerarquía -----
   Los títulos usan la display condensada (Saira) y el cuerpo usa Manrope. Esa
   separación es lo que da carácter deportivo sin sacrificar legibilidad: la
   condensada tiene fuerza en tamaños grandes, pero cansa en párrafos. */
h1, h2, h3, h4, h5, h6 {
    color: var(--gt-text);
    font-weight: 700;
    letter-spacing: -0.01em;
    text-wrap: balance; /* evita títulos con una palabra huérfana en la última línea */
}

h1 {
    font-weight: 800;
    letter-spacing: -0.02em;
}

p {
    text-wrap: pretty;
}

.text-muted {
    color: var(--gt-text-muted) !important;
}

a {
    text-decoration: none;
    transition: color var(--gt-dur-fast) var(--gt-ease-out);
}

/* Foco visible y consistente en toda la app. Se usa :focus-visible (no :focus)
   para que el anillo aparezca al navegar con teclado pero no al hacer clic con
   el mouse, que es cuando estorba. */
:focus-visible {
    outline: 2px solid var(--gt-accent);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Encabezado de página reutilizable.
   Escala FIJA en rem, no fluida con clamp(): esto es UI de producto, no una
   portada. El usuario trabaja a un DPI constante, y un título que se encoge al
   angostar la ventana se ve peor, no mejor. El único ajuste es por breakpoint
   (abajo), que es un cambio estructural y no una interpolación continua. */
.page-title {
    font-family: var(--gt-font-display);
    font-weight: 700;
    font-size: 2rem;
    line-height: 1.05;
    letter-spacing: 0.005em;
    text-transform: uppercase;
    margin-bottom: 0.2rem;
}

@media (min-width: 768px) {
    .page-title {
        font-size: 2.5rem;
    }
}

.page-subtitle {
    color: var(--gt-text-muted);
    margin-bottom: 0;
    max-width: 62ch; /* medida de lectura cómoda */
}

/* Acento de marca: barra roja antes de los títulos de sección. Es el eco del
   pico angular de la "N" del logotipo, y el punto donde el rojo entra en cada
   pantalla sin necesidad de rellenar nada. */
.section-accent {
    position: relative;
    padding-left: 0.9rem;
}

.section-accent::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.12em;
    bottom: 0.12em;
    width: 5px;
    border-radius: 5px;
    background: var(--gt-accent);
}

/* Cabecera de página: título a la izquierda, acción primaria a la derecha.
   Colapsa a columna en móvil. Unifica el patrón que hoy cada vista resuelve
   por su cuenta con utilidades sueltas de Bootstrap. */
.page-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.75rem;
}

/* Cifra grande suelta (fuera de una tarjeta .gt-stat): tonelaje en una tarjeta
   de rutina, kg en el historial. Tabular para que los dígitos no bailen de
   ancho al actualizarse. */
.gt-figura {
    font-family: var(--gt-font-display);
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

.gt-figura-accent {
    color: var(--gt-accent);
}

/* ==========================================================================
   Navbar
   ========================================================================== */
/* Barra translúcida que se pega arriba: al hacer scroll el contenido pasa por
   detrás difuminado, lo que mantiene la navegación siempre accesible sin robar
   peso visual a la página. */
.gt-navbar {
    position: sticky;
    top: 0;
    z-index: 1030;
    background-color: rgba(250, 249, 247, 0.82);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    border-bottom: 1px solid var(--gt-border);
    padding-top: 0.6rem;
    padding-bottom: 0.6rem;
}

/* La marca es el logotipo del diseñador, no texto: por eso aquí no hay
   tipografía que ajustar. */
.gt-navbar .navbar-brand {
    display: inline-flex;
    align-items: center;
    margin-right: 1.5rem;
    padding-top: 0;
    padding-bottom: 0;
}

/* La proporción real del archivo (1200×153) fija el ancho, así que basta con
   dar la altura para que no se deforme ni salte mientras carga. */
.gt-navbar .navbar-brand .brand-logotipo {
    display: block;
    height: 1.35rem;
    aspect-ratio: 1200 / 153;
    position: relative;
    /* La máscara recorta TODO lo que se pinte aquí dentro —incluido el brillo
       del ::after—, así que el efecto queda confinado a las letras. */
    overflow: hidden;
    transform-origin: left center;
    transition: transform var(--gt-dur) var(--gt-ease-emphasis);
}

/* Un destello que barre las letras de izquierda a derecha. Es un degradado
   claro sobre el rojo: como la máscara del logotipo lo recorta, parece que la
   luz pasa por encima de la tipografía y no por una caja rectangular. */
.gt-navbar .navbar-brand .brand-logotipo::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg,
        transparent 35%,
        rgba(255, 255, 255, 0.85) 50%,
        transparent 65%);
    transform: translateX(-100%);
    opacity: 0;
}

/* El barrido corre solo al pasar el cursor, no en bucle: una animación
   permanente en la navbar distrae de la navegación. */
.gt-navbar .navbar-brand:hover .brand-logotipo {
    transform: scale(1.04);
}

.gt-navbar .navbar-brand:hover .brand-logotipo::after {
    animation: nx-brillo-marca 620ms var(--gt-ease-out);
}

@keyframes nx-brillo-marca {
    from { transform: translateX(-100%); opacity: 1; }
    to   { transform: translateX(100%);  opacity: 1; }
}

/* Al pulsar, la marca cede un poco: confirma el clic antes de que cargue la
   página siguiente. */
.gt-navbar .navbar-brand:active .brand-logotipo {
    transform: scale(0.98);
    transition-duration: var(--gt-dur-fast);
}

/* Quien pide menos movimiento conserva el realce, pero sin barrido ni escala:
   el foco y el hover siguen siendo perceptibles. */
@media (prefers-reduced-motion: reduce) {
    .gt-navbar .navbar-brand:hover .brand-logotipo,
    .gt-navbar .navbar-brand:active .brand-logotipo {
        transform: none;
    }

    .gt-navbar .navbar-brand:hover .brand-logotipo::after {
        animation: none;
    }
}

/* ===== Pantallas de acceso (login y registro) =====
   Columna estrecha y centrada: no hay nada más en la página, así que el
   formulario no compite con ningún otro contenido. */
.nx-acceso {
    max-width: 24rem;
    margin: 0 auto 4rem;
}

.nx-acceso-titulo {
    font-family: var(--gt-font-display);
    font-size: 2rem;
    font-weight: 700;
    text-transform: uppercase;
    line-height: 1.05;
    margin-bottom: 0.4rem;
}

.nx-acceso-texto {
    color: var(--gt-text-muted);
    margin-bottom: 1.75rem;
}

.nx-acceso-enlaces {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--gt-border);
    font-size: 0.9rem;
}

.nx-acceso-enlaces a {
    color: var(--gt-text-muted);
    font-weight: 600;
}

.nx-acceso-enlaces a:hover {
    color: var(--gt-accent);
}

/* ===== Logotipo completo ===== */

/* En el hero (fondo rojo) el logotipo blanco funciona tal cual. */
.nx-hero-logotipo {
    display: block;
    width: min(19rem, 62%);
    height: auto;
    margin-bottom: 1.5rem;
}

/* El archivo del logotipo es blanco sobre transparente, hecho para el hero
   rojo. Sobre fondo claro —la navbar y las pantallas de acceso— sería casi
   invisible, así que se usa el PNG como MÁSCARA y el color lo pone el token de
   acento: la marca queda ligada a la variable, no a un archivo teñido a mano.

   Elemento VACÍO: lo que se ve es el color de fondo recortado por la silueta
   del logotipo. Si aquí hubiera un <img>, el navegador lo dibujaría encima del
   color y se vería el logotipo blanco con un halo rojo. */
.gt-navbar .navbar-brand .brand-logotipo,
.nx-identity-logotipo {
    background-color: var(--gt-accent);
    -webkit-mask-image: url("../img/novux-logotipo.png");
    mask-image: url("../img/novux-logotipo.png");
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
}

/* Respaldo para navegadores sin soporte de máscara: en vez de un rectángulo
   rojo sólido (que es lo que quedaría), se muestra el logotipo blanco sobre un
   bloque rojo, que es legible aunque menos elegante. */
@supports not ((mask-image: url("x.png")) or (-webkit-mask-image: url("x.png"))) {
    .gt-navbar .navbar-brand .brand-logotipo,
    .nx-identity-logotipo {
        background-color: transparent;
        background-image: url("../img/novux-logotipo.png");
        background-size: contain;
        background-repeat: no-repeat;
        background-position: center;
        box-shadow: inset 0 0 0 100vmax var(--gt-accent);
        border-radius: var(--gt-radius-sm);
    }
}

/* ===== Marca en las pantallas de acceso (login y registro) =====
   Isotipo y logotipo juntos, centrados y a mayor escala que en la navbar: aquí
   la marca sí es el contenido principal, no un elemento de navegación. */
.nx-identity-marca {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.85rem;
    margin: 1.5rem 0 2.25rem;
}

.nx-identity-isotipo {
    display: inline-grid;
    place-items: center;
    flex: none;
    width: 3.25rem;
    height: 3.25rem;
    border-radius: 0.85rem;
    background: var(--gt-accent);
}

/* El PNG del isotipo es blanco sobre transparente, así que se ve directamente
   sobre el cuadro rojo. */
.nx-identity-isotipo img {
    width: 2.4rem;
    height: 2.4rem;
    object-fit: contain;
}

.nx-identity-logotipo {
    /* La proporción real del archivo (1200×153) fija el ancho a partir de la
       altura, así que el logotipo no se deforma ni salta mientras carga. */
    height: 1.9rem;
    aspect-ratio: 1200 / 153;
}

/* En pantallas estrechas la marca completa no cabe en una línea junto al
   isotipo, así que se reduce en vez de desbordarse. */
@media (max-width: 26rem) {
    .nx-identity-isotipo {
        width: 2.6rem;
        height: 2.6rem;
    }

    .nx-identity-isotipo img {
        width: 1.9rem;
        height: 1.9rem;
    }

    .nx-identity-logotipo {
        height: 1.5rem;
    }
}

/* Punto de sesión activa junto al correo del usuario. Va en rojo para que se
   lea como indicador de estado y no como parte del texto. */
.nx-punto-sesion {
    color: var(--gt-accent);
    font-size: 0.7em;
    vertical-align: middle;
}

/* Los enlaces llevan un subrayado rojo que crece desde el centro. Se anima con
   transform (no con width) para que corra en la GPU y no provoque reflow. */
.gt-navbar .nav-link {
    position: relative;
    color: var(--gt-text-muted) !important;
    font-weight: 600;
    padding: 0.45rem 0.85rem !important;
    border-radius: var(--gt-radius-sm);
    transition: color var(--gt-dur-fast) var(--gt-ease-out);
}

.gt-navbar .nav-link::after {
    content: "";
    position: absolute;
    left: 0.85rem;
    right: 0.85rem;
    bottom: 0.15rem;
    height: 2px;
    border-radius: 2px;
    background: var(--gt-accent);
    transform: scaleX(0);
    transition: transform var(--gt-dur) var(--gt-ease-out);
}

.gt-navbar .nav-link:hover,
.gt-navbar .nav-link:focus-visible {
    color: var(--gt-text) !important;
}

.gt-navbar .nav-link:hover::after {
    transform: scaleX(1);
}

/* Estado activo: el enlace de la sección en la que estás. Se distingue por
   color e indicador permanente, no solo por color (accesibilidad). */
.gt-navbar .nav-link.active {
    color: var(--gt-accent) !important;
}

.gt-navbar .nav-link.active::after {
    transform: scaleX(1);
}

.gt-navbar .navbar-toggler {
    border-color: var(--gt-border);
    padding: 0.35rem 0.6rem;
}

.gt-navbar .navbar-toggler:focus {
    box-shadow: 0 0 0 3px var(--gt-accent-ring);
}

.gt-navbar .navbar-toggler-icon {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%2316161a' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2.2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}

/* ==========================================================================
   Tarjetas
   ========================================================================== */
.card {
    background-color: var(--gt-surface);
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    box-shadow: var(--gt-shadow-sm);
    color: var(--gt-text);
    overflow: hidden;
}

.card-header {
    background-color: transparent;
    border-bottom: 1px solid var(--gt-border);
    color: var(--gt-text);
    font-weight: 600;
    padding: 1rem 1.25rem;
}

.card-body {
    padding: 1.25rem;
}

.card-footer {
    background-color: var(--gt-surface-2);
    border-top: 1px solid var(--gt-border);
    padding: 0.85rem 1.25rem;
}

.card-title {
    font-weight: 700;
}

/* Tarjeta interactiva (listados) con realce al pasar el cursor.
   Solo se animan transform y box-shadow: ambas corren en el compositor, así
   que el hover es fluido aunque la lista tenga docenas de tarjetas. */
.gt-card-link {
    transition: transform var(--gt-dur) var(--gt-ease-out),
                box-shadow var(--gt-dur) var(--gt-ease-out),
                border-color var(--gt-dur) var(--gt-ease-out);
}

.gt-card-link:hover {
    transform: translateY(-4px);
    box-shadow: var(--gt-shadow-hover);
    border-color: var(--gt-border-strong);
}

.gt-card-link:active {
    transform: translateY(-1px);
    transition-duration: var(--gt-dur-fast);
}

/* Cinta de acento superior para tarjetas de rutina */
.gt-card-accent {
    border-top: 3px solid var(--gt-accent);
}

/* ==========================================================================
   Botones
   ========================================================================== */
/* Jerarquía de botones: sólo UNA acción primaria roja por pantalla. Todo lo
   demás es secundario (contorno) o terciario (texto). Esa disciplina es la que
   hace que el rojo signifique algo cuando aparece. */
.btn {
    font-weight: 600;
    border-radius: var(--gt-radius-sm);
    padding: 0.55rem 1.15rem;
    line-height: 1.4;
    transition: transform var(--gt-dur-fast) var(--gt-ease-out),
                box-shadow var(--gt-dur) var(--gt-ease-out),
                background-color var(--gt-dur-fast) var(--gt-ease-out),
                color var(--gt-dur-fast) var(--gt-ease-out),
                border-color var(--gt-dur-fast) var(--gt-ease-out);
}

.btn:active {
    transform: translateY(1px);
}

.btn-sm {
    padding: 0.32rem 0.75rem;
    font-size: 0.825rem;
}

.btn-lg {
    padding: 0.8rem 1.6rem;
    font-size: 1.05rem;
}

/* Primario = rojo Novux con texto blanco. Contraste 5.9:1, cumple AA. */
.btn-primary {
    background-color: var(--gt-accent);
    border-color: var(--gt-accent);
    color: #fff;
}

.btn-primary:hover,
.btn-primary:focus {
    background-color: var(--gt-accent-dark);
    border-color: var(--gt-accent-dark);
    color: #fff;
    box-shadow: 0 4px 14px rgba(225, 6, 0, 0.3);
}

/* Confirmar (terminar sesión, guardar serie): verde de éxito con texto blanco.
   Se mantiene distinto del primario porque significa "cerrar algo", no
   "empezar algo". */
.btn-success {
    background-color: var(--gt-success);
    border-color: var(--gt-success);
    color: #fff;
}

.btn-success:hover,
.btn-success:focus {
    background-color: #0f6b40;
    border-color: #0f6b40;
    color: #fff;
}

/* Secundario = tinta sólida. Es la acción neutra de peso, para cuando hay dos
   caminos válidos y ninguno debe robarse el rojo. */
.btn-secondary {
    background-color: var(--gt-secondary);
    border-color: var(--gt-secondary);
    color: #fff;
}

.btn-secondary:hover,
.btn-secondary:focus {
    background-color: #34333a;
    border-color: #34333a;
    color: #fff;
}

.btn-danger {
    background-color: var(--gt-danger);
    border-color: var(--gt-danger);
    color: #fff;
}

.btn-danger:hover,
.btn-danger:focus {
    background-color: #9e0d09;
    border-color: #9e0d09;
    color: #fff;
}

/* Botones de contorno sobre fondo claro */
.btn-outline-primary {
    color: var(--gt-accent);
    border-color: var(--gt-accent);
    background-color: transparent;
}

.btn-outline-primary:hover,
.btn-outline-primary:focus {
    background-color: var(--gt-accent);
    border-color: var(--gt-accent);
    color: #fff;
}

.btn-outline-secondary,
.btn-outline-dark {
    color: var(--gt-text);
    border-color: var(--gt-border-strong);
    background-color: var(--gt-surface);
}

.btn-outline-secondary:hover,
.btn-outline-secondary:focus,
.btn-outline-dark:hover,
.btn-outline-dark:focus {
    background-color: var(--gt-surface-2);
    border-color: var(--gt-text-dim);
    color: var(--gt-text);
}

.btn-outline-danger {
    color: var(--gt-danger);
    border-color: rgba(194, 17, 12, 0.35);
    background-color: transparent;
}

.btn-outline-danger:hover,
.btn-outline-danger:focus {
    background-color: var(--gt-danger);
    border-color: var(--gt-danger);
    color: #fff;
}

/* Filtro tipo "chip" activo (botón sólido de filtro) */
.btn-dark {
    background-color: var(--gt-accent);
    border-color: var(--gt-accent);
    color: #fff;
}

.btn-dark:hover,
.btn-dark:focus {
    background-color: var(--gt-accent-dark);
    border-color: var(--gt-accent-dark);
    color: #fff;
}

/* Botón de texto: la acción terciaria, sin peso visual. Para "Cancelar" y
   navegación de vuelta, donde un botón sólido competiría con la acción real. */
.btn-link {
    color: var(--gt-text-muted);
    text-decoration: none;
    font-weight: 600;
}

.btn-link:hover,
.btn-link:focus {
    color: var(--gt-accent);
}

/* Foco accesible coherente con el acento */
.btn:focus,
.btn:active:focus,
.btn-link.nav-link:focus,
.form-control:focus,
.form-select:focus,
.form-check-input:focus {
    box-shadow: 0 0 0 0.2rem var(--gt-accent-ring);
    outline: none;
}

/* ==========================================================================
   Formularios
   ========================================================================== */
.form-label {
    color: var(--gt-text-muted);
    font-weight: 600;
    font-size: 0.9rem;
    margin-bottom: 0.35rem;
}

/* Los campos van en blanco sobre el fondo hueso: se leen como "huecos" donde
   se escribe, sin necesidad de bordes pesados. */
.form-control,
.form-select {
    background-color: var(--gt-surface);
    border: 1px solid var(--gt-border-strong);
    border-radius: var(--gt-radius-sm);
    color: var(--gt-text);
    padding: 0.6rem 0.85rem;
    transition: border-color var(--gt-dur-fast) var(--gt-ease-out),
                box-shadow var(--gt-dur-fast) var(--gt-ease-out);
}

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

.form-control:hover:not(:focus),
.form-select:hover:not(:focus) {
    border-color: var(--gt-text-dim);
}

.form-control:focus,
.form-select:focus {
    background-color: var(--gt-surface);
    border-color: var(--gt-accent);
    color: var(--gt-text);
}

/* Los campos numéricos (peso, series, reps) usan cifras tabulares: al escribir
   los dígitos no cambian de ancho, así que el campo no "tiembla". */
.form-control[type="number"] {
    font-variant-numeric: tabular-nums;
}

.form-select {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%235c5a63' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
}

.form-select option {
    background-color: var(--gt-surface);
    color: var(--gt-text);
}

/* Casillas y radios en rojo de marca cuando están activos */
.form-check-input:checked {
    background-color: var(--gt-accent);
    border-color: var(--gt-accent);
}

.form-check-input {
    border-color: var(--gt-border-strong);
}

/* Mensajes de validación: el texto de error necesita contraste real sobre el
   fondo claro, no un rosa lavado. */
.text-danger,
.field-validation-error,
.validation-summary-errors {
    color: var(--gt-danger) !important;
    font-size: 0.875rem;
}

.input-validation-error {
    border-color: var(--gt-danger) !important;
}

.input-validation-error:focus {
    box-shadow: 0 0 0 0.2rem rgba(194, 17, 12, 0.2) !important;
}

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

.form-floating > .form-control-plaintext:focus::placeholder,
.form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* ==========================================================================
   Tablas
   ========================================================================== */
.table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--gt-text);
    color: var(--gt-text);
    margin-bottom: 0;
}

.table > thead th {
    color: var(--gt-text-dim);
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    border-bottom: 1px solid var(--gt-border);
    padding: 0.85rem 0.9rem;
}

.table > tbody > tr {
    border-color: var(--gt-border);
}

.table > tbody > tr > td {
    padding: 0.85rem 0.9rem;
    vertical-align: middle;
    border-color: var(--gt-border);
}

.table-hover > tbody > tr:hover > * {
    --bs-table-hover-bg: var(--gt-surface-2);
    --bs-table-hover-color: var(--gt-text);
    color: var(--gt-text);
}

/* Tag de grupo muscular: chip con acento lateral de color según el grupo.
   Coherente con el lenguaje de .section-accent (barra de color a la izquierda).
   El color por grupo se define en la variable --grupo-color más abajo. */
.gt-badge-grupo {
    position: relative;
    display: inline-flex;
    align-items: center;
    padding: 0.3em 0.7em 0.3em 0.9em;
    border-radius: var(--gt-radius-sm);
    font-weight: 600;
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--gt-text);
    background-color: var(--gt-surface-2);
    border: 1px solid var(--gt-border);
    overflow: hidden;
}

    /* La barra de acento lateral toma el color del grupo. */
    .gt-badge-grupo::before {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        width: 4px;
        background: var(--grupo-color, var(--gt-text-muted));
    }

    /* Cada grupo define su color en una sola variable, y de ahí sale la barra
   lateral. Los tonos se recalibraron para fondo claro: los neón que funcionaban
   sobre negro (lima, cian) desaparecen sobre hueso, así que aquí van versiones
   saturadas y oscuras que mantienen contraste contra el blanco.
   Ninguno usa el rojo de marca: ese está reservado para acciones, y un grupo
   muscular en rojo se leería como "error" o "botón". */
    .gt-badge-grupo[data-grupo="Pecho"] {
        --grupo-color: #d1345b;
    }

    .gt-badge-grupo[data-grupo="Espalda"] {
        --grupo-color: #1a5fb4;
    }

    .gt-badge-grupo[data-grupo="Pierna"] {
        --grupo-color: #4a7c0f;
    }

    .gt-badge-grupo[data-grupo="Hombro"] {
        --grupo-color: #8f5600; /* ocre, no ámbar: el ámbar no llega a AA en claro */
    }

    .gt-badge-grupo[data-grupo="Brazo"] {
        --grupo-color: #c2410c;
    }

    .gt-badge-grupo[data-grupo="Core"] {
        --grupo-color: #6d28d9;
    }

    .gt-badge-grupo[data-grupo="Cardio"] {
        --grupo-color: #0f766e;
    }

/* ==========================================================================
   Alertas
   ========================================================================== */
/* Alertas: borde completo del color del estado más un tinte de fondo muy leve.
   Deliberadamente SIN barra lateral gruesa (border-left de color), que es el
   reflejo perezoso: el color del contorno ya comunica severidad en los cuatro
   lados y no desbalancea la caja. El texto va en tinta normal, no teñido, para
   que se lea igual de bien que el resto de la app. */
.alert {
    border-radius: var(--gt-radius);
    border: 1px solid var(--gt-border);
    background-color: var(--gt-surface);
    color: var(--gt-text);
    padding: 1rem 1.15rem;
}

.alert-info {
    border-color: rgba(26, 95, 180, 0.35);
    background-color: rgba(26, 95, 180, 0.05);
}

.alert-warning {
    border-color: rgba(176, 106, 0, 0.35);
    background-color: rgba(176, 106, 0, 0.06);
}

.alert-danger {
    border-color: rgba(194, 17, 12, 0.35);
    background-color: rgba(194, 17, 12, 0.05);
}

.alert-success {
    border-color: rgba(21, 127, 77, 0.35);
    background-color: rgba(21, 127, 77, 0.05);
}

/* El encabezado sí toma el color del estado: es donde la severidad debe leerse
   primero, y en texto grande el contraste alcanza sin problema. */
.alert-heading {
    font-weight: 700;
    margin-bottom: 0.35rem;
}

.alert-info .alert-heading {
    color: var(--gt-info);
}

.alert-warning .alert-heading {
    color: var(--gt-warning);
}

.alert-danger .alert-heading {
    color: var(--gt-danger);
}

.alert-success .alert-heading {
    color: var(--gt-success);
}

/* ==========================================================================
   Estado vacío (listados sin datos)
   ========================================================================== */
.gt-empty {
    text-align: center;
    padding: 3.5rem 1.5rem;
    background-color: var(--gt-surface);
    border: 1px dashed var(--gt-border-strong);
    border-radius: var(--gt-radius);
}

.gt-empty .gt-empty-icon {
    font-size: 2.75rem;
    line-height: 1;
    margin-bottom: 0.75rem;
    filter: grayscale(0.2);
}

.gt-empty h5 {
    margin-bottom: 0.35rem;
}

.gt-empty p {
    color: var(--gt-text-muted);
    margin-bottom: 1.25rem;
}

/* Descripción de tipo "definición" (Detalle) */
dt {
    color: var(--gt-text-muted);
    font-weight: 600;
}

dd {
    color: var(--gt-text);
}

/* Tarjeta de métrica (chips de stats en Detalle de rutina) */
.gt-stat {
    background-color: var(--gt-surface-2);
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius-sm);
    padding: 0.75rem 1rem;
    text-align: center;
}

.gt-stat .gt-stat-value {
    font-family: var(--gt-font-display);
    font-size: 2.1rem;
    font-weight: 700;
    color: var(--gt-accent);
    line-height: 1;
    letter-spacing: 0.01em;
}

.gt-stat .gt-stat-label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--gt-text-dim);
}

/* ==========================================================================
   Hero (Home)
   ========================================================================== */
/* El hero es la única superficie donde el rojo ocupa área grande: es la
   portada, y ahí la marca debe dominar. En el resto de la app el rojo vuelve a
   ser sólo acento. */
.gt-hero {
    position: relative;
    border-radius: var(--gt-radius);
    padding: clamp(2.5rem, 1.5rem + 5vw, 5rem) clamp(1.5rem, 1rem + 3vw, 3.5rem);
    background: var(--gt-accent);
    color: #fff;
    overflow: hidden;
}

/* Trama diagonal muy tenue que rompe el plano rojo sin ensuciarlo: repite el
   ángulo del pico de la "N" del logotipo. */
.gt-hero::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: repeating-linear-gradient(115deg, rgba(255, 255, 255, 0.05) 0 2px, transparent 2px 26px);
    pointer-events: none;
}

.gt-hero > * {
    position: relative;
    z-index: 1;
}

/* El hero es la ÚNICA superficie de la app con registro de marca: es la portada
   que ve quien todavía no inició sesión. Por eso aquí sí aplica tipografía
   fluida con clamp() y el rojo a área completa, mientras que el resto de la app
   (UI de producto) usa escala fija en rem y el rojo sólo como acento. */
.gt-hero h1 {
    font-family: var(--gt-font-display);
    font-size: clamp(2.4rem, 1.4rem + 4vw, 4.5rem);
    font-weight: 800;
    line-height: 0.98;
    letter-spacing: 0.005em;
    text-transform: uppercase;
    color: #fff;
    margin-bottom: 1rem;
}

.gt-hero .gt-hero-accent {
    /* Sobre el rojo del hero, el "acento" es el contraste inverso: blanco
       calado con un subrayado sólido. */
    color: #fff;
    box-shadow: inset 0 -0.18em 0 rgba(255, 255, 255, 0.35);
}

.gt-hero p.lead {
    color: rgba(255, 255, 255, 0.92);
    max-width: 40ch;
    font-size: 1.1rem;
}

/* Dentro del hero la acción primaria se invierte: fondo blanco, texto rojo.
   Un botón rojo sobre rojo sería invisible. */
.gt-hero .btn-primary {
    background-color: #fff;
    border-color: #fff;
    color: var(--gt-accent);
}

.gt-hero .btn-primary:hover,
.gt-hero .btn-primary:focus {
    background-color: rgba(255, 255, 255, 0.9);
    border-color: rgba(255, 255, 255, 0.9);
    color: var(--gt-accent-dark);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
}

.gt-hero .btn-outline-secondary,
.gt-hero .btn-outline-dark {
    background-color: transparent;
    border-color: rgba(255, 255, 255, 0.5);
    color: #fff;
}

.gt-hero .btn-outline-secondary:hover,
.gt-hero .btn-outline-dark:hover {
    background-color: rgba(255, 255, 255, 0.14);
    border-color: #fff;
    color: #fff;
}

.gt-eyebrow {
    display: inline-block;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--gt-accent);
    margin-bottom: 1rem;
}

.gt-hero .gt-eyebrow {
    color: rgba(255, 255, 255, 0.75);
}



/* ==========================================================================
   Footer
   ========================================================================== */
.footer {
    position: absolute;
    bottom: 0;
    width: 100%;
    line-height: 60px;
    background-color: var(--gt-surface);
    border-top: 1px solid var(--gt-border);
    color: var(--gt-text-muted);
    font-size: 0.9rem;
}

.footer a {
    color: var(--gt-accent);
}

.footer a:hover {
    color: var(--gt-accent-dark);
}

/* ===== Tag de resultado (historial de series): barra de progreso mini =====
   Refleja el cumplimiento real vs meta. La vista pasa --pct-escala como un
   factor de 0 a 1 (con punto decimal invariante, no coma) y el color sale de
   la clase de estado. */
.gt-resultado {
    display: inline-flex;
    flex-direction: column;
    gap: 0.25em;
    min-width: 84px;
}

.gt-resultado-label {
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--gt-text-muted);
}

/* display:block porque el elemento puede ser un <span> (dentro de un contenedor
   en línea) o un <div>: en ambos casos debe ocupar todo el ancho disponible. */
.gt-resultado-barra {
    display: block;
    position: relative;
    height: 6px;
    border-radius: 999px;
    background-color: var(--gt-surface-2);
    overflow: hidden;
}

    /* El relleno ocupa el 100% y se escala con transform en vez de animar
       `width`: animar una propiedad de layout obliga al navegador a recalcular
       la página en cada cuadro, y en el historial hay una barra por serie.
       `scaleX` corre en el compositor, así que no provoca reflow.
       El origen a la izquierda hace que crezca desde el inicio, no del centro. */
    .gt-resultado-barra::before {
        content: "";
        position: absolute;
        inset: 0;
        border-radius: 999px;
        background: var(--gt-resultado-color, var(--gt-text-muted));
        transform: scaleX(var(--pct-escala, 0));
        transform-origin: left center;
        transition: transform var(--gt-dur-slow) var(--gt-ease-out);
    }

/* Estados: color según desempeño. Cada uno se distingue además por el ancho de
   la barra, así que la información no depende sólo del color (accesibilidad
   para daltonismo). */
.gt-resultado.supero {
    --gt-resultado-color: var(--gt-success);
}

.gt-resultado.cumplio {
    --gt-resultado-color: var(--gt-info);
}

.gt-resultado.bajo {
    --gt-resultado-color: var(--gt-text-dim);
}


/* ===== Acciones de fila: aparecen al hacer hover (solo en dispositivos con
   hover real; en táctil se muestran siempre). Reemplaza el patrón de tres
   botones de texto siempre visibles. ===== */
.gt-acciones {
    display: inline-flex;
    gap: 0.25rem;
    align-items: center;
}

.gt-accion {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: var(--gt-radius-sm);
    border: 1px solid var(--gt-border);
    background-color: var(--gt-surface-2);
    color: var(--gt-text-muted);
    transition: all 0.15s ease;
    text-decoration: none;
}

    .gt-accion:hover {
        color: var(--gt-text);
        border-color: var(--gt-border-strong);
        background-color: var(--gt-surface);
        transform: translateY(-1px);
    }

    /* La acción de eliminar se tiñe de rojo al hover, como señal de peligro. */
    .gt-accion.gt-accion-danger:hover {
        color: var(--gt-danger);
        border-color: var(--gt-danger);
    }

    .gt-accion svg {
        width: 16px;
        height: 16px;
    }

/* En dispositivos CON hover (escritorio), las acciones arrancan ocultas
   y aparecen al pasar sobre la fila. */
@media (hover: hover) {
    tr .gt-acciones,
    .nx-rutina .gt-acciones {
        opacity: 0;
        transition: opacity var(--gt-dur-fast) var(--gt-ease-out);
    }

    tr:hover .gt-acciones,
    .nx-rutina:hover .gt-acciones {
        opacity: 1;
    }

    /* Con teclado no hay hover: si el foco entra en una acción, se muestra.
       Sin esto, quien navega con Tab enfocaría botones invisibles. */
    tr .gt-acciones:focus-within,
    .nx-rutina .gt-acciones:focus-within {
        opacity: 1;
    }
}



/* ==========================================================================
   Coach IA — invitación y panel de análisis
   --------------------------------------------------------------------------
   Comparte el lenguaje del chatbot a propósito: es el mismo modelo hablando,
   así que el guion rojo, las barras de espera y la superficie blanca se repiten
   aquí. Lo que cambia es el formato, porque esto es un informe y no un diálogo.
   ========================================================================== */
.nx-coach {
    margin-bottom: 1.5rem;
}

/* ----- Invitación (estado inicial) -----
   Antes esto era un botón gris llamado "Analizar con IA" entre Editar y
   Eliminar: la función más interesante de la pantalla parecía una acción
   administrativa. Ahora es una tarjeta que dice qué va a revisar. */
.nx-coach-invitacion {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.1rem 1.25rem;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background: var(--gt-surface);
    transition: border-color var(--gt-dur) var(--gt-ease-out),
                box-shadow var(--gt-dur) var(--gt-ease-out),
                transform var(--gt-dur) var(--gt-ease-out),
                opacity var(--gt-dur) var(--gt-ease-out);
}

.nx-coach-invitacion:hover {
    border-color: var(--gt-border-strong);
    box-shadow: var(--gt-shadow);
}

/* Al analizar, la invitación se va hacia arriba y el panel ocupa su sitio: es
   el mismo bloque cambiando de estado, no dos tarjetas apiladas. */
.nx-coach-oculto {
    opacity: 0;
    transform: translateY(-0.5rem);
    /* Se saca del flujo al terminar para que el panel suba a ocupar el hueco. */
    position: absolute;
    pointer-events: none;
}

/* Las barras laten en bucle lento. Es el único elemento animado en reposo de
   la pantalla: sirve para llevar la vista hasta aquí sin recurrir a un color
   chillón ni a un contorno parpadeante. */
.nx-coach-pulso {
    display: flex;
    align-items: center;
    gap: 0.16rem;
    flex: none;
    height: 1.7rem;
}

.nx-coach-pulso i {
    display: block;
    width: 0.2rem;
    height: 100%;
    border-radius: 0.2rem;
    background: var(--gt-accent);
    transform-origin: center;
    transform: scaleY(0.35);
    animation: nx-coach-latido 2.4s infinite var(--gt-ease-out);
}

.nx-coach-pulso i:nth-child(1) { animation-delay: 0s; }
.nx-coach-pulso i:nth-child(2) { animation-delay: 0.18s; }
.nx-coach-pulso i:nth-child(3) { animation-delay: 0.42s; }
.nx-coach-pulso i:nth-child(4) { animation-delay: 0.26s; }

@keyframes nx-coach-latido {
    0%, 55%, 100% { transform: scaleY(0.35); opacity: 0.5; }
    22%           { transform: scaleY(1);    opacity: 1; }
}

/* Al pasar el cursor por la tarjeta, el latido se acelera: la invitación
   responde antes de que se pulse nada. */
.nx-coach-invitacion:hover .nx-coach-pulso i {
    animation-duration: 1.1s;
}

.nx-coach-invitacion-texto {
    flex: 1;
    min-width: 0;
}

.nx-coach-invitacion-titulo {
    margin: 0 0 0.15rem;
    font-family: var(--gt-font-display);
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--gt-text);
}

.nx-coach-invitacion-sub {
    margin: 0;
    font-size: 0.85rem;
    line-height: 1.4;
    color: var(--gt-text-muted);
}

.nx-coach-cta {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    flex: none;
    padding: 0.55rem 1.1rem;
    border: none;
    border-radius: 2rem;
    background: var(--gt-accent);
    color: #fff;
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: 700;
    cursor: pointer;
    transition: background var(--gt-dur-fast) var(--gt-ease-out),
                box-shadow var(--gt-dur) var(--gt-ease-out);
}

.nx-coach-cta svg {
    width: 1rem;
    height: 1rem;
    transition: transform var(--gt-dur) var(--gt-ease-emphasis);
}

/* La flecha avanza al pasar el cursor: sugiere hacia dónde lleva la acción. */
.nx-coach-invitacion:hover .nx-coach-cta {
    background: var(--gt-accent-dark);
    box-shadow: 0 4px 14px -4px rgba(225, 6, 0, 0.5);
}

.nx-coach-invitacion:hover .nx-coach-cta svg {
    transform: translateX(3px);
}

.nx-coach-cta:focus-visible {
    outline: 2px solid var(--gt-accent);
    outline-offset: 3px;
}

.nx-coach-cta:active {
    transform: translateY(1px);
}

.nx-coach-cta:disabled {
    opacity: 0.6;
    cursor: default;
}

/* ----- Panel del análisis ----- */
.nx-coach-panel {
    padding: 1.25rem;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background: var(--gt-surface);
    box-shadow: 0 1px 2px rgba(22, 22, 26, 0.05),
                0 10px 26px -18px rgba(22, 22, 26, 0.4);
    animation: nx-coach-panel-entra var(--gt-dur-slow) var(--gt-ease-emphasis) both;
}

@keyframes nx-coach-panel-entra {
    from { opacity: 0; transform: translateY(0.6rem); }
    to   { opacity: 1; transform: translateY(0); }
}

.nx-coach-header {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 1.1rem;
}

/* El mismo guion rojo que abre las respuestas del chatbot: es la firma de que
   habla el modelo, repetida en las dos pantallas. */
.nx-coach-marca {
    width: 1.25rem;
    height: 2px;
    flex: none;
    border-radius: 2px;
    background: var(--gt-accent);
    transform-origin: left center;
    animation: nx-coach-guion var(--gt-dur) var(--gt-ease-out) both;
    animation-delay: 140ms;
}

@keyframes nx-coach-guion {
    from { transform: scaleX(0); opacity: 0; }
    to   { transform: scaleX(1); opacity: 1; }
}

.nx-coach-title {
    flex: 1;
    margin: 0;
    font-family: var(--gt-font-display);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    font-size: 1.15rem;
    color: var(--gt-text);
}

/* Volver a analizar: la rutina cambia, el análisis debe poder rehacerse. */
.nx-coach-repetir {
    display: grid;
    place-items: center;
    flex: none;
    width: 2rem;
    height: 2rem;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius-sm);
    background: var(--gt-surface);
    color: var(--gt-text-muted);
    cursor: pointer;
    transition: color var(--gt-dur-fast) var(--gt-ease-out),
                border-color var(--gt-dur-fast) var(--gt-ease-out);
}

.nx-coach-repetir svg {
    width: 1rem;
    height: 1rem;
    transition: transform var(--gt-dur-slow) var(--gt-ease-emphasis);
}

.nx-coach-repetir:hover {
    color: var(--gt-accent);
    border-color: var(--gt-accent);
}

.nx-coach-repetir:hover svg {
    transform: rotate(-180deg);
}

.nx-coach-repetir:focus-visible {
    outline: 2px solid var(--gt-accent);
    outline-offset: 2px;
}

.nx-coach-repetir:disabled {
    opacity: 0.5;
    cursor: default;
}

/* ----- Secciones del informe -----
   Entran escalonadas: el índice lo pone el JS en --nx-orden y el retardo se
   calcula aquí, así los tiempos viven en un solo sitio. */
.nx-coach-seccion,
.nx-coach-veredicto {
    animation: nx-coach-seccion-entra var(--gt-dur) var(--gt-ease-out) both;
    animation-delay: calc(var(--nx-orden, 0) * 70ms);
}

@keyframes nx-coach-seccion-entra {
    from { opacity: 0; transform: translateY(0.5rem); }
    to   { opacity: 1; transform: translateY(0); }
}

.nx-coach-seccion {
    margin-bottom: 1.1rem;
}

.nx-coach-seccion h4 {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--gt-text-muted);
    margin-bottom: 0.4rem;
}

.nx-coach-seccion p {
    margin: 0;
    line-height: 1.55;
    color: var(--gt-text);
}

/* ----- Veredicto -----
   Ya no es una etiqueta suelta seguida de un párrafo huérfano: el icono, el
   titular y la explicación forman un bloque, que es como se lee un diagnóstico. */
.nx-coach-veredicto {
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    padding: 0.85rem 1rem;
    margin-bottom: 1.1rem;
    border-radius: var(--gt-radius-sm);
}

.nx-coach-veredicto svg {
    width: 1.25rem;
    height: 1.25rem;
    flex: none;
    margin-top: 0.05rem;
}

.nx-coach-veredicto strong {
    display: block;
    margin-bottom: 0.2rem;
    font-size: 0.95rem;
}

.nx-coach-veredicto p {
    margin: 0;
    font-size: 0.88rem;
    line-height: 1.5;
    color: var(--gt-text);
}

/* El tinte va al 7% y no al 9%: medido, el verde de --gt-success sobre su
   propio tinte al 9% da 4.45:1, justo por debajo del 4.5:1 de AA. Al 7% son
   4.59:1. Se ajusta el fondo y no el token, que se usa en otras pantallas. */
.nx-coach-veredicto.ok {
    background: rgba(21, 127, 77, 0.07);
    color: var(--gt-success);
}

.nx-coach-veredicto.no {
    background: rgba(143, 86, 0, 0.09);
    color: var(--gt-warning);
}

/* ----- Sugerencias ----- */
.nx-coach-lista {
    list-style: none;
    padding: 0;
    margin: 0;
}

.nx-coach-lista li {
    position: relative;
    padding-left: 1.35rem;
    margin-bottom: 0.5rem;
    line-height: 1.55;
    color: var(--gt-text);
    animation: nx-coach-item-entra var(--gt-dur) var(--gt-ease-out) both;
    /* Se suma al retardo de la sección para que los puntos caigan después del
       encabezado que los introduce. */
    animation-delay: calc(var(--nx-orden, 0) * 70ms + var(--nx-i, 0) * 60ms + 120ms);
}

@keyframes nx-coach-item-entra {
    from { opacity: 0; transform: translateX(-0.35rem); }
    to   { opacity: 1; transform: translateX(0); }
}

.nx-coach-lista li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.6em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--gt-accent);
}

/* ----- Grupos descuidados ----- */
.nx-coach-descuidados {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.nx-coach-descuidado {
    display: inline-block;
    font-size: 0.8rem;
    font-weight: 600;
    padding: 0.3em 0.75em;
    border-radius: 2rem;
    border: 1px solid rgba(143, 86, 0, 0.35);
    color: var(--gt-warning);
    background: rgba(143, 86, 0, 0.08);
    animation: nx-coach-item-entra var(--gt-dur) var(--gt-ease-out) both;
    animation-delay: calc(var(--nx-orden, 0) * 70ms + var(--nx-i, 0) * 60ms + 120ms);
}

/* ----- Carga y error ----- */
.nx-coach-cargando {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.4rem 0;
}

.nx-coach-cargando-texto {
    font-size: 0.9rem;
    color: var(--gt-text-muted);
}

.nx-coach-error {
    margin: 0;
    padding: 0.75rem 0.9rem;
    border-radius: var(--gt-radius-sm);
    background: rgba(194, 17, 12, 0.08);
    border: 1px solid rgba(194, 17, 12, 0.28);
    color: var(--gt-danger);
    font-size: 0.9rem;
}

/* En móvil la tarjeta pasa a columna: el texto de la invitación no cabe junto
   al botón en 409px, y partirlo en dos líneas lo dejaría ilegible. */
@media (max-width: 34rem) {
    .nx-coach-invitacion {
        flex-wrap: wrap;
    }

    .nx-coach-invitacion-texto {
        flex: 1 1 100%;
        order: 2;
    }

    .nx-coach-cta {
        flex: 1 1 100%;
        order: 3;
        justify-content: center;
    }
}

@media (prefers-reduced-motion: reduce) {
    .nx-coach-pulso i,
    .nx-coach-panel,
    .nx-coach-seccion,
    .nx-coach-veredicto,
    .nx-coach-lista li,
    .nx-coach-descuidado {
        animation: none;
    }

    /* Sin animación, el guion se quedaría en scaleX(0), es decir invisible. */
    .nx-coach-marca {
        animation: none;
        transform: scaleX(1);
        opacity: 1;
    }

    .nx-coach-pulso i {
        transform: scaleY(0.7);
        opacity: 0.8;
    }

    .nx-coach-repetir:hover svg {
        transform: none;
    }
}

/* ===== Catálogo "Explorar ejercicios" (GIFs de ExerciseDB) ===== */
.gt-catalogo-filtros {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1.5rem;
}

.gt-catalogo-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 1rem;
}

.gt-cat-card {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background-color: var(--gt-surface);
    overflow: hidden;
    text-decoration: none;
    color: var(--gt-text);
    transition: all 0.18s ease;
}

    .gt-cat-card:hover {
        border-color: var(--gt-accent);
        transform: translateY(-2px);
        box-shadow: var(--gt-shadow-hover);
        color: var(--gt-text);
    }

/* El GIF: fondo claro porque los GIFs de ExerciseDB son sobre blanco. */
.gt-cat-gif {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: contain;
    background-color: #f5f5f5;
}

/* Contenedor de la tarjeta: permite superponer el botón "Vincular" (que es
   hermano del <a>, no hijo, para no anidar interactivos). */
.gt-cat-card-wrap {
    position: relative;
    display: flex;
}

    .gt-cat-card-wrap > .gt-cat-card {
        flex: 1;
    }

/* Acción "Vincular": aparece en hover (DESIGN-RULES), acento con mesura. */
.gt-cat-vincular {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.6rem;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--gt-bg);
    background-color: var(--gt-accent);
    border: none;
    border-radius: var(--gt-radius-sm);
    cursor: pointer;
    opacity: 0;
    transform: translateY(-4px);
    pointer-events: none;
    transition: opacity 0.16s ease, transform 0.16s ease, background-color 0.16s ease;
}

.gt-cat-card-wrap:hover .gt-cat-vincular,
.gt-cat-vincular:focus-visible {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

    .gt-cat-vincular:hover {
        background-color: var(--gt-accent-dark);
    }

/* En pantallas táctiles no hay hover: mostrar siempre. */
@media (hover: none) {
    .gt-cat-vincular {
        opacity: 1;
        transform: none;
        pointer-events: auto;
    }
}

/* Toast de confirmación (vinculado). */
.gt-toast {
    position: fixed;
    bottom: 1.5rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1080;
    padding: 0.7rem 1.1rem;
    background-color: var(--gt-surface-2);
    border: 1px solid var(--gt-accent);
    border-radius: var(--gt-radius-sm);
    color: var(--gt-text);
    box-shadow: var(--gt-shadow-hover);
    font-size: 0.9rem;
}

/* Estado de vinculación en editar ejercicio. */
.gt-vinculo-estado {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    padding: 0.75rem;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius-sm);
    background-color: var(--gt-surface-2);
}

.gt-vinculo-thumb {
    width: 64px;
    height: 64px;
    object-fit: contain;
    background-color: #f5f5f5;
    border-radius: var(--gt-radius-sm);
    flex-shrink: 0;
}

.gt-vinculo-info {
    flex: 1;
    min-width: 0;
}

.gt-vinculo-nombre {
    font-family: var(--gt-font-display);
    font-weight: 600;
}

/* Miniatura de GIF (entrenamiento y detalle de rutina) que abre el modal. */
.gt-serie-gif {
    width: 46px;
    height: 46px;
    object-fit: contain;
    background-color: #f5f5f5;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius-sm);
    cursor: pointer;
    flex-shrink: 0;
    transition: border-color 0.16s ease;
}

    .gt-serie-gif:hover {
        border-color: var(--gt-accent);
    }

/* ===== Barra de filtros de "Explorar" (Fase 4) ===== */
.gt-filtros {
    margin-bottom: 1.5rem;
}

.gt-filtros-buscar {
    position: relative;
    margin-bottom: 1.1rem;
}

    .gt-filtros-buscar svg {
        position: absolute;
        left: 0.9rem;
        top: 50%;
        transform: translateY(-50%);
        color: var(--gt-text-muted);
        pointer-events: none;
    }

    .gt-filtros-buscar input {
        width: 100%;
        padding: 0.6rem 0.9rem 0.6rem 2.6rem;
        background-color: var(--gt-surface);
        border: 1px solid var(--gt-border);
        border-radius: var(--gt-radius-sm);
        color: var(--gt-text);
        font-size: 0.95rem;
        transition: border-color 0.16s ease, box-shadow 0.16s ease;
    }

        .gt-filtros-buscar input::placeholder {
            color: var(--gt-text-muted);
        }

        .gt-filtros-buscar input:focus {
            outline: none;
            border-color: var(--gt-accent);
            box-shadow: 0 0 0 3px var(--gt-accent-soft);
        }

.gt-filtros-seccion {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 0.85rem;
}

.gt-filtros-label {
    font-family: var(--gt-font-display);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--gt-text-muted);
    margin-right: 0.5rem;
    min-width: 4.5rem;
}

.gt-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.gt-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.32rem 0.7rem;
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--gt-text);
    background-color: var(--gt-surface-2);
    border: 1px solid var(--gt-border);
    border-radius: 2rem;
    cursor: pointer;
    transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}

    .gt-pill:hover {
        border-color: var(--gt-border-strong);
        background-color: var(--gt-surface);
    }

    .gt-pill:focus-visible {
        outline: none;
        border-color: var(--gt-accent);
        box-shadow: 0 0 0 3px var(--gt-accent-soft);
    }

    .gt-pill:active {
        transform: scale(0.97);
    }

    .gt-pill.activo {
        background-color: var(--gt-accent);
        border-color: var(--gt-accent);
        color: var(--gt-bg);
        font-weight: 600;
    }

.gt-pill-count {
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
    padding: 0 0.35em;
    border-radius: 1rem;
    background-color: var(--gt-surface-2);
    color: var(--gt-text-muted);
}

.gt-pill.activo .gt-pill-count {
    background-color: rgba(255, 255, 255, 0.25);
    color: #fff;
}

/* Botón "Más filtros" */
.gt-filtros-mas {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.8rem;
    margin-bottom: 0.85rem;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--gt-text);
    background-color: transparent;
    border: 1px dashed var(--gt-border-strong);
    border-radius: var(--gt-radius-sm);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}

    .gt-filtros-mas:hover {
        border-color: var(--gt-accent);
        color: var(--gt-accent);
    }

    .gt-filtros-mas.activo {
        border-style: solid;
        border-color: var(--gt-accent);
        color: var(--gt-accent);
    }

/* Panel colapsable: se anima con grid-template-rows (sin thrash de layout). */
.gt-filtros-panel {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.25s ease;
}

    .gt-filtros-panel.abierto {
        grid-template-rows: 1fr;
    }

.gt-filtros-panel-inner {
    overflow: hidden;
    min-height: 0;
    padding-top: 0.25rem;
}

/* Chips de filtros activos */
.gt-filtros-activos {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
}

    .gt-filtros-activos:not(:empty) {
        margin-top: 0.4rem;
    }

.gt-chip-activo {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.25rem 0.5rem 0.25rem 0.7rem;
    font-size: 0.78rem;
    color: var(--gt-accent);
    background-color: var(--gt-accent-soft);
    border: 1px solid var(--gt-accent);
    border-radius: 2rem;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

    .gt-chip-activo:hover {
        background-color: rgba(225, 6, 0, 0.16);
    }

.gt-chip-x {
    font-size: 1.05rem;
    line-height: 1;
}

.gt-chip-limpiar {
    padding: 0.25rem 0.6rem;
    font-size: 0.76rem;
    color: var(--gt-text-muted);
    background: none;
    border: none;
    text-decoration: underline;
    cursor: pointer;
}

    .gt-chip-limpiar:hover {
        color: var(--gt-text);
    }

.gt-resultados-info {
    font-family: var(--gt-font-display);
    font-size: 0.85rem;
    color: var(--gt-text-muted);
    margin-bottom: 0.85rem;
}

.gt-cat-body {
    padding: 0.75rem 0.9rem;
}

.gt-cat-nombre {
    font-family: var(--gt-font-display);
    font-weight: 600;
    text-transform: capitalize;
    font-size: 1rem;
    line-height: 1.1;
    margin-bottom: 0.35rem;
}


.gt-cat-chip {
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 0.15em 0.5em;
    border-radius: var(--gt-radius-sm);
    background-color: var(--gt-surface-2);
    color: var(--gt-text-muted);
    border: 1px solid var(--gt-border);
}

/* Detalle: GIF grande + instrucciones. */
.gt-cat-detalle-gif {
    width: 100%;
    max-width: 420px;
    aspect-ratio: 1 / 1;
    object-fit: contain;
    background-color: #f5f5f5;
    border-radius: var(--gt-radius);
    border: 1px solid var(--gt-border);
}



/* ==========================================================================
   Navegación inferior (SÓLO MÓVIL)
   --------------------------------------------------------------------------
   Oculta por defecto: en escritorio la navegación es la navbar de arriba y esto
   no existe. Se enciende por debajo de 576px, el mismo punto en el que Bootstrap
   colapsa la navbar (navbar-expand-sm), para que nunca haya dos navegaciones a
   la vez ni un hueco entre ambas.
   ========================================================================== */
.nx-tabbar {
    display: none;
}

@media (max-width: 575.98px) {
    /* Oculta la hamburguesa y su desplegable: la barra inferior los sustituye.
       El logotipo se queda, así que la navbar sigue identificando la app. */
    .gt-navbar .navbar-toggler,
    .gt-navbar .navbar-collapse {
        display: none !important;
    }

    .nx-tabbar {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 1040;
        display: flex;
        align-items: stretch;
        background: rgba(255, 255, 255, 0.92);
        backdrop-filter: saturate(180%) blur(14px);
        -webkit-backdrop-filter: saturate(180%) blur(14px);
        border-top: 1px solid var(--gt-border);
        /* Respeta la barra de gestos del iPhone: sin esto, el último renglón de
           iconos queda debajo del indicador del sistema. */
        padding-bottom: env(safe-area-inset-bottom, 0);
    }

    /* El contenido necesita sitio para no quedar tapado por la barra fija. */
    body {
        padding-bottom: 4.5rem;
    }

    /* El footer es lo último de la página: si queda pegado a la barra, sus
       enlaces son intocables. */
    .footer {
        margin-bottom: 0.5rem;
    }

    .nx-tab {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 0.15rem;
        /* 3.25rem = 52px de alto real de toque, por encima del mínimo de 44px
           que recomienda WCAG para objetivos táctiles. */
        min-height: 3.25rem;
        padding: 0.45rem 0.2rem;
        color: var(--gt-text-muted);
        text-decoration: none;
        font-size: 0.62rem;
        font-weight: 600;
        letter-spacing: 0.01em;
        list-style: none;
        cursor: pointer;
        transition: color var(--gt-dur-fast) var(--gt-ease-out);
    }

    .nx-tab svg {
        width: 1.35rem;
        height: 1.35rem;
    }

    /* La sección actual va en rojo y con una barrita arriba. El color solo no
       basta: quien no distingue el rojo necesita una segunda señal. */
    .nx-tab.active {
        color: var(--gt-accent);
    }

    .nx-tab.active::before {
        content: "";
        position: absolute;
        top: 0;
        width: 1.75rem;
        height: 3px;
        border-radius: 0 0 3px 3px;
        background: var(--gt-accent);
    }

    .nx-tab {
        position: relative;
    }

    .nx-tab:active {
        background: var(--gt-surface-2);
    }

    .nx-tab:focus-visible {
        outline: 2px solid var(--gt-accent);
        outline-offset: -3px;
    }

    /* ----- "Más" -----
       <details> nativo: abre y cierra sin JavaScript, con el comportamiento de
       teclado que ya trae el navegador. */
    /* position: relative es imprescindible: el panel de abajo es absolute y sin
       esto se anclaría al viewport en vez de a este botón. */
    .nx-tab-mas {
        position: relative;
        flex: 1;
        display: flex;
    }

    .nx-tab-mas > summary {
        flex: 1;
        /* Quita el triangulito por defecto del navegador. */
        list-style: none;
    }

    .nx-tab-mas > summary::-webkit-details-marker {
        display: none;
    }

    /* Si la sección actual está dentro de "Más", el botón se marca igual que
       una pestaña activa: no se pierde la referencia de dónde estás. */
    .nx-tab-mas.active > summary {
        color: var(--gt-accent);
    }

    .nx-tab-mas.active > summary::before {
        content: "";
        position: absolute;
        top: 0;
        width: 1.75rem;
        height: 3px;
        border-radius: 0 0 3px 3px;
        background: var(--gt-accent);
    }

    /* El panel sube desde la barra, anclado a la derecha porque su botón está
       en esa esquina: sale de donde se tocó. */
    .nx-tab-panel {
        position: absolute;
        right: 0.5rem;
        bottom: calc(100% + 0.4rem);
        min-width: 11rem;
        display: flex;
        flex-direction: column;
        padding: 0.35rem;
        background: var(--gt-surface);
        border: 1px solid var(--gt-border);
        border-radius: var(--gt-radius);
        box-shadow: var(--gt-shadow-hover);
        animation: nx-tab-panel-entra var(--gt-dur) var(--gt-ease-emphasis);
    }

    @keyframes nx-tab-panel-entra {
        from { opacity: 0; transform: translateY(0.5rem); }
        to   { opacity: 1; transform: translateY(0); }
    }

    .nx-tab-mas-item {
        padding: 0.6rem 0.75rem;
        border: none;
        border-radius: var(--gt-radius-sm);
        background: none;
        color: var(--gt-text);
        font-family: inherit;
        font-size: 0.9rem;
        font-weight: 600;
        text-align: left;
        text-decoration: none;
        cursor: pointer;
    }

    .nx-tab-mas-item:hover,
    .nx-tab-mas-item:active {
        background: var(--gt-surface-2);
        color: var(--gt-accent);
    }

    .nx-tab-mas-item.active {
        color: var(--gt-accent);
    }

    .nx-tab-panel-sep {
        height: 1px;
        margin: 0.3rem 0.25rem;
        background: var(--gt-border);
    }

    .nx-tab-panel-salir {
        display: flex;
        margin: 0;
    }

    .nx-tab-mas-salir {
        flex: 1;
        color: var(--gt-danger);
    }

    .nx-tab-mas-salir:hover,
    .nx-tab-mas-salir:active {
        color: var(--gt-danger);
    }

    /* La pestaña del asistente se centra dentro de la zona que queda LIBRE por
       encima de la barra. Como .gt-chat se estira de top a bottom y centra a su
       hijo, subir el borde inferior mueve ese centro hacia arriba: así la
       pestaña no queda partida por la barra. */
    .gt-chat {
        bottom: 4.5rem;
    }

    /* A pantalla completa el panel del chat SÍ tapa la barra: es una vista
       propia, y dejar asomar la navegación por debajo se vería como un error.
       El botón de volver de su cabecera es la salida.

       Va con :has() en el body porque la clase gt-chat-abierto vive en
       #gt-chat, que es hermano POSTERIOR de la barra: un selector de
       descendiente no puede alcanzarla. Si el navegador no soporta :has(),
       simplemente no se oculta — el panel la tapa igual por z-index. */
    body:has(#gt-chat.gt-chat-abierto) .nx-tabbar {
        display: none;
    }

    @media (prefers-reduced-motion: reduce) {
        .nx-tab-panel {
            animation: none;
        }
    }
}

/* ==========================================================================
   Chatbot con contexto (Integración 4) — widget flotante
   ========================================================================== */
/* FORMA: no es la burbuja circular flotante de siempre. Es una PESTAÑA anclada
   al borde derecho que despliega un panel lateral de altura completa, como una
   libreta de entrenamiento que se abre al margen. Razón de uso: en el gimnasio
   se consulta de reojo, con una mano, sin tapar la pantalla en la que se está
   registrando la serie. */
.gt-chat {
    position: fixed;
    right: 0;
    top: 0;
    bottom: 0;
    z-index: 1050;
    display: flex;
    align-items: center;
    /* El contenedor no debe bloquear los clics de la página que hay detrás:
       solo sus hijos reales son interactivos. */
    pointer-events: none;
}

.gt-chat > * {
    pointer-events: auto;
}

/* ----- Pestaña lateral ----- */
/* Franja vertical pegada al borde. Ocupa ~2.4rem de ancho en vez de los 4.5rem
   de una burbuja redonda, y al ir centrada no choca con el botón de guardar de
   los formularios, que vive abajo a la derecha. */
.gt-chat-toggle {
    position: relative;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    width: 2.4rem;
    padding: 1.1rem 0;
    border: 1px solid var(--gt-border);
    border-right: none;
    border-radius: var(--gt-radius) 0 0 var(--gt-radius);
    background: var(--gt-surface);
    color: var(--gt-text-muted);
    cursor: pointer;
    box-shadow: var(--gt-shadow);
    transition: color var(--gt-dur) var(--gt-ease-out),
                background var(--gt-dur) var(--gt-ease-out),
                width var(--gt-dur) var(--gt-ease-emphasis);
}

.gt-chat-toggle:hover {
    background: var(--gt-accent);
    border-color: var(--gt-accent);
    color: #fff;
}

.gt-chat-toggle:focus-visible {
    outline: 2px solid var(--gt-accent);
    outline-offset: -4px;
}

/* Marca: dos discos y la barra, el isotipo reducido a su gesto mínimo. Es lo
   que identifica la pestaña sin necesidad de un icono de globo de diálogo,
   que es justamente lo que la haría parecer un chatbot más. */
.gt-chat-toggle-marca {
    width: 1rem;
    height: 0.5rem;
    flex: none;
    background:
        linear-gradient(var(--gt-accent), var(--gt-accent)) left center / 0.26rem 100% no-repeat,
        linear-gradient(var(--gt-accent), var(--gt-accent)) right center / 0.26rem 100% no-repeat,
        linear-gradient(var(--gt-accent), var(--gt-accent)) center / 100% 0.16rem no-repeat;
    transition: background-color var(--gt-dur) var(--gt-ease-out);
}

/* Al pasar el cursor la pestaña se vuelve roja, así que la marca pasa a blanco
   para no desaparecer sobre el acento. */
.gt-chat-toggle:hover .gt-chat-toggle-marca {
    background-image:
        linear-gradient(#fff, #fff),
        linear-gradient(#fff, #fff),
        linear-gradient(#fff, #fff);
}

/* Texto en vertical: es lo que permite que la pestaña sea una franja estrecha
   y aun así diga qué es, en vez de depender de un icono que hay que adivinar. */
.gt-chat-toggle-texto {
    writing-mode: vertical-rl;
    text-orientation: mixed;
    font-family: var(--gt-font-display);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* La ✕ de cerrar se dibuja con dos líneas: no depende de que la fuente del
   sistema tenga el glifo. */
.gt-chat-toggle-cerrar {
    display: none;
    position: relative;
    width: 0.85rem;
    height: 0.85rem;
    flex: none;
}

.gt-chat-toggle-cerrar::before,
.gt-chat-toggle-cerrar::after {
    content: "";
    position: absolute;
    inset: 50% 0 auto 0;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
}

.gt-chat-toggle-cerrar::before { transform: rotate(45deg); }
.gt-chat-toggle-cerrar::after  { transform: rotate(-45deg); }

/* Abierto: la pestaña se vuelve roja y cambia a la ✕. Sigue siendo el mismo
   botón en el mismo sitio, así que cerrar es donde la mano ya está. */
.gt-chat-abierto .gt-chat-toggle {
    background: var(--gt-accent);
    border-color: var(--gt-accent);
    color: #fff;
}

.gt-chat-abierto .gt-chat-toggle-marca,
.gt-chat-abierto .gt-chat-toggle-texto {
    display: none;
}

.gt-chat-abierto .gt-chat-toggle-cerrar {
    display: block;
}

/* ----- Panel ----- */
/* Columna de altura casi completa pegada al borde, no una tarjeta flotante.
   Se abre desde el lado con un desplazamiento propio. */
.gt-chat-panel {
    position: absolute;
    right: 2.4rem;
    top: 50%;
    transform: translateY(-50%);
    width: min(24rem, calc(100vw - 3.4rem));
    height: min(38rem, calc(100vh - 3rem));
    display: flex;
    flex-direction: column;
    background: var(--gt-surface);
    border: 1px solid var(--gt-border);
    border-right: none;
    border-radius: var(--gt-radius) 0 0 var(--gt-radius);
    box-shadow: var(--gt-shadow-hover);
    overflow: hidden;
}

/* La entrada se anima sólo cuando el panel deja de estar [hidden]; sin esto la
   animación correría también al ocultarlo y provocaría un parpadeo. */
.gt-chat-panel:not([hidden]) {
    animation: nx-chat-entrada var(--gt-dur-slow) var(--gt-ease-emphasis);
}

@keyframes nx-chat-entrada {
    from {
        opacity: 0;
        transform: translateY(-50%) translateX(1.5rem);
    }
    to {
        opacity: 1;
        transform: translateY(-50%) translateX(0);
    }
}

/* La cabecera va en rojo de marca: identifica el panel de un vistazo y lo
   separa del contenido de la página sin necesidad de una sombra pesada. */
.gt-chat-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.85rem 1rem;
    background: var(--gt-accent);
    color: #fff;
}

/* Volver. Oculto por defecto: sólo aparece en móvil (ver la media query del
   final), donde el panel tapa la página entera y hace falta una salida
   explícita. En escritorio la pestaña lateral ya cumple esa función. */
.gt-chat-volver {
    display: none;
    place-items: center;
    flex: none;
    width: 2rem;
    height: 2rem;
    margin-left: -0.25rem;
    background: none;
    border: none;
    border-radius: var(--gt-radius-sm);
    color: #fff;
    cursor: pointer;
    transition: background var(--gt-dur-fast) var(--gt-ease-out);
}

.gt-chat-volver:hover {
    background: rgba(255, 255, 255, 0.18);
}

.gt-chat-volver:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

.gt-chat-title {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    min-width: 0;
    /* Ocupa el espacio sobrante para que el botón de limpiar quede pegado a la
       derecha aunque el de volver aparezca o desaparezca. */
    margin-right: auto;
}

.gt-chat-title-texto {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
    font-family: var(--gt-font-display);
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

/* La segunda línea dice de qué puede hablar el asistente. Un usuario que abre
   el panel por primera vez no tiene por qué adivinar el alcance.

   Va en blanco PURO, no en blanco translúcido: medido, el blanco al 82% sobre
   #e10600 da 3.6:1, por debajo del 4.5:1 que exige AA en texto pequeño. El
   blanco sólido da 4.97:1. El matiz de jerarquía lo aportan el tamaño y el
   peso, no una opacidad que rompe el contraste. */
.gt-chat-title-sub {
    font-family: var(--gt-font-body);
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.01em;
    text-transform: none;
    color: #fff;
}

/* Punto de "en línea". Sobre el rojo, el verde de éxito se ensucia, así que
   aquí va en blanco: lo que comunica es actividad, no estado semántico. */
.gt-chat-dot {
    width: 0.5rem;
    height: 0.5rem;
    flex: none;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.25);
}

.gt-chat-iconbtn {
    display: grid;
    place-items: center;
    flex: none;
    width: 1.9rem;
    height: 1.9rem;
    background: rgba(255, 255, 255, 0.14);
    border: none;
    border-radius: var(--gt-radius-sm);
    color: #fff;
    cursor: pointer;
    transition: background var(--gt-dur-fast) var(--gt-ease-out);
}

.gt-chat-iconbtn:hover {
    background: rgba(255, 255, 255, 0.28);
}

.gt-chat-iconbtn:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

/* ----- Mensajes ----- */
.gt-chat-messages {
    flex: 1;
    overflow-y: auto;
    padding: 1rem 0.9rem;
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
    background: var(--gt-bg);
}

/* --nx-orden lo pone chat.js al cargar el historial para escalonar la entrada
   de los últimos mensajes. Vale 0 en los mensajes nuevos, que entran de
   inmediato: nadie debe esperar por lo que acaba de escribir.

   OJO: las reglas de abajo declaran la animación con propiedades LONGHAND
   (animation-name, animation-duration…) y no con el atajo `animation:`. El
   atajo reinicia animation-delay a 0s, y como estas reglas van después en la
   hoja y tienen la misma especificidad, borraría este escalonado sin avisar. */
.gt-msg {
    max-width: 88%;
    font-size: 0.9rem;
    line-height: 1.5;
    word-wrap: break-word;
    animation-delay: calc(var(--nx-orden, 0) * 45ms);
    animation-fill-mode: both;
}

/* ----- Mensaje del usuario -----
   Sí es una burbuja: es lo que dijo, un bloque cerrado. El rojo va en degradado
   sutil (dos tonos del propio acento, 12° de diferencia) para que la pieza tenga
   volumen en lugar de leerse como un rectángulo plano de color.

   La sombra usa el rojo, no negro: una sombra gris bajo una pieza saturada la
   ensucia; teñida del mismo tono, la burbuja parece apoyada sobre la página.

   El tope claro es #e81410 y no un rojo más vivo: medido, el blanco sobre
   #ef2a24 da 4.18:1, por debajo del 4.5:1 de AA, y el texto cae justo sobre esa
   esquina. Con #e81410 son 4.63:1 conservando el volumen. */
.gt-msg-usuario {
    align-self: flex-end;
    padding: 0.6rem 0.9rem;
    border-radius: 1.1rem 1.1rem 0.3rem 1.1rem;
    background: linear-gradient(160deg, #e81410 0%, var(--gt-accent) 55%, var(--gt-accent-dark) 100%);
    color: #fff;
    box-shadow: 0 2px 10px -3px rgba(225, 6, 0, 0.55);
    /* Entra desde el lado en el que vive: escribiste tú, a la derecha.
       Longhand a propósito (ver la nota en .gt-msg). */
    animation-name: nx-msg-usuario;
    animation-duration: var(--gt-dur);
    animation-timing-function: var(--gt-ease-out);
}

@keyframes nx-msg-usuario {
    from { opacity: 0; transform: translate3d(0.9rem, 0.3rem, 0) scale(0.96); }
    to   { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
}

/* ----- Respuesta del asistente -----
   NO es una burbuja: es texto a plena anchura sobre una superficie propia. El
   texto largo —que es lo que de verdad devuelve— se lee como texto y no como un
   globo de diálogo enorme, que es el gesto que hace que todos los chatbots se
   parezcan entre sí.

   La superficie blanca sobre el fondo hueso separa la respuesta del hilo sin
   encerrarla, y da sitio a que el guion rojo se dibuje dentro. */
.gt-msg-asistente {
    align-self: stretch;
    max-width: 100%;
    padding: 0.75rem 0.9rem;
    border-radius: 0.3rem 1.1rem 1.1rem 1.1rem;
    background: var(--gt-surface);
    color: var(--gt-text);
    box-shadow: 0 1px 2px rgba(22, 22, 26, 0.05),
                0 6px 16px -10px rgba(22, 22, 26, 0.35);
    /* Longhand a propósito (ver la nota en .gt-msg). */
    animation-name: nx-msg-asistente;
    animation-duration: var(--gt-dur-slow);
    animation-timing-function: var(--gt-ease-emphasis);
}

@keyframes nx-msg-asistente {
    from { opacity: 0; transform: translate3d(-0.6rem, 0.3rem, 0); }
    to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

/* Un guion rojo corto abre la respuesta, como la raya de diálogo de un libro.
   Es la marca de autoría más pequeña posible: identifica quién habla sin
   necesidad de avatar ni de nombre repetido en cada mensaje.

   Se dibuja creciendo desde la izquierda (scaleX, no width: no provoca
   reflow) justo después de que la respuesta aterrice. Es el detalle que hace
   que el mensaje se sienta escrito y no pegado. */
.gt-msg-asistente::before {
    content: "";
    display: block;
    width: 1.25rem;
    height: 2px;
    margin-bottom: 0.55rem;
    border-radius: 2px;
    background: var(--gt-accent);
    transform-origin: left center;
    animation: nx-msg-guion var(--gt-dur) var(--gt-ease-out) both;
    /* Espera a que su propio mensaje haya aterrizado: al escalonar el historial
       hay que sumar el retardo del mensaje, o el guion de los últimos se
       dibujaría antes de que la superficie llegue. */
    animation-delay: calc(var(--nx-orden, 0) * 45ms + 120ms);
}

@keyframes nx-msg-guion {
    from { transform: scaleX(0); opacity: 0; }
    to   { transform: scaleX(1); opacity: 1; }
}

/* ----- Formato Markdown dentro de las burbujas -----
   El asistente responde con negritas y listas. Sin estas reglas, las listas
   heredarían el sangrado enorme del navegador (40px) dentro de una burbuja que
   mide poco más de 20rem. */
.gt-msg-asistente ul,
.gt-msg-asistente ol {
    margin: 0.5rem 0;
    padding-left: 1.35rem;
}

.gt-msg-asistente li {
    margin-bottom: 0.3rem;
}

.gt-msg-asistente li:last-child {
    margin-bottom: 0;
}

.gt-msg-asistente strong {
    font-weight: 700;
}

.gt-msg-asistente code {
    padding: 0.1em 0.35em;
    border-radius: 0.3rem;
    background: rgba(28, 22, 18, 0.07);
    font-size: 0.9em;
}

/* Un <br> pegado a una lista dejaría un hueco doble: el margen de la lista ya
   separa lo suficiente. */
.gt-msg-asistente br + ul,
.gt-msg-asistente br + ol {
    margin-top: 0;
}

/* El error no lleva sombra ni degradado: comparte la forma de la respuesta del
   asistente (viene del mismo lado) pero en tinte de peligro, plano y mate, para
   que no compita con los mensajes reales. */
.gt-msg-error {
    align-self: flex-start;
    padding: 0.6rem 0.85rem;
    border-radius: 0.3rem 1.1rem 1.1rem 1.1rem;
    background: rgba(194, 17, 12, 0.08);
    color: var(--gt-danger);
    border: 1px solid rgba(194, 17, 12, 0.28);
    animation-name: nx-msg-asistente;
    animation-duration: var(--gt-dur);
    animation-timing-function: var(--gt-ease-out);
}

/* Indicador "escribiendo…". Comparte clase con las respuestas del asistente,
   así que hay que anular el guion (son puntos, no una respuesta empezada) y
   encogerlo: hereda el ancho completo, y una superficie de 20rem con tres
   puntitos dentro se ve vacía. */
.gt-typing {
    display: flex;
    gap: 0.3rem;
    align-items: center;
    align-self: flex-start;
    width: auto;
    padding: 0.7rem 0.9rem;
}

.gt-typing::before {
    display: none;
}

/* Ecualizador de barras en vez de los tres puntos de siempre. Las barras suben
   y bajan como las repeticiones de una serie: es el gesto propio de una app de
   gimnasio, y a la vez lee al instante como "está trabajando".

   Se anima scaleY y no height: escalar no provoca reflow, así que las cinco
   barras corren en la GPU aunque el hilo de mensajes sea largo. */
.gt-typing-barras {
    display: flex;
    align-items: center;
    gap: 0.2rem;
    /* Altura fija: al escalar desde el centro, la caja no cambia de tamaño y el
       hilo no da saltos mientras la animación corre. */
    height: 1.1rem;
}

.gt-typing-barras i {
    display: block;
    width: 0.22rem;
    height: 100%;
    border-radius: 0.2rem;
    background: var(--gt-accent);
    transform-origin: center;
    /* Arranca abajo para que la primera subida se vea entrar. */
    transform: scaleY(0.3);
    animation: nx-typing-serie 1s infinite var(--gt-ease-out);
}

/* Los retardos no son uniformes: con un paso constante las barras parecen una
   ola mecánica. Escalonados de forma irregular se leen como esfuerzo real. */
.gt-typing-barras i:nth-child(1) { animation-delay: 0s; }
.gt-typing-barras i:nth-child(2) { animation-delay: 0.12s; }
.gt-typing-barras i:nth-child(3) { animation-delay: 0.26s; }
.gt-typing-barras i:nth-child(4) { animation-delay: 0.16s; }
.gt-typing-barras i:nth-child(5) { animation-delay: 0.04s; }

@keyframes nx-typing-serie {
    0%, 100% {
        transform: scaleY(0.3);
        opacity: 0.55;
    }

    50% {
        transform: scaleY(1);
        opacity: 1;
    }
}

/* Sin movimiento: las barras se quedan quietas a media altura y sólo laten en
   opacidad, que sigue comunicando "esperando" sin desplazamiento. */
@media (prefers-reduced-motion: reduce) {
    .gt-typing-barras i {
        animation: nx-typing-latido 1.4s infinite var(--gt-ease-out);
        transform: scaleY(0.65);
    }

    @keyframes nx-typing-latido {
        0%, 100% { opacity: 0.4; }
        50%      { opacity: 1; }
    }
}

/* ----- Preguntas sugeridas ----- */
/* Fila que se desplaza en horizontal, no un envoltorio de varias líneas: así
   ocupa una altura fija y previsible por más sugerencias que haya, y el hilo
   de la conversación no pierde espacio.

   Se desplaza con el dedo (o con shift+rueda en escritorio). El degradado del
   borde derecho corta las píldoras a media altura y es lo que comunica que hay
   más contenido, en lugar de unas flechas que en móvil nadie acierta. */
.gt-chat-ideas {
    flex: none;
}

/* Botón "Ideas": pliega y despliega la fila. Sólo se muestra cuando ya hay
   conversación (lo decide chat.js con la clase de abajo); al abrir el panel por
   primera vez las sugerencias ya están a la vista y un botón para mostrarlas
   sería un clic de más. */
.gt-chat-ideas-btn {
    display: none;
    align-items: center;
    gap: 0.35rem;
    margin: 0.55rem 0.7rem 0;
    padding: 0.3rem 0.6rem;
    border: 1px solid var(--gt-text-dim);
    border-radius: 2rem;
    background: var(--gt-surface);
    color: var(--gt-text-muted);
    font-family: inherit;
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
    transition: color var(--gt-dur-fast) var(--gt-ease-out),
                border-color var(--gt-dur-fast) var(--gt-ease-out),
                background var(--gt-dur-fast) var(--gt-ease-out);
}

.gt-chat-ideas-plegable .gt-chat-ideas-btn {
    display: inline-flex;
}

.gt-chat-ideas-btn:hover {
    background: var(--gt-accent-soft);
    border-color: var(--gt-accent);
    color: var(--gt-accent-dark);
}

.gt-chat-ideas-btn:focus-visible {
    outline: 2px solid var(--gt-accent);
    outline-offset: 2px;
}

/* Chevron dibujado con bordes: gira 180° al desplegar, así el botón dice en qué
   estado está sin depender de un glifo de la fuente. */
.gt-chat-ideas-chevron {
    width: 0.4rem;
    height: 0.4rem;
    margin-left: 0.1rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: translateY(-0.1rem) rotate(45deg);
    transition: transform var(--gt-dur) var(--gt-ease-emphasis);
}

.gt-chat-ideas-btn[aria-expanded="true"] .gt-chat-ideas-chevron {
    transform: translateY(0.05rem) rotate(-135deg);
}

.gt-chat-sugerencias {
    position: relative;
    display: flex;
    gap: 0.4rem;
    flex: none;
    padding: 0.7rem 0.7rem 0;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    /* Se desvanece en el borde derecho: la última píldora visible se corta con
       un degradado, señal de que la fila continúa. */
    mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent);
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent);
}

.gt-chat-sugerencias::-webkit-scrollbar {
    display: none;
}

.gt-chat-sugerencias[hidden] {
    display: none;
}

/* El borde va en --gt-text-dim y no en --gt-border-strong: medido, el borde
   suave da 1.59:1 sobre blanco, por debajo del 3:1 que WCAG pide para el
   contorno de un control. Estas píldoras son botones, no separadores
   decorativos, así que su límite tiene que verse. */
.gt-chat-sugerencia {
    flex: none;
    scroll-snap-align: start;
    padding: 0.4rem 0.8rem;
    border: 1px solid var(--gt-text-dim);
    border-radius: 2rem;
    background: var(--gt-surface);
    color: var(--gt-text-muted);
    font-family: inherit;
    font-size: 0.8rem;
    line-height: 1.3;
    white-space: nowrap;
    cursor: pointer;
    transition: color var(--gt-dur-fast) var(--gt-ease-out),
                border-color var(--gt-dur-fast) var(--gt-ease-out),
                background var(--gt-dur-fast) var(--gt-ease-out);
}

.gt-chat-sugerencia:hover {
    background: var(--gt-accent-soft);
    border-color: var(--gt-accent);
    color: var(--gt-accent-dark);
}

.gt-chat-sugerencia:focus-visible {
    outline: 2px solid var(--gt-accent);
    outline-offset: 2px;
}

.gt-chat-sugerencia:active {
    transform: translateY(1px);
}

/* ----- Formulario de entrada ----- */
/* El campo y el botón forman una sola pieza enmarcada, en vez de dos controles
   sueltos separados por un hueco. El foco ilumina el conjunto (:focus-within),
   así que el objetivo de toque es toda la barra. */
.gt-chat-form {
    display: flex;
    align-items: flex-end;
    gap: 0.4rem;
    margin: 0.7rem;
    padding: 0.3rem 0.3rem 0.3rem 0.75rem;
    border: 1px solid var(--gt-border-strong);
    border-radius: var(--gt-radius);
    background: var(--gt-surface);
    transition: border-color var(--gt-dur-fast) var(--gt-ease-out),
                box-shadow var(--gt-dur-fast) var(--gt-ease-out);
}

/* El foco se marca con el anillo suave, NO con un borde rojo sólido: en esta
   app el rojo también señala error, y un campo de escritura con el contorno
   rojo se lee como "algo está mal" cuando en realidad sólo está activo. */
.gt-chat-form:focus-within {
    border-color: var(--gt-text-dim);
    box-shadow: 0 0 0 3px var(--gt-accent-ring);
}

.gt-chat-input {
    flex: 1;
    resize: none;
    max-height: 120px;
    padding: 0.45rem 0;
    background: none;
    border: none;
    color: var(--gt-text);
    font-family: inherit;
    font-size: 0.9rem;
    line-height: 1.4;
}

/* El anillo lo pinta el contenedor, así que el textarea no lleva outline
   propio: dos anillos concéntricos se verían como un error de estilo. */
.gt-chat-input:focus {
    outline: none;
}

.gt-chat-input::placeholder {
    color: var(--gt-text-dim);
}

.gt-chat-send {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 2.2rem;
    height: 2.2rem;
    border-radius: calc(var(--gt-radius) - 0.25rem);
    border: none;
    background: var(--gt-accent);
    color: #fff;
    cursor: pointer;
    transition: background var(--gt-dur-fast) var(--gt-ease-out),
                transform var(--gt-dur-fast) var(--gt-ease-out);
}

.gt-chat-send:hover:not(:disabled) {
    background: var(--gt-accent-dark);
    transform: translateX(1px);
}

.gt-chat-send:focus-visible {
    outline: 2px solid var(--gt-accent);
    outline-offset: 2px;
}

.gt-chat-send:disabled {
    opacity: 0.45;
    cursor: default;
}

/* ----- Móvil ----- */
/* En pantallas estrechas el panel ocupa todo el ancho: una columna de 24rem
   dejaría una franja inútil, y el teclado ya se come media pantalla. */
@media (max-width: 30rem) {
    .gt-chat-panel {
        position: fixed;
        inset: 0 0 0 auto;
        width: 100vw;
        height: 100dvh;
        max-height: none;
        border: none;
        border-radius: 0;
        transform: none;
    }

    .gt-chat-panel:not([hidden]) {
        animation: nx-chat-entrada-movil var(--gt-dur-slow) var(--gt-ease-emphasis);
    }

    @keyframes nx-chat-entrada-movil {
        from { opacity: 0; transform: translateX(2rem); }
        to   { opacity: 1; transform: translateX(0); }
    }

    /* La pestaña se oculta mientras el panel está abierto: a pantalla completa
       taparía el texto. La salida pasa a ser el botón de volver. */
    .gt-chat-abierto .gt-chat-toggle {
        display: none;
    }

    /* Aquí sí: el panel cubre la página, así que hace falta una salida
       explícita y en el sitio donde se espera, arriba a la izquierda. */
    .gt-chat-volver {
        display: grid;
    }
}

/* Quien pide menos movimiento conserva el panel y los mensajes, pero sin
   desplazamientos: aparecen y ya. El guion del asistente se deja dibujado
   (scaleX(1)); si sólo se anulara la animación quedaría en su estado inicial,
   es decir invisible. */
@media (prefers-reduced-motion: reduce) {
    .gt-chat-panel:not([hidden]),
    .gt-msg,
    .gt-msg-usuario,
    .gt-msg-asistente,
    .gt-msg-error {
        animation: none;
    }

    .gt-msg-asistente::before {
        animation: none;
        transform: scaleX(1);
        opacity: 1;
    }
}


/* ==========================================================================
   Pantalla de carga (Lottie)
   Overlay a pantalla completa con la animación del logo. Se muestra en cada
   carga de página y hace fade-out cuando el DOM está listo (lógica en site.js).
   ========================================================================== */
/* Fondo rojo de marca: la pantalla de carga es el único momento en que el
   usuario ve la identidad a pantalla completa, igual que el logotipo (blanco
   sobre rojo). El color va aquí y NO dentro del archivo de la animación, para
   no cargar un fondo rasterizado de varios megabytes sólo para pintar un
   rectángulo de un color plano. */
.gt-loader {
    position: fixed;
    inset: 0;
    z-index: 2000; /* por encima de todo, incluida la burbuja del chat (1000) */
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--gt-accent);
    opacity: 1;
    transition: opacity var(--gt-dur-slow) var(--gt-ease-out);
}

    /* Estado oculto: se desvanece y deja de capturar clics. */
    .gt-loader.gt-loader-hidden {
        opacity: 0;
        pointer-events: none;
    }

/* La animación del logo viene en un lienzo de 1920×1080 (16:9), así que el
   contenedor respeta esa proporción: en un cuadrado, el logo quedaría diminuto
   con franjas vacías arriba y abajo. */
.gt-loader-anim {
    width: min(560px, 82vw);
    aspect-ratio: 16 / 9;
}

/* Accesibilidad: si el usuario pide menos movimiento, no reproducimos la
   animación ni el fade; el overlay se retira de inmediato desde site.js. */
@media (prefers-reduced-motion: reduce) {
    .gt-loader {
        transition: none;
    }
}

/* ==========================================================================
   NovuxTracker — Componentes del rediseño (prefijo nx-)
   El prefijo distingue lo nuevo de lo heredado (gt-), que sigue en uso donde
   ya funcionaba. No es un sistema paralelo: consume los mismos tokens --gt-*.
   ========================================================================== */

/* ===== Panel de inicio (usuario con historial) ===== */

.nx-panel {
    margin-bottom: 2.5rem;
}

/* La línea de contexto va ARRIBA de la acción: primero "dónde estoy", luego
   "qué hago". Al revés, el botón no significa nada. */
.nx-panel-contexto {
    font-size: 1.05rem;
    color: var(--gt-text-muted);
    margin-bottom: 1rem;
}

.nx-panel-contexto strong {
    color: var(--gt-text);
    font-weight: 600;
}

/* ----- La acción dominante -----
   Una sola por pantalla. Alta (mínimo 96px), a todo el ancho y roja: pensada
   para acertarle con el pulgar, de pie, sin mirar con detenimiento. */
.nx-cta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    min-height: 6rem;
    padding: 1.5rem 1.75rem;
    border-radius: var(--gt-radius);
    background: var(--gt-accent);
    color: #fff;
    text-decoration: none;
    box-shadow: 0 2px 4px rgba(225, 6, 0, 0.12), 0 10px 24px rgba(225, 6, 0, 0.18);
    transition: transform var(--gt-dur) var(--gt-ease-out),
                box-shadow var(--gt-dur) var(--gt-ease-out),
                background-color var(--gt-dur-fast) var(--gt-ease-out);
}

.nx-cta:hover {
    background: var(--gt-accent-dark);
    color: #fff;
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(225, 6, 0, 0.16), 0 16px 34px rgba(225, 6, 0, 0.24);
}

.nx-cta:active {
    transform: translateY(0);
    transition-duration: var(--gt-dur-fast);
}

/* Agrupa título y descripción para que la flecha quede al extremo opuesto sin
   que el texto se estire. */
.nx-cta-contenido {
    min-width: 0;
}

.nx-cta-titulo {
    display: block;
    font-family: var(--gt-font-display);
    font-size: 2.25rem;
    font-weight: 700;
    text-transform: uppercase;
    line-height: 1;
    letter-spacing: 0.01em;
}

.nx-cta-desc {
    display: block;
    margin-top: 0.35rem;
    font-size: 0.95rem;
    color: rgba(255, 255, 255, 0.85);
}

.nx-cta-flecha {
    flex-shrink: 0;
    width: 2rem;
    height: 2rem;
    transition: transform var(--gt-dur) var(--gt-ease-emphasis);
}

.nx-cta:hover .nx-cta-flecha {
    transform: translateX(5px);
}

/* ----- Cifras de resumen -----
   Sin tarjetas: la separación la dan el espacio y una línea divisoria. Tres
   tarjetas idénticas en fila son el cliché de dashboard de plantilla. */
.nx-cifras {
    display: flex;
    flex-wrap: wrap;
    gap: 2.5rem;
    margin-top: 1.75rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--gt-border);
}

.nx-cifra {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.nx-cifra-valor {
    font-family: var(--gt-font-display);
    font-size: 2.5rem;
    font-weight: 700;
    line-height: 1;
    color: var(--gt-text);
    font-variant-numeric: tabular-nums;
}

.nx-cifra-valor-vacio {
    color: var(--gt-text-dim);
}

.nx-cifra-unidad {
    font-size: 1.1rem;
    color: var(--gt-text-muted);
    margin-left: 0.15rem;
}

.nx-cifra-label {
    font-size: 0.85rem;
    color: var(--gt-text-muted);
}

.nx-cifra-vacia {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    color: inherit;
}

.nx-cifra-vacia:hover .nx-cifra-label {
    color: var(--gt-accent);
}

/* El cambio de peso: el dato que convierte una cifra en información. Va en
   tinta neutra a propósito — ni subir ni bajar es "bueno" por sí mismo, eso
   depende del objetivo de cada persona, y colorearlo sería juzgar. */
.nx-delta {
    display: inline-block;
    margin-left: 0.4rem;
    padding: 0.1em 0.45em;
    border-radius: var(--gt-radius-pill);
    background: var(--gt-surface-2);
    border: 1px solid var(--gt-border);
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--gt-text);
    font-variant-numeric: tabular-nums;
}

/* ===== Pantalla de arranque (usuario sin sesiones) ===== */

.nx-arranque {
    margin-bottom: 2.5rem;
}

/* En el arranque el contenido va alineado a la izquierda, no centrado como en
   los estados vacíos. */
.nx-arranque .nx-isotipo {
    margin-left: 0;
    margin-bottom: 0.75rem;
}

.nx-arranque-titulo {
    font-family: var(--gt-font-display);
    font-size: 2rem;
    font-weight: 700;
    text-transform: uppercase;
    line-height: 1;
    margin-bottom: 0.6rem;
}

.nx-arranque-texto {
    color: var(--gt-text-muted);
    max-width: 58ch;
    margin-bottom: 1.75rem;
}

.nx-arranque-pasos {
    display: grid;
    gap: 0.75rem;
}

/* Los pasos se numeran porque SON una secuencia real: sin ejercicios no hay
   rutina, y sin rutina no hay sesión. El número informa el orden, no decora. */
.nx-paso {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.1rem 1.25rem;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background: var(--gt-surface);
    color: var(--gt-text);
    text-decoration: none;
    transition: border-color var(--gt-dur) var(--gt-ease-out),
                transform var(--gt-dur) var(--gt-ease-out),
                box-shadow var(--gt-dur) var(--gt-ease-out);
}

.nx-paso:hover {
    border-color: var(--gt-accent);
    color: var(--gt-text);
    transform: translateX(3px);
    box-shadow: var(--gt-shadow);
}

.nx-paso-num {
    flex-shrink: 0;
    display: grid;
    place-items: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background: var(--gt-accent);
    color: #fff;
    font-family: var(--gt-font-display);
    font-size: 1.15rem;
    font-weight: 700;
}

/* Paso ya completado: el número pierde el rojo y se vuelve neutro. El rojo se
   reserva para lo que falta hacer. */
.nx-paso-hecho .nx-paso-num {
    background: var(--gt-surface-2);
    color: var(--gt-text-dim);
    border: 1px solid var(--gt-border);
}

.nx-paso-texto {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    font-size: 0.9rem;
    color: var(--gt-text-muted);
}

.nx-paso-texto strong {
    font-size: 1rem;
    font-weight: 600;
    color: var(--gt-text);
}

/* ===== Navegación de secciones =====
   Fila compacta en vez de cuatro tarjetas idénticas: la navegación es
   secundaria frente a la acción de entrenar y no debe competir con ella. */
.nx-secciones {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
    gap: 0.5rem;
    margin-bottom: 2rem;
}

.nx-seccion {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    /* 44px de alto mínimo (aquí muy por encima): objetivo de toque cómodo. */
    min-height: 5.5rem;
    padding: 1rem 0.5rem;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius-sm);
    background: var(--gt-surface);
    color: var(--gt-text-muted);
    font-size: 0.85rem;
    font-weight: 600;
    text-align: center;
    text-decoration: none;
    transition: color var(--gt-dur-fast) var(--gt-ease-out),
                border-color var(--gt-dur-fast) var(--gt-ease-out),
                background-color var(--gt-dur-fast) var(--gt-ease-out);
}

.nx-seccion svg {
    width: 22px;
    height: 22px;
    color: var(--gt-text-dim);
    transition: color var(--gt-dur-fast) var(--gt-ease-out);
}

.nx-seccion:hover {
    color: var(--gt-text);
    border-color: var(--gt-border-strong);
    background: var(--gt-surface-2);
}

.nx-seccion:hover svg {
    color: var(--gt-accent);
}

/* ===== Portada pública: los tres pasos ===== */

.nx-como {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: 2rem;
}

.nx-como-paso h2 {
    font-family: var(--gt-font-display);
    font-size: 1.4rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    margin: 0.6rem 0 0.5rem;
}

.nx-como-paso p {
    color: var(--gt-text-muted);
    margin: 0;
    font-size: 0.95rem;
}

.nx-como-num {
    display: block;
    font-family: var(--gt-font-display);
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1;
    color: var(--gt-accent);
}

/* ===== Pantalla de error ===== */

.nx-error {
    max-width: 34rem;
    margin: 4rem auto;
    text-align: center;
}

.nx-error-codigo {
    display: inline-block;
    font-family: var(--gt-font-display);
    font-size: 0.85rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--gt-accent);
    margin-bottom: 0.75rem;
}

.nx-error-titulo {
    font-family: var(--gt-font-display);
    font-size: 2rem;
    font-weight: 700;
    text-transform: uppercase;
    line-height: 1.05;
    margin-bottom: 0.75rem;
}

.nx-error-texto {
    color: var(--gt-text-muted);
    margin-bottom: 1.75rem;
}

.nx-error-acciones {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    justify-content: center;
}

.nx-error-id {
    margin-top: 2.5rem;
    font-size: 0.82rem;
    color: var(--gt-text-dim);
}

.nx-error-id code {
    color: var(--gt-text-muted);
    background: var(--gt-surface-2);
    border: 1px solid var(--gt-border);
    border-radius: 0.35rem;
    padding: 0.1em 0.4em;
    font-size: 0.95em;
}

/* ===== Isotipo animado (Lottie) en estados vacíos =====
   Las animaciones vienen en un lienzo de 1920×1080 con el dibujo centrado al
   35% de escala, así que hay mucho aire alrededor. En vez de pedir un
   reexportado con otro encuadre, se recorta aquí: el contenedor declara la
   proporción 16:9 y se escala el SVG para que el dibujo llene el espacio.
   Resultado: el isotipo se ve grande sin franjas vacías. */
.nx-isotipo {
    width: min(15rem, 60vw);
    aspect-ratio: 16 / 9;
    margin: 0 auto 0.5rem;
    /* El recorte evita que el escalado desborde sobre el texto de al lado. */
    overflow: hidden;
    display: grid;
    place-items: center;
}

.nx-isotipo svg {
    /* 1.9 compensa el 35% de escala del archivo: el dibujo ocupa poco más de un
       tercio del lienzo, y así llena la caja sin recortarse. */
    transform: scale(1.9);
    transform-origin: center;
}

/* ----- Movimiento añadido desde CSS -----
   Los archivos Lottie traen poca animación propia: el isotipo de rutinas es
   una imagen completamente estática, y los otros dos sólo varían opacidad o
   escala interna. Aquí se les da vida sin tocar los archivos del diseñador.

   El movimiento se aplica al CONTENEDOR, no al SVG interno, para no pisar el
   scale(1.9) que corrige el encuadre. Son transformaciones compuestas sobre
   una capa ya escalada, así que corren en el compositor sin provocar reflow. */
.nx-isotipo[data-animacion="isotipo-rutinas"] svg {
    /* Balanceo suave: el muñeco no puede "correr" porque el dibujo viene
       aplanado en una sola capa, pero un vaivén leve lo saca de la rigidez.
       Rotación mínima y origen en la base, como un cuerpo que se mece. */
    animation: nx-balanceo 3.2s var(--gt-ease-out) infinite;
    transform-origin: 50% 70%;
}

@keyframes nx-balanceo {
    0%, 100% { transform: scale(1.9) rotate(-1.5deg) translateY(0); }
    50%      { transform: scale(1.9) rotate(1.5deg) translateY(-2%); }
}

.nx-isotipo[data-animacion="isotipo-progreso"] svg {
    /* La gráfica "respira" hacia arriba: acompaña la idea de progreso que
       sube, reforzando lo que el dibujo ya representa. */
    animation: nx-subir 2.8s var(--gt-ease-out) infinite;
}

@keyframes nx-subir {
    0%, 100% { transform: scale(1.9) translateY(1.5%); }
    50%      { transform: scale(1.9) translateY(-1.5%); }
}

.nx-isotipo[data-animacion="isotipo-mancuerna"] svg {
    /* Latido corto y con pausa larga: llama la atención una vez y se calma,
       en vez de pulsar sin parar como un elemento que pide clic. */
    animation: nx-latido 4s var(--gt-ease-out) infinite;
}

@keyframes nx-latido {
    0%, 70%, 100% { transform: scale(1.9); }
    80%           { transform: scale(2); }
    90%           { transform: scale(1.87); }
}

/* Con movimiento reducido, los isotipos se quedan quietos: el dibujo sigue
   comunicando, sin animación. */
@media (prefers-reduced-motion: reduce) {
    .nx-isotipo svg {
        animation: none !important;
        transform: scale(1.9) !important;
    }
}

/* ===== Estado vacío (sin resultados) ===== */

.nx-vacio {
    text-align: center;
    padding: 3rem 1.5rem 4rem;
}

.nx-vacio-titulo {
    font-family: var(--gt-font-display);
    font-size: 1.5rem;
    font-weight: 700;
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

.nx-vacio-texto {
    color: var(--gt-text-muted);
    max-width: 42ch;
    margin: 0 auto;
}

/* ===== Esqueletos de carga =====
   Ocupan el mismo espacio que el contenido real, así la página no salta al
   llegar los datos. Preferidos a un spinner centrado: comunican QUÉ está
   cargando, no sólo que algo pasa. */
.nx-cargando {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 1rem;
}

/* Ante un fallo de red el JS sustituye el contenido por un texto plano. Sin
   esto, ese texto quedaría como una celda del grid, desalineado a la izquierda
   en una columna estrecha. */
.nx-cargando:not(:has(.nx-skeleton-card)) {
    display: block;
    text-align: center;
    padding: 3rem 1rem;
    color: var(--gt-text-muted);
}

.nx-skeleton-card {
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background: var(--gt-surface);
    padding: 0.85rem;
    overflow: hidden;
}

.nx-skeleton-img,
.nx-skeleton-linea {
    background: var(--gt-surface-2);
    border-radius: var(--gt-radius-sm);
    position: relative;
    overflow: hidden;
}

.nx-skeleton-img {
    aspect-ratio: 4 / 3;
    margin-bottom: 0.75rem;
}

.nx-skeleton-linea {
    height: 0.85rem;
    margin-bottom: 0.5rem;
}

.nx-skeleton-linea-corta {
    width: 55%;
    margin-bottom: 0;
}

/* El brillo que recorre el esqueleto se hace con un pseudo-elemento que se
   desplaza por transform: no se anima background-position (que fuerza repintado
   en cada cuadro) ni ninguna propiedad de layout. */
.nx-skeleton-img::after,
.nx-skeleton-linea::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.65), transparent);
    transform: translateX(-100%);
    animation: nx-shimmer 1.4s var(--gt-ease-out) infinite;
}

@keyframes nx-shimmer {
    to {
        transform: translateX(100%);
    }
}

/* Con movimiento reducido el esqueleto se queda quieto: sigue comunicando la
   forma de lo que viene, sin animación. */
@media (prefers-reduced-motion: reduce) {
    .nx-skeleton-img::after,
    .nx-skeleton-linea::after {
        animation: none;
    }
}

/* ===== Tarjetas de rutina =====
   Cada tarjeta es una unidad de decisión: dice qué grupos trabaja y qué tan
   larga es la sesión, para poder elegir sin entrar al detalle. */
.nx-rutinas {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
    gap: 1rem;
}

.nx-rutina {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background: var(--gt-surface);
    overflow: hidden;
    transition: border-color var(--gt-dur) var(--gt-ease-out),
                box-shadow var(--gt-dur) var(--gt-ease-out),
                transform var(--gt-dur) var(--gt-ease-out);
}

.nx-rutina:hover {
    border-color: var(--gt-border-strong);
    box-shadow: var(--gt-shadow);
    transform: translateY(-2px);
}

/* El cuerpo entero es el enlace al detalle: superficie de clic grande, no un
   botón diminuto de "ver". */
.nx-rutina-principal {
    flex: 1;
    display: block;
    padding: 1.25rem 1.25rem 1rem;
    color: var(--gt-text);
}

.nx-rutina-principal:hover {
    color: var(--gt-text);
}

.nx-rutina-nombre {
    font-family: var(--gt-font-display);
    font-size: 1.5rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    line-height: 1.1;
    margin-bottom: 0.6rem;
}

.nx-rutina:hover .nx-rutina-nombre {
    color: var(--gt-accent);
}

.nx-rutina-grupos {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    margin-bottom: 0.75rem;
}

.nx-rutina-cuenta {
    font-size: 0.9rem;
    color: var(--gt-text-muted);
    margin-bottom: 0.4rem;
}

.nx-rutina-cuenta strong {
    color: var(--gt-text);
    font-variant-numeric: tabular-nums;
}

.nx-sep {
    margin: 0 0.4rem;
    color: var(--gt-border-strong);
}

/* Una rutina sin ejercicios no se puede entrenar: se avisa en la tarjeta en
   vez de dejar que la persona lo descubra al intentar iniciarla. */
.nx-rutina-alerta {
    color: var(--gt-warning);
    font-weight: 600;
}

.nx-rutina-desc {
    font-size: 0.9rem;
    color: var(--gt-text-muted);
    margin: 0;
    /* Se recorta a dos líneas para que todas las tarjetas midan parecido sin
       imponer una altura fija que corte el texto a media palabra. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.nx-rutina-pie {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.75rem 1.25rem;
    border-top: 1px solid var(--gt-border);
    background: var(--gt-surface-2);
}

/* Botón de entrenar dentro de la tarjeta. Es un <button> real dentro de un
   <form> POST: iniciar una sesión modifica datos, así que no puede ser un
   enlace. Se estiliza para leerse como acción principal de la tarjeta. */
.nx-rutina-entrenar {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    /* 44px de alto: objetivo de toque cómodo con el pulgar. */
    min-height: 2.75rem;
    padding: 0.5rem 1.1rem;
    border: none;
    border-radius: var(--gt-radius-sm);
    background: var(--gt-accent);
    color: #fff;
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color var(--gt-dur-fast) var(--gt-ease-out),
                box-shadow var(--gt-dur) var(--gt-ease-out);
}

.nx-rutina-entrenar svg {
    width: 16px;
    height: 16px;
    transition: transform var(--gt-dur) var(--gt-ease-emphasis);
}

.nx-rutina-entrenar:hover {
    background: var(--gt-accent-dark);
    box-shadow: 0 3px 10px rgba(225, 6, 0, 0.25);
}

.nx-rutina-entrenar:hover svg {
    transform: translateX(3px);
}

.nx-rutina-entrenar:active {
    transform: translateY(1px);
}

/* ===== Resumen de rutina + acción de entrenar =====
   Las cifras describen la sesión que está por empezar, y el botón vive junto a
   ellas: es la relación causa-efecto que hace que el botón signifique algo. */
.nx-resumen {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
    padding: 1.5rem;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background: var(--gt-surface);
    margin-bottom: 2rem;
}

.nx-resumen-cifras {
    display: flex;
    flex-wrap: wrap;
    gap: 2.5rem;
}

.nx-resumen-cta {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 3rem;
    padding: 0.75rem 1.5rem;
    border: none;
    border-radius: var(--gt-radius-sm);
    background: var(--gt-accent);
    color: #fff;
    font-family: inherit;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color var(--gt-dur-fast) var(--gt-ease-out),
                box-shadow var(--gt-dur) var(--gt-ease-out),
                transform var(--gt-dur-fast) var(--gt-ease-out);
}

.nx-resumen-cta svg {
    width: 18px;
    height: 18px;
    transition: transform var(--gt-dur) var(--gt-ease-emphasis);
}

.nx-resumen-cta:hover {
    background: var(--gt-accent-dark);
    box-shadow: 0 4px 14px rgba(225, 6, 0, 0.28);
}

.nx-resumen-cta:hover svg {
    transform: translateX(3px);
}

.nx-resumen-cta:active {
    transform: translateY(1px);
}

/* ===== Lista de ejercicios de una rutina =====
   Lista en vez de tabla: la meta se lee como frase ("3 × 10 con 40 kg") en
   lugar de obligar a cruzar celdas con el encabezado. */
.nx-ejercicios-lista {
    list-style: none;
    padding: 0;
    margin: 0;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background: var(--gt-surface);
    overflow: hidden;
}

.nx-ejercicio-fila {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    padding: 0.85rem 1.1rem;
    border-bottom: 1px solid var(--gt-border);
    transition: background-color var(--gt-dur-fast) var(--gt-ease-out);
}

.nx-ejercicio-fila:last-child {
    border-bottom: none;
}

.nx-ejercicio-fila:hover {
    background: var(--gt-surface-2);
}

.nx-ejercicio-orden {
    flex-shrink: 0;
    width: 1.5rem;
    font-family: var(--gt-font-display);
    font-size: 1rem;
    font-weight: 700;
    color: var(--gt-text-dim);
    font-variant-numeric: tabular-nums;
}

.nx-ejercicio-datos {
    flex: 1;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}

.nx-ejercicio-nombre {
    font-weight: 600;
}

/* La meta alineada a la derecha y en cifras tabulares: así los números quedan
   en columna aunque cada ejercicio tenga valores de distinto ancho. */
.nx-ejercicio-meta {
    flex-shrink: 0;
    display: flex;
    align-items: baseline;
    gap: 0.3rem;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.nx-ejercicio-meta strong {
    font-family: var(--gt-font-display);
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1;
}

.nx-x {
    color: var(--gt-text-dim);
    font-size: 0.9rem;
}

.nx-meta-peso {
    margin-left: 0.4rem;
    font-size: 0.85rem;
    color: var(--gt-text-muted);
}

/* Nota explicativa: texto de apoyo que enseña cómo funciona la app. Discreto,
   pero presente donde surge la duda. */
.nx-nota {
    margin-top: 1rem;
    padding-left: 0.9rem;
    border-left: 2px solid var(--gt-border-strong);
    font-size: 0.88rem;
    color: var(--gt-text-muted);
    max-width: 68ch;
}

@media (max-width: 575.98px) {
    /* En móvil la meta baja a su propia línea: en 360px de ancho, nombre y
       cifras en la misma fila se aplastan. */
    .nx-ejercicio-fila {
        flex-wrap: wrap;
    }

    .nx-ejercicio-meta {
        width: 100%;
        padding-left: 2.35rem;
        justify-content: flex-start;
    }

    .nx-resumen {
        flex-direction: column;
        align-items: stretch;
    }

    .nx-resumen-cta {
        justify-content: center;
    }
}

/* ===== Páginas de formulario =====
   Ancho acotado a una medida de lectura cómoda. Sin tarjeta que envuelva el
   formulario: sobre fondo claro los campos ya se distinguen solos y una caja
   alrededor sólo añade un borde más. */
.nx-form-pagina {
    max-width: 38rem;
    margin: 1.5rem auto 0;
    padding: 0 1rem;
}

.nx-form {
    margin-top: 1.5rem;
}

.nx-campo {
    margin-bottom: 1.35rem;
}

.nx-campo .form-label {
    display: block;
    font-weight: 600;
    font-size: 0.9rem;
    margin-bottom: 0.35rem;
}

/* Texto de ayuda bajo el campo: explica sin condescender, una sola vez. */
.nx-ayuda {
    display: block;
    margin-top: 0.35rem;
    font-size: 0.82rem;
    color: var(--gt-text-muted);
}

/* El error de validación sólo ocupa espacio cuando existe: con :empty no se
   reserva un hueco vacío bajo cada campo, que descuadraría el ritmo vertical. */
.nx-error {
    display: block;
    margin-top: 0.35rem;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--gt-danger);
}

.nx-error:empty {
    display: none;
}

/* La acción primaria va PRIMERO en el orden de lectura y de tabulación. El
   cancelar es un enlace, no un botón: no compite visualmente con guardar. */
.nx-form-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--gt-border);
}

.nx-parrafo {
    color: var(--gt-text);
    max-width: 68ch;
}

/* ===== Filtros de segmento (grupo muscular) ===== */

.nx-filtros {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 1.5rem;
}

.nx-filtro {
    /* 2.5rem de alto: cómodo para tocar con el pulgar. */
    display: inline-flex;
    align-items: center;
    min-height: 2.5rem;
    padding: 0.4rem 0.9rem;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius-pill);
    background: var(--gt-surface);
    color: var(--gt-text-muted);
    font-size: 0.88rem;
    font-weight: 600;
    transition: color var(--gt-dur-fast) var(--gt-ease-out),
                border-color var(--gt-dur-fast) var(--gt-ease-out),
                background-color var(--gt-dur-fast) var(--gt-ease-out);
}

.nx-filtro:hover {
    color: var(--gt-text);
    border-color: var(--gt-border-strong);
}

.nx-filtro-activo,
.nx-filtro-activo:hover {
    background: var(--gt-accent);
    border-color: var(--gt-accent);
    color: #fff;
}

/* ===== Lista genérica de registros =====
   Sustituye a las tablas en pantallas de listado: una tabla de cuatro columnas
   obliga a desplazarse en horizontal en un teléfono, que es el dispositivo real
   de uso. */
.nx-lista {
    list-style: none;
    padding: 0;
    margin: 0;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background: var(--gt-surface);
    overflow: hidden;
}

.nx-lista-fila {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    padding: 0.85rem 1.1rem;
    border-bottom: 1px solid var(--gt-border);
    transition: background-color var(--gt-dur-fast) var(--gt-ease-out);
}

.nx-lista-fila:last-child {
    border-bottom: none;
}

.nx-lista-fila:hover {
    background: var(--gt-surface-2);
}

.nx-lista-principal {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    color: var(--gt-text);
}

.nx-lista-fila:hover .nx-lista-titulo {
    color: var(--gt-accent);
}

.nx-lista-titulo {
    font-weight: 600;
    transition: color var(--gt-dur-fast) var(--gt-ease-out);
}

.nx-lista-desc {
    font-size: 0.85rem;
    color: var(--gt-text-muted);
    /* Una línea: el detalle completo está a un clic. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Lista simple sin caja (enumeraciones dentro de un texto). */
.nx-lista-simple {
    margin: 0 0 1.5rem;
    padding-left: 1.2rem;
    color: var(--gt-text);
}

.nx-lista-simple li {
    margin-bottom: 0.3rem;
    font-weight: 600;
}

@media (max-width: 575.98px) {
    /* En pantalla estrecha el chip de grupo baja a su propia línea para que el
       nombre del ejercicio conserve ancho legible. */
    .nx-lista-fila {
        flex-wrap: wrap;
    }

    .nx-lista-principal {
        flex-basis: 100%;
    }
}

/* ===== Mediciones ===== */

/* Peso y fecha lado a lado: son los dos únicos campos que casi todo el mundo
   llena. El resto vive plegado. */
.nx-medidas-basicas {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}

@media (max-width: 480px) {
    .nx-medidas-basicas {
        grid-template-columns: 1fr;
        gap: 0;
    }
}

/* El peso es el dato principal de la pantalla: se escribe en grande. */
.nx-input-grande {
    font-family: var(--gt-font-display);
    font-size: 1.6rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* ----- Secciones plegables -----
   Doce campos opcionales visibles sugieren que hay que llenarlos todos. Con
   <details> nativo: funciona sin JavaScript y es accesible por defecto. */
.nx-plegable {
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background: var(--gt-surface);
    margin-bottom: 1rem;
}

.nx-plegable-cab {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.85rem 1.1rem;
    cursor: pointer;
    list-style: none;
    border-radius: var(--gt-radius);
    transition: background-color var(--gt-dur-fast) var(--gt-ease-out);
}

.nx-plegable-cab:hover {
    background: var(--gt-surface-2);
}

/* Se oculta el triángulo por defecto del navegador para dibujar el propio. */
.nx-plegable-cab::-webkit-details-marker {
    display: none;
}

.nx-plegable-cab::after {
    content: "";
    margin-left: auto;
    width: 0.55rem;
    height: 0.55rem;
    border-right: 2px solid var(--gt-text-dim);
    border-bottom: 2px solid var(--gt-text-dim);
    transform: rotate(45deg) translate(-0.15rem, -0.15rem);
    transition: transform var(--gt-dur) var(--gt-ease-out);
}

.nx-plegable[open] .nx-plegable-cab::after {
    transform: rotate(-135deg) translate(-0.15rem, -0.15rem);
}

.nx-plegable-titulo {
    font-weight: 600;
}

.nx-plegable-nota {
    font-size: 0.82rem;
    color: var(--gt-text-muted);
}

.nx-plegable-cuerpo {
    padding: 0 1.1rem 1.1rem;
    border-top: 1px solid var(--gt-border);
    padding-top: 1.1rem;
}

.nx-rejilla-campos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: 0.85rem;
}

.nx-rejilla-campos .nx-campo {
    margin-bottom: 0;
}

/* ----- Listado de mediciones ----- */
.nx-medicion-peso {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.2rem;
}

.nx-medicion-valor {
    font-family: var(--gt-font-display);
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.nx-medicion-unidad {
    font-size: 0.75rem;
    color: var(--gt-text-muted);
    margin-left: 0.1rem;
}

/* ----- Detalle: el peso destacado ----- */
.nx-peso-destacado {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    padding: 1.25rem 0 1.5rem;
    border-bottom: 1px solid var(--gt-border);
    margin-bottom: 1.5rem;
}

.nx-peso-valor {
    font-family: var(--gt-font-display);
    font-size: 3rem;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.nx-peso-unidad {
    font-size: 1.25rem;
    color: var(--gt-text-muted);
    margin-left: 0.2rem;
}

.nx-peso-label {
    font-size: 0.85rem;
    color: var(--gt-text-muted);
}

/* Rejilla de datos: sólo aparecen los campos con valor, así que no hay huecos
   con guiones ocupando espacio. */
.nx-datos-rejilla {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
    gap: 1.25rem;
    margin: 0 0 2rem;
}

.nx-dato dt {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--gt-text-dim);
    margin-bottom: 0.2rem;
}

.nx-dato dd {
    margin: 0;
    font-family: var(--gt-font-display);
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

/* ===== Registro de series (la pantalla del gimnasio) =====
   Es la única pantalla que se usa DE PIE, entre series, con una sola mano. Todo
   aquí está dimensionado para el pulgar: controles de 3rem, campos anchos y
   nada de tablas con desplazamiento horizontal. */
.nx-registro-ejercicio {
    margin-bottom: 2rem;
}

.nx-registro-encabezado {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    padding-bottom: 0.6rem;
    margin-bottom: 0.85rem;
    border-bottom: 2px solid var(--gt-border);
}

.nx-registro-titulo {
    flex: 1;
    font-family: var(--gt-font-display);
    font-size: 1.35rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    margin: 0;
    min-width: 0;
}

.nx-registro-serie {
    padding: 0.85rem 0;
    border-bottom: 1px solid var(--gt-border);
}

.nx-registro-serie:last-child {
    border-bottom: none;
}

.nx-registro-serie-cab {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.6rem;
}

.nx-registro-num {
    font-weight: 600;
    font-size: 0.95rem;
}

.nx-registro-meta {
    font-size: 0.82rem;
    color: var(--gt-text-dim);
    font-variant-numeric: tabular-nums;
}

.nx-registro-campos {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
}

.nx-paso-campo {
    min-width: 0;
}

.nx-paso-label {
    display: block;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--gt-text-dim);
    margin-bottom: 0.3rem;
}

/* Control de ± con el campo al centro. Los botones son grandes a propósito:
   ajustar 2.5 kg tocando un botón es mucho más rápido que abrir el teclado
   numérico del teléfono con las manos ocupadas. */
.nx-paso-control {
    display: flex;
    align-items: stretch;
    border: 1px solid var(--gt-border-strong);
    border-radius: var(--gt-radius-sm);
    background: var(--gt-surface);
    overflow: hidden;
}

.nx-paso-control:focus-within {
    border-color: var(--gt-accent);
    box-shadow: 0 0 0 0.2rem var(--gt-accent-ring);
}

.nx-paso-btn {
    flex: 0 0 3rem;
    /* 48px: el mínimo cómodo para tocar con el pulgar. */
    min-height: 3rem;
    border: none;
    background: var(--gt-surface-2);
    color: var(--gt-text);
    font-size: 1.35rem;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    user-select: none;
    transition: background-color var(--gt-dur-fast) var(--gt-ease-out),
                color var(--gt-dur-fast) var(--gt-ease-out);
}

.nx-paso-btn:hover {
    background: var(--gt-accent);
    color: #fff;
}

.nx-paso-btn:active {
    background: var(--gt-accent-dark);
    color: #fff;
}

.nx-paso-input {
    flex: 1;
    min-width: 0;
    border: none;
    border-left: 1px solid var(--gt-border);
    border-right: 1px solid var(--gt-border);
    background: var(--gt-surface);
    color: var(--gt-text);
    /* 1.25rem evita que iOS haga zoom automático al enfocar el campo. */
    font-family: var(--gt-font-display);
    font-size: 1.35rem;
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
    padding: 0.4rem 0.2rem;
}

.nx-paso-input:focus {
    outline: none;
}

/* Se ocultan las flechas nativas del input number: ya hay botones de ± mucho
   más grandes, y las flechas del navegador son diminutas. */
.nx-paso-input::-webkit-outer-spin-button,
.nx-paso-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.nx-paso-input[type="number"] {
    -moz-appearance: textfield;
    appearance: textfield;
}

/* Barra de guardado fija abajo: en una rutina de seis ejercicios, el botón
   quedaría a varias pantallas de distancia. Aquí siempre está al alcance. */
.nx-guardar-barra {
    position: sticky;
    bottom: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin: 2rem -1rem 0;
    padding: 0.85rem 1rem;
    background: rgba(250, 249, 247, 0.92);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-top: 1px solid var(--gt-border);
}

.nx-guardar-barra .btn-success {
    flex: 1;
    max-width: 20rem;
}

@media (max-width: 400px) {
    /* En pantallas muy estrechas los dos campos se apilan: con 360px de ancho,
       dos controles de ± lado a lado dejan el campo demasiado angosto. */
    .nx-registro-campos {
        grid-template-columns: 1fr;
    }
}

/* ===== Gráficas de progreso =====
   Cada gráfica en su propia sección, sin tarjeta que la envuelva: el título y
   el espacio ya establecen la jerarquía, y un borde alrededor de un lienzo que
   ya tiene sus propios ejes es una caja de más. */
.nx-grafica-bloque {
    margin-bottom: 3rem;
}

.nx-grafica-encabezado {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
}

.nx-grafica-encabezado .nx-subtitulo {
    margin-bottom: 0.2rem;
}

/* La nota explica QUÉ mide la gráfica. Un eje etiquetado "Volumen (kg)" no le
   dice nada a quien empieza; "repeticiones por peso, sumado" sí. */
.nx-grafica-nota {
    font-size: 0.85rem;
    color: var(--gt-text-muted);
    max-width: 60ch;
    margin: 0;
}

.nx-grafica-selector {
    max-width: 17rem;
}

/* Alto fijo por breakpoint en vez del atributo height del canvas: con
   maintainAspectRatio:false Chart.js se ajusta al contenedor, y así la gráfica
   no se aplasta en pantallas estrechas. */
.nx-grafica-lienzo {
    position: relative;
    height: 15rem;
}

@media (min-width: 768px) {
    .nx-grafica-lienzo {
        height: 18rem;
    }
}

/* Estado vacío de una gráfica: ocupa un alto parecido al del lienzo para que
   la página no dé un salto cuando llegan los datos. */
.nx-grafica-vacia {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    min-height: 12rem;
    padding: 2rem 1rem;
    border: 1px dashed var(--gt-border-strong);
    border-radius: var(--gt-radius);
    text-align: center;
    color: var(--gt-text-muted);
}

.nx-grafica-vacia p {
    margin: 0;
    max-width: 42ch;
}

/* ===== Barra de composición (agregar ejercicio a una rutina) =====
   Selector, tres cifras y el botón en una sola línea. Los valores por defecto
   (3 × 10) cubren el caso habitual, así que agregar un ejercicio suele ser
   elegirlo y pulsar el botón. */
.nx-agregar-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.6rem;
    padding: 1rem;
    margin-bottom: 1rem;
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background: var(--gt-surface-2);
}

.nx-agregar-campo {
    display: flex;
    flex-direction: column;
    /* Ancho suficiente para tres dígitos más los controles del input number. */
    flex: 0 0 5.5rem;
}

/* El selector de ejercicio se lleva el espacio sobrante: sus nombres son
   mucho más largos que un número de dos cifras. */
.nx-agregar-ejercicio {
    flex: 1 1 12rem;
    min-width: 0;
}

.nx-agregar-campo .form-label {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--gt-text-dim);
    margin-bottom: 0.25rem;
}

.nx-agregar-btn {
    flex: 0 0 auto;
    /* Misma altura que los campos de al lado, para que la línea quede pareja. */
    min-height: 2.75rem;
    padding: 0.55rem 1.25rem;
    border: none;
    border-radius: var(--gt-radius-sm);
    background: var(--gt-secondary);
    color: #fff;
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color var(--gt-dur-fast) var(--gt-ease-out);
}

/* Es una acción de composición, no la acción principal de la pantalla: esa es
   "Guardar rutina". Por eso va en tinta y no en rojo. */
.nx-agregar-btn:hover {
    background: #34333a;
}

.nx-agregar-btn:active {
    transform: translateY(1px);
}

/* ===== Tabla de composición =====
   Se conserva como <table> porque el JS genera filas de 7 celdas. El scroll
   horizontal queda contenido en su envoltura, nunca en el body. */
.nx-tabla-envoltura {
    border: 1px solid var(--gt-border);
    border-radius: var(--gt-radius);
    background: var(--gt-surface);
    overflow-x: auto;
}

.nx-tabla {
    width: 100%;
    border-collapse: collapse;
}

.nx-tabla thead th {
    padding: 0.7rem 0.85rem;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--gt-text-dim);
    text-align: left;
    border-bottom: 1px solid var(--gt-border);
    white-space: nowrap;
}

.nx-tabla tbody td {
    padding: 0.7rem 0.85rem;
    border-bottom: 1px solid var(--gt-border);
    vertical-align: middle;
}

.nx-tabla tbody tr:last-child td {
    border-bottom: none;
}

.nx-tabla tbody tr:hover {
    background: var(--gt-surface-2);
}

.nx-col-num {
    width: 2.5rem;
    color: var(--gt-text-dim);
    font-variant-numeric: tabular-nums;
}

.nx-col-cifra,
th.nx-col-cifra {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.nx-col-quitar {
    width: 3rem;
    text-align: right;
}

.nx-tabla-vacia {
    padding: 2.5rem 1rem !important;
    text-align: center;
    color: var(--gt-text-muted);
}

/* El botón de quitar reutiliza .gt-accion pero aquí es un <button>, no un
   enlace: hay que neutralizar el fondo por defecto del navegador. */
.nx-tabla .gt-accion {
    background: transparent;
    cursor: pointer;
}

/* ===== Historial de sesiones =====
   Cada fila muestra el tonelaje con una barra relativa a la sesión más pesada:
   se comparan de un vistazo, sin leer los números uno por uno. */
/* La fila de sesión es más alta que una fila normal (lleva cifra, conteo y
   barra apilados), así que alinea arriba en vez de centrar. */
.nx-sesion {
    align-items: flex-start;
}

.nx-sesion .nx-lista-principal {
    padding-top: 0.15rem;
}

.nx-sesion-datos {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.15rem;
    min-width: 8rem;
}

.nx-sesion-volumen {
    display: flex;
    align-items: baseline;
    gap: 0.15rem;
}

.nx-sesion-kg {
    font-family: var(--gt-font-display);
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.nx-sesion-unidad {
    font-size: 0.8rem;
    color: var(--gt-text-muted);
}

.nx-sesion-series {
    font-size: 0.78rem;
    color: var(--gt-text-dim);
    font-variant-numeric: tabular-nums;
}

/* Barra comparativa. Se escala con transform (no width) para no provocar
   reflow con listas largas. */
.nx-sesion-barra {
    display: block;
    position: relative;
    width: 100%;
    height: 3px;
    margin-top: 0.25rem;
    border-radius: 3px;
    background: var(--gt-surface-2);
    overflow: hidden;
}

.nx-sesion-barra::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 3px;
    background: var(--gt-accent);
    transform: scaleX(var(--pct-escala, 0));
    transform-origin: left center;
}

/* Sesión iniciada pero nunca capturada: se marca como pendiente en vez de
   mostrar un tonelaje de cero, que parecería un entrenamiento fallido. */
.nx-sesion-pendiente {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--gt-warning);
}

.nx-sesion-pendiente:hover {
    color: var(--gt-accent);
}

/* ===== Detalle de sesión: bloques por ejercicio =====
   Sin tarjetas anidadas (una card con una tabla dentro, repetida por ejercicio).
   La jerarquía la dan el encabezado y el espacio. */
.nx-ejercicio-bloque {
    margin-bottom: 2rem;
}

.nx-ejercicio-encabezado {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    padding-bottom: 0.6rem;
    margin-bottom: 0.75rem;
    border-bottom: 1px solid var(--gt-border);
}

.nx-ejercicio-titulo {
    font-family: var(--gt-font-display);
    font-size: 1.3rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    margin: 0;
}

.nx-series {
    list-style: none;
    padding: 0;
    margin: 0;
}

.nx-serie {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--gt-border);
}

.nx-serie:last-child {
    border-bottom: none;
}

.nx-serie-num {
    flex-shrink: 0;
    display: grid;
    place-items: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    background: var(--gt-surface-2);
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--gt-text-muted);
    font-variant-numeric: tabular-nums;
}

.nx-serie-valores {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}

/* Lo realizado va primero y en grande; la meta debajo, como referencia. En la
   versión anterior ambos tenían el mismo peso y había que leer el encabezado
   de la columna para saber cuál era cuál. */
.nx-serie-real {
    font-family: var(--gt-font-display);
    font-size: 1.2rem;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.nx-serie-meta {
    font-size: 0.78rem;
    color: var(--gt-text-dim);
    font-variant-numeric: tabular-nums;
}

.nx-serie .gt-resultado {
    flex-shrink: 0;
    width: 6.5rem;
}

@media (max-width: 575.98px) {
    .nx-serie {
        flex-wrap: wrap;
        gap: 0.5rem 0.75rem;
    }

    .nx-serie .gt-resultado {
        width: 100%;
        padding-left: 2.5rem;
    }

    .nx-sesion-datos {
        min-width: 6rem;
    }
}

/* ===== Confirmación de borrado =====
   Sin tarjeta roja ni iconos de alarma: el peso lo lleva el texto, que dice
   exactamente qué se pierde y qué se conserva. La jerarquía de los botones es
   la salvaguarda real — conservar es sólido, eliminar es de contorno. */
.nx-confirmar-titulo {
    font-family: var(--gt-font-display);
    font-size: 1.9rem;
    font-weight: 700;
    line-height: 1.1;
    margin-bottom: 1rem;
}

.nx-confirmar-texto {
    color: var(--gt-text-muted);
    max-width: 60ch;
    margin-bottom: 0.85rem;
}

.nx-confirmar-texto strong {
    color: var(--gt-text);
    font-weight: 600;
}

.nx-ficha-plana {
    margin: 1.5rem 0;
}

.nx-ficha-plana dd {
    display: block;
    color: var(--gt-text);
}

.nx-confirmar-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--gt-border);
}

/* ===== Enlace de regreso ===== */

.nx-volver {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 1.25rem;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--gt-text-muted);
}

.nx-volver svg {
    width: 16px;
    height: 16px;
    transition: transform var(--gt-dur) var(--gt-ease-out);
}

.nx-volver:hover {
    color: var(--gt-accent);
}

.nx-volver:hover svg {
    transform: translateX(-3px);
}

/* ===== Detalle de ejercicio del catálogo =====
   Dos columnas: la animación queda pegajosa mientras se leen los pasos. En
   móvil vuelve a una sola columna y la animación va arriba. */
.nx-ejercicio {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 2.5rem;
    align-items: start;
}

.nx-ejercicio-visual {
    position: sticky;
    top: 5.5rem; /* deja libre la navbar pegajosa */
}

.nx-subtitulo {
    font-family: var(--gt-font-display);
    font-size: 1.35rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    margin-bottom: 1rem;
}

/* Ficha de datos: etiqueta arriba, valores abajo. Sin tarjeta que la envuelva
   —la jerarquía la dan el espacio y el tamaño, no una caja más. */
.nx-ficha {
    margin: 1.25rem 0 0;
}

.nx-ficha-fila {
    padding: 0.75rem 0;
    border-top: 1px solid var(--gt-border);
}

.nx-ficha dt {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--gt-text-dim);
    margin-bottom: 0.4rem;
}

.nx-ficha dd {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin: 0;
}

/* Pasos numerados de ejecución. Aquí el número SÍ es información: es el orden
   del movimiento, y hacerlo en desorden cambia el ejercicio. */
.nx-pasos {
    list-style: none;
    counter-reset: paso;
    padding: 0;
    margin: 0;
}

.nx-pasos li {
    counter-increment: paso;
    position: relative;
    padding-left: 3rem;
    padding-bottom: 1.5rem;
    color: var(--gt-text);
    max-width: 68ch;
}

.nx-pasos li::before {
    content: counter(paso);
    position: absolute;
    left: 0;
    top: -0.15rem;
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: var(--gt-surface-2);
    border: 1px solid var(--gt-border);
    font-family: var(--gt-font-display);
    font-size: 1rem;
    font-weight: 700;
    color: var(--gt-text-muted);
}

/* Línea que conecta los pasos: refuerza que es una secuencia continua. */
.nx-pasos li::after {
    content: "";
    position: absolute;
    left: 1rem;
    top: 2.1rem;
    bottom: 0.35rem;
    width: 1px;
    background: var(--gt-border);
}

.nx-pasos li:last-child {
    padding-bottom: 0;
}

.nx-pasos li:last-child::after {
    display: none;
}

@media (max-width: 767.98px) {
    .nx-ejercicio {
        grid-template-columns: 1fr;
        gap: 1.75rem;
    }

    /* En móvil no tiene sentido lo pegajoso: la animación ocuparía toda la
       pantalla y no dejaría leer. */
    .nx-ejercicio-visual {
        position: static;
    }
}

/* ===== Ajustes para pantalla chica =====
   El teléfono es el dispositivo real de uso durante el entrenamiento. */
@media (max-width: 575.98px) {
    .nx-cta {
        min-height: 5.5rem;
        padding: 1.25rem;
    }

    .nx-cta-titulo {
        font-size: 1.85rem;
    }

    .nx-cifras {
        gap: 1.5rem;
    }

    .nx-cifra-valor {
        font-size: 2rem;
    }

    .nx-seccion {
        min-height: 4.75rem;
        font-size: 0.78rem;
    }

    .nx-error {
        margin: 2.5rem auto;
    }
}