/* ============================================================
   ZUEKIN — Design tokens
   Fuente: export Figma (1440px reference). Todo tamaño, color,
   espaciado y transición vive aquí — cero valores sueltos en los
   componentes de abajo.
   ============================================================ */
   :root {
    /* ---- Color ---- */
    --color-ink: #2C2A25;
    --color-cream: #F2EDE4;
    --color-cream-soft: #F4F1EA;
    --color-white: #FFFFFF;
    --color-ink-mid: rgba(44, 42, 37, .42);
    --color-ink-low: rgba(44, 42, 37, .22);
    --color-on-photo: rgba(255, 255, 255, .6);
    --color-on-photo-hover-bg: rgba(255, 255, 255, .08);
    --color-terracota: #B5704A;
    --color-musgo: #4A5C45;
    --color-arenisca: #C4B49A;

    /* ---- Opacity roles ---- */
    --opacity-muted: .4;
    --opacity-hover: .7;
    --opacity-hover-soft: .85;
  
    /* ---- Spacing scale (fluid — scales smoothly between mobile/desktop) ---- */
    --space-1: clamp(.25rem, .2rem + .2vw, .375rem);
    --space-2: clamp(.5rem,  .4rem + .4vw, .75rem);
    --space-3: clamp(.75rem, .6rem + .6vw, 1.125rem);
    --space-4: clamp(1rem,   .85rem + .6vw, 1.5rem);
    --space-5: clamp(1.5rem, 1.2rem + 1.2vw, 2.25rem);
    --space-6: clamp(2rem,   1.5rem + 2vw, 3rem);
    --space-7: clamp(3rem,   2.2rem + 3.2vw, 4.5rem);
    --space-8: clamp(4rem,   2.8rem + 4.8vw, 6rem);
  
    --gutter: var(--space-6);          /* padding horizontal general de página */
  
    /* ---- Radius ---- */
    /* Radio estándar de TODO elemento tipo botón del sitio (CTAs, link
       de "Empieza aquí" del nav, triggers de acordeón) — redondeo sutil,
       no rompe la lectura angular del sitio a simple vista. Usado en:
       .site-nav__cta/.site-nav__panel-cta, .philosophy__cta,
       .valoracion-cta__button, .pricing-accordion__question,
       .faq__question. */
    --radius-sm: 4px;
    --radius-md: 12px;
    --radius-lg: 16px;
    --radius-pill: 999px;
    /* Excepción deliberada a la regla de esquinas vivas del resto del
       sitio — lenguaje "softened rectangle" reservado para bloques de
       foto/tarjeta destacados, NUNCA para botones (ver --radius-sm de
       arriba, un token separado a propósito): .about-photo__inner,
       .service-card, .location__map. En rem (no px, a diferencia de los
       --radius-* de arriba) porque esta convención vive en la escala
       tipográfica, no en la de radios fijos. */
    --radius-soft: 1.25rem; /* 20px @ 16px root */
  
    /* ---- Borders ---- */
    --border-w: 1px;
    --border-hairline: var(--border-w) solid var(--color-ink-low);
    --border-on-photo: var(--border-w) solid var(--color-on-photo);
  
    /* ---- Type families ---- */
    --font-display: "Resist Sans Display", "Helvetica Neue", Arial, sans-serif;
    --font-body: "Helvetica Neue", Arial, sans-serif;
  
    /* ---- Fluid type scale ---- */
    --text-2xs: clamp(.5rem, .48rem + .1vw, .5625rem);     /* footer / info-label   ~8-9px  */
    --text-xs:  clamp(.5625rem, .53rem + .15vw, .625rem);  /* info-line              ~9-10px */
    --text-sm:  clamp(.8125rem, .76rem + .25vw, .875rem);  /* nav links / CTA        ~13-14px*/
    --text-base: clamp(.9375rem, .87rem + .3vw, 1rem);     /* philosophy quote / cta ~15-16px*/
    --text-logo: clamp(2.6rem, 1.9rem + 3vw, 4.8rem);      /* wordmark central       */
    --text-display: clamp(3.25rem, .6rem + 11vw, 12.5rem);    /* hero headline          */
  
    /* ---- Letter spacing roles ---- */
    --tracking-tight: -.03em;
    --tracking-display: -.05em;
    --tracking-display-tight: -.06em;
    --tracking-wide: .1em;
    --tracking-wider: .14em;
    --tracking-widest: .2em;
  
    /* ---- Line height roles ---- */
    --leading-tight: 1.286;
    --leading-snug: 1.3125;
    --leading-hero: 1.32;
    --leading-body: 1.7;
    --leading-loose: 1.75;
  
    /* ---- Motion ---- */
    --duration-fast: 180ms;
    --duration-base: 600ms;
    /* Bloques del sistema de reveal (ver más abajo) — más corto que su
       valor original (900ms): con el stagger entre hermanos de un
       mismo grupo, 900ms por bloque hacía que la secuencia se sintiera
       lenta de ver completa, no deliberada. */
    --duration-slow: 700ms;
    /* Curva de desaceleración pronunciada al inicio ("expo-out"), no
       la keyword ease-out del navegador — deceleración más marcada al
       final, sensación más premium en hovers/transforms cortos y en
       cualquier animación de un solo sentido (como el reveal en
       scroll: nunca se revierte, así que no necesita el tramo de
       arranque lento de una curva simétrica). */
    --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
    /* Curva simétrica (entra y sale con la misma suavidad) — reservada
       para lo que de verdad se abre Y se cierra con la misma curva:
       el panel móvil de navegación, el subrayado de hover del footer.
       El reveal en scroll NO la usa — ver --ease-out. */
    --ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1);
    /* Distancia y ritmo del sistema de reveal (ver assets/js/reveal.js)
       — centralizados aquí en vez de repetidos como números sueltos en
       cada regla .has-reveal. Stagger subido de 60 a 90ms: con la
       duración ya más corta, 60ms entre hermanos apenas se notaba —
       la secuencia eyebrow → heading → body pedía más separación para
       leerse como una cascada, no como algo casi simultáneo. */
    --reveal-distance: 1.25rem;
    --stagger-step: 90ms;

    /* ---- Layout ---- */
    --max-content-width: 90rem;      /* 1440px, referencia Figma */
    --hero-min-height: 35rem;        /* 560px */
    --hero-stagger: clamp(0px, 30vw, 26.25rem); /* offset de la 2ª línea del hero, máx 420px */
    --z-nav: 20;

    /* ---- Nav (barra fija a todo lo ancho + menú móvil a pantalla
       completa). Vuelta a "Dirección 1": sin fondo/blur en reposo, solo
       en .is-scrolled (ver assets/js/nav.js). --nav-pill-bg es el fondo
       de ESE estado, y también el de los paneles desplegables
       (Servicios, ES/EUS), que lo usan siempre, con o sin scroll.
       Opacidad bajada a .18 (antes .28): la barra scrolleada debe leerse
       como cristal apenas perceptible, no como un bloque con presencia
       propia — más cerca del .18 original que del .38 de la pasada de
       rediseño visual. ---- */
    --nav-blur: 10px;
    --nav-pill-bg: rgba(20, 18, 16, .18);

    /* ---- Icon sizes ---- */
    --icon-social-size: .9375rem;    /* 15px */
    --icon-social-stroke: 1.6px;
    /* Punto intermedio entre 18px (original) y 22px (pasada de
       rediseño visual, demasiado grande para la barra ya compacta). */
    --icon-nav-logo-h: 1.25rem;      /* 20px */
  
    /*
      Breakpoints — referencia únicamente. Las custom properties no son
      interpolables dentro de @media, así que estos valores se repiten
      como literales en cada media query de abajo. Mantén esta tabla
      actualizada si cambias algún breakpoint.
        --bp-xs: 380px
        --bp-sm: 640px
        --bp-md: 760px
        --bp-lg: 1024px
    */

  /* ---- Noise overlay ---- */
  --noise-opacity: .12;
  --noise-blend: overlay;
  --noise-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");

  }
  
  *,
  *::before,
  *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
  }
  
  html, body {
    height: 100%;
  }
  
  html {
    -webkit-font-smoothing: antialiased;
  }
  
  body {
    min-height: 100dvh;
    background: var(--color-cream);
    color: var(--color-ink);
    font-family: var(--font-body);
    line-height: var(--leading-body);
  }
  
  /* Display voice: bold italic uppercase — headlines, nav, CTAs ONLY.
     Nunca en copy de párrafo a tamaño grande. */
  .display-voice {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 700;
    text-transform: uppercase;
  }

  /* ============================================================
     REVEAL — entrada en scroll (ver assets/js/reveal.js). Progressive
     enhancement: sin la clase .has-reveal en <html> (JS no corre, o
     prefers-reduced-motion), todo esto es contenido normal, siempre
     visible — el estado oculto-hasta-visible SOLO existe bajo
     .has-reveal, que el propio script añade el último, después de que
     el observer ya vigila todos los elementos.

     .reveal-item es la clase única que el script añade a los tres
     tipos de marcado (suelto, hijo de grupo, con o sin variante) — el
     CSS solo distingue por el valor de data-reveal, no por de dónde
     viene el elemento. Variante por defecto: fade + translateY.
     data-reveal="image": añade un scale sutil, mismo transform que ya
     usa el zoom en hover de las fotos (misma firma visual, no una
     animación sin relación). data-reveal="mask": el elemento en sí no
     se mueve — su overflow:hidden recorta la línea interior
     (.reveal-mask__line, creada por el script) que entra deslizándose
     desde abajo. El stagger entre hijos de [data-reveal-group] es
     transition-delay puesto por JS a partir de --stagger-step, no
     nada del otro lado.
     ============================================================ */
  .has-reveal .reveal-item {
    opacity: 0;
    transform: translateY(var(--reveal-distance));
    /* --ease-out, no --ease-in-out: un reveal es de un solo sentido
       (nunca se revierte), así que no hace falta una curva simétrica
       pensada para abrir Y cerrar — el tramo de arranque lento de
       ease-in-out solo suma demora percibida encima del propio delay
       del stagger. --ease-out empieza a moverse ya, decelera al
       llegar. */
    transition: opacity var(--duration-slow) var(--ease-out),
                transform var(--duration-slow) var(--ease-out);
  }

  .has-reveal .reveal-item.is-visible {
    opacity: 1;
    transform: none;
  }

  .has-reveal .reveal-item[data-reveal="image"] {
    transform: scale(1.06);
  }

  .has-reveal .reveal-item[data-reveal="image"].is-visible {
    transform: none;
  }

  .has-reveal .reveal-item[data-reveal="mask"] {
    opacity: 1;
    transform: none;
    transition: none;
  }

  /* El propio script solo añade esta clase cuando SÍ va a animar (nunca
     bajo prefers-reduced-motion), así que el overflow:hidden no
     necesita estar condicionado a .has-reveal aparte. */
  .reveal-mask {
    overflow: hidden;
  }

  .reveal-mask__line {
    display: inline-block;
    transform: translateY(110%);
    transition: transform var(--duration-slow) var(--ease-out);
  }

  .has-reveal .reveal-item[data-reveal="mask"].is-visible .reveal-mask__line {
    transform: none;
  }

  /* Red de seguridad adicional a la comprobación en JS: si por lo que
     sea .has-reveal llega a aplicarse con reduced-motion activo, el
     contenido sigue siendo visible de inmediato, sin animación. */
  @media (prefers-reduced-motion: reduce) {
    .has-reveal .reveal-item,
    .has-reveal .reveal-item[data-reveal="image"] {
      opacity: 1;
      transform: none;
      transition: none;
    }

    .reveal-mask__line {
      transform: none;
      transition: none;
    }
  }

  /* ============================================================
     HERO
     ============================================================ */
     .hero {
      position: relative;
      z-index: 0;   /* crea un stacking context propio para que los pseudo-elementos no se escapen detrás de la sección */
      width: 100%;
      height: 72vh;
      min-height: var(--hero-min-height);
      overflow: hidden;
      background-color: var(--color-ink);
      /* #hero es el destino de "Inicio" en zuekin-nav (home.html) — la
         barra fija a todo lo ancho (top: 0) taparía el borde superior
         de la sección al llegar por anclaje sin este offset. */
      scroll-margin-top: 4rem;
    }

    /* Imagen de fondo en su propio pseudo-elemento para poder invertirla
       verticalmente (transform) sin afectar al contenido real de .hero. */
    .hero::before {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      /* --hero-photo-height (opcional, por página): por defecto 100% del
         alto de .hero (igual que inset:0 de siempre). Una página puede
         reducirlo para que la foto solo ocupe una franja superior — el
         resto de .hero (más alto que esta franja) queda cubierto por su
         propio background-color plano, sin necesidad de que el gradiente
         llegue más abajo. Así es como /entrenamiento-funcional/ fusiona
         hero + statement en un único contenedor sin costura. */
      height: var(--hero-photo-height, 100%);
      /* --hero-gradient (opcional, por página, igual que --hero-bg-image)
         se pinta ENCIMA de la foto — por eso va primero en la lista de
         capas de background-image. Vacío por defecto (none) en cualquier
         página que no lo declare, así que esto no cambia nada fuera de
         donde se fije explícitamente. */
      background-image: var(--hero-gradient, none), var(--hero-bg-image, none);
      background-position: var(--hero-bg-position, center 10%);   /* favorece la parte baja de la imagen, dejando ~10% de margen respecto al borde inferior real; overridable por página igual que --hero-bg-image */
      background-size: cover;
      background-repeat: no-repeat;
      transform: scale(-1);
      z-index: 0;
    }

    .hero::after {
      content: "";
      position: absolute;
      inset: 0;
      background-image: var(--noise-svg);
      background-repeat: repeat;
      background-size: 200px 200px;
      opacity: var(--noise-opacity);
      mix-blend-mode: var(--noise-blend);
      pointer-events: none;
      z-index: 1;
    }

  .hero__content {
    position: absolute;
    z-index: 2;
    inset: auto 0 0 0;
    padding: 0 var(--space-3) var(--space-4);   /* antes: var(--gutter) var(--space-7) */
  }

  /* Envoltorio opcional para páginas que fusionan hero + contenido
     posterior en un único .hero (ej. /entrenamiento-funcional/): fija
     el alto de la "zona visual" (foto + título + kicker + scroll-cue)
     de forma independiente del alto total de .hero, que puede crecer
     más abajo con contenido real. Contexto de posicionamiento propio
     para que .hero__content/.hero__scroll-cue sigan ancladas a ESTA
     franja, no al final del bloque completo. Mismo valor por defecto
     (100%) que --hero-photo-height, para no cambiar nada donde no se
     use explícitamente. */
  .hero__visual {
    position: relative;
    height: var(--hero-photo-height, 100%);
  }

  /* ============================================================
     .hero--service — modificador formal para las páginas de servicio
     individuales (ej. /entrenamiento-funcional/, /smart-group/,
     /open-gym/...) que fusionan hero + statement en un único .hero.
     Agrupa aquí TODO lo que antes se repetía como estilo inline por
     página (altura auto, alto de la franja visual, gradiente,
     tamaño/opacidad de H1 y kicker, anclaje del contenido) — así cada
     página nueva solo necesita fijar --hero-bg-image/--hero-bg-position
     por su cuenta; el resto es 100% compartido y consistente por
     construcción, no por disciplina de copy-paste.
     ============================================================ */
  .hero--service {
    height: auto;
    --hero-photo-height: clamp(30rem, 14vw + 22rem, 40rem);
    --hero-gradient: linear-gradient(to top, rgba(44, 42, 37, 0) 60%, var(--color-ink) 95%);
  }

  .hero--service .hero__content {
    inset: 0 0 auto 0;
    /* Antes var(--space-5) (24-36px) — la barra fija a todo lo ancho
       del nav mide ~3.75rem (60px) de alto (mismo valor que ya usa
       .page-subnav para despejarla); ese padding dejaba el H1/kicker
       arrancando POR DEBAJO de esa altura, prácticamente pegados a la
       barra. var(--space-8) (64-96px) la despeja con aire real de
       sobra en vez de solo lo justo. */
    padding: var(--space-8) var(--space-3) 0;
  }

  .hero--service .hero__headline {
    font-size: clamp(3rem, 1.5rem + 8.75vw, 10rem);
    opacity: .6;
  }

  .hero--service .hero__kicker {
    margin: var(--space-3) 0 0;
    font-size: clamp(1rem, .8rem + 1vw, 1.5rem);
    opacity: .7;
  }

  /* ---- Hero con intro + 2 CTAs (solo /app/ por ahora) — el resto de
     .hero--service son solo H1+kicker, sin acción posible dentro del
     propio hero (la acción vive en .statement__back o el scroll-cue).
     Aquí SÍ hace falta una acción real dentro del hero, así que se
     añaden estos 3 elementos nuevos — reutilizan tokens/tratamientos ya
     existentes en el sitio (no una paleta/tipografía nueva):
     .hero__intro es prosa normal (--font-body) igual que .offer__intro;
     .hero__cta es el mismo botón que .valoracion-cta__button (cream +
     radius-sm, botón primario ya establecido sobre fondo oscuro);
     .hero__cta--secondary reutiliza el mecanismo de flecha+subrayado de
     .statement__back, con la flecha invertida (apunta a la derecha, no
     "volver" sino "seguir leyendo"). ---- */
  .hero__intro {
    margin: var(--space-4) 0 0;
    max-width: 32rem;
    font-family: var(--font-body);
    font-size: var(--text-base);
    line-height: var(--leading-body);
    color: rgba(242, 237, 228, .85);
  }

  .hero__cta-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-5);
    margin: var(--space-5) 0 0;
  }

  .hero__cta {
    display: inline-block;
    background: var(--color-cream);
    color: var(--color-ink);
    border-radius: var(--radius-sm);
    padding: clamp(.75rem, 1.5vw, 1rem) clamp(1.5rem, 3vw, 2rem);
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-display-tight);
    font-size: var(--text-base);
    text-decoration: none;
    transition: transform var(--duration-fast) var(--ease-out);
  }

  .hero__cta:hover,
  .hero__cta:focus-visible {
    transform: scale(1.03);
  }

  .hero__cta--secondary {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 700;
    text-transform: uppercase;
    font-size: var(--text-sm);
    letter-spacing: var(--tracking-tight);
    color: var(--color-cream);
    text-decoration: none;
    opacity: .78;
    transition: opacity var(--duration-fast) var(--ease-out);
  }

  .hero__cta--secondary:hover {
    opacity: 1;
    text-decoration: underline;
  }

  .hero__cta--secondary svg {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    stroke: currentColor;
    stroke-width: 1.6;
    fill: none;
    transition: transform var(--duration-fast) var(--ease-out);
  }

  .hero__cta--secondary:hover svg {
    transform: translateX(3px);
  }

  @media (prefers-reduced-motion: reduce) {
    .hero__cta,
    .hero__cta--secondary,
    .hero__cta--secondary svg {
      transition: none !important;
    }
  }

  /* Ancla de posición para los dos kickers del home (ver más abajo):
     position:relative + sin padding/margen propios, así que su altura
     es EXACTAMENTE la del <h1> que envuelve — dos líneas iguales en
     tamaño/line-height, así que top:50% cae justo donde empieza la
     segunda línea, geometría real en vez de un valor calculado a mano
     que puede desincronizarse. */
  .hero__headline-wrap {
    position: relative;
  }

  .hero__kicker {
    font-family: 'Roboto Slab', serif;
    font-weight: 400;
    font-synthesis: none;                               /* fuerza el weight real de la fuente, sin faux-bold */
    font-size: clamp(1.25rem, .95rem + 1.2vw, 2rem);  /* 32px en desktop, escala hacia abajo en mobile */
    line-height: 1;                                    /* 100%, como en Figma */
    text-transform: uppercase;
    color: var(--color-white);
    opacity: .4;
    hanging-punctuation: first last;
    margin: 0 0 var(--space-3);   /* Roboto Slab es más ancha/pesada que Noto — algo más de aire respecto al headline */
  }

  /* ---- Los dos kickers del home (izquierdo sobre "Salud", derecho
     sobre "Movimiento"): MISMO mecanismo para los dos, no dos rutas
     independientes que puedan desincronizarse — position:absolute +
     el mismo transform (sube el kicker su propia altura + --space-3,
     el mismo espacio que ya separaba el kicker izquierdo del headline
     antes de este cambio). Solo cambia el punto de anclaje: 0% para la
     primera línea, 50% para la segunda. margin:0 anula el margin-
     bottom de .hero__kicker de arriba, que ya no aplica aquí (la
     separación ahora es 100% geométrica, no de márgenes). ---- */
  .hero__kicker--start,
  .hero__kicker--end {
    position: absolute;
    margin: 0;
    transform: translateY(calc(-100% - var(--space-3)));
  }

  .hero__kicker--start {
    top: 0;
    left: 0;
  }

  .hero__kicker--end {
    top: 50%;
    right: 0;
    text-align: right;
  }

  .hero__kicker span {
    display: block;
  }

  /* ---- Scroll cue — solo en /entrenamiento-funcional/. Independiente
     de .hero__content (que en esta página queda anclado arriba): vive
     directamente en .hero, anclado abajo. Tipografía calcada de
     .hero__kicker a propósito — mismo font-family/weight/tamaño/
     opacidad, para leerse como su hermano visual, no un estilo nuevo. ---- */
  .hero__scroll-cue {
    position: absolute;
    z-index: 2;
    right: var(--space-4);
    bottom: var(--space-4);
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    font-family: 'Roboto Slab', serif;
    font-weight: 400;
    font-synthesis: none;
    font-size: clamp(1rem, .8rem + 1vw, 1.5rem);
    line-height: 1;
    text-transform: uppercase;
    color: var(--color-white);
    white-space: nowrap;
  }

  .hero__scroll-cue span {
    opacity: .7;
  }

  .hero__scroll-cue-icon {
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    stroke: currentColor;
    stroke-width: 2.4;
    fill: none;
    opacity: .78;
    transition: opacity var(--duration-fast) var(--ease-out);
    animation: hero-scroll-cue-float 2.4s ease-in-out infinite;
  }

  .hero__scroll-cue:hover .hero__scroll-cue-icon {
    opacity: 1;
    animation-duration: 1.2s;
  }

  @keyframes hero-scroll-cue-float {
    0%, 100% { transform: rotate(90deg) translateY(0); }
    50% { transform: rotate(90deg) translateY(4px); }
  }

  @media (prefers-reduced-motion: reduce) {
    .hero__scroll-cue-icon {
      animation: none;
      transform: rotate(90deg);
    }
  }

  .hero__headline {
    color: var(--color-white);
    opacity: var(--opacity-muted);
    letter-spacing: var(--tracking-display-tight);
    line-height: 0.86;                           /* antes: var(--leading-hero), 1.32 — demasiado suelto para texto grande */
  }

  .hero__headline span {
    display: block;
    width: 100%;
    font-size: var(--text-display);
  }
  
  .hero__headline span:nth-child(1) {
    text-align: left;
  }
  
  .hero__headline span:nth-child(2) {
    text-align: right;
  }
  
  /* ============================================================
     PHILOSOPHY
     ============================================================ */
  .philosophy {
    background: var(--color-cream);
    padding: var(--space-8) var(--gutter);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-6);
  }
  
  .philosophy__quote {
    max-width: 30rem;
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 700;
    font-size: var(--text-base);
    line-height: var(--leading-snug);
    letter-spacing: var(--tracking-display);
    text-align: center;
    text-transform: uppercase;
    color: var(--color-ink);
  }
  
  .philosophy__cta {
    display: inline-block;
    background: var(--color-ink);
    color: var(--color-white);
    /* --radius-sm, no --radius-soft: es un botón, no un bloque de foto
       — ver comentario de --radius-sm en :root. */
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-5);
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 700;
    font-size: var(--text-base);
    letter-spacing: var(--tracking-display-tight);
    text-transform: uppercase;
    text-decoration: none;
    transition: transform var(--duration-fast) var(--ease-out);
  }
  
  .philosophy__cta:hover {
    transform: scale(1.02);
  }

  /* ============================================================
     COMING SOON — aviso breve entre Philosophy y About Photo. Bloque
     de color a todo lo ancho (fondo full-bleed, contenido centrado
     sin wrapper extra), Musgo. Tipografía: .display-voice compartido
     (familia/italic/weight/uppercase) + tamaño/letter-spacing propios.
     ============================================================ */
  .coming-soon {
    width: 100%;
    background: var(--color-musgo);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding-block: clamp(5rem, 8vw, 6rem);
    padding-inline: var(--gutter);
    /* Antes clamp(2rem, 3vw, 3rem) — demasiado para dos líneas que
       deben leerse como un solo bloque, no como elementos separados.
       Un gap de párrafo normal, no de secciones distintas. */
    gap: clamp(.25rem, .5vw, .5rem);
  }

  .coming-soon__text {
    max-width: 30rem;
    margin-inline: auto;
    font-family: var(--font-display);
    text-transform: uppercase;
    /* ~20.03px en 1440px, ~16px de suelo en móvil. */
    font-size: clamp(1rem, .91rem + .38vw, 1.3rem);
    line-height: var(--leading-snug);
    letter-spacing: var(--tracking-display);
    color: var(--color-cream);
    text-align: center;
  }

  /* Contraste de dos niveles pedido explícitamente para esta sección
     (línea 1 bold/upright, línea 2 italic/regular) — no viene de
     .statement__text--strong/--muted: esas dos solo se diferencian por
     color (cream vs arenisca), comparten el mismo italic+700 vía
     .statement__text p. Aquí el peso/estilo SÍ es la diferencia. */
  .coming-soon__text--strong {
    font-style: normal;
    font-weight: 700;
  }

  .coming-soon__text--muted {
    font-style: italic;
    font-weight: 400;
  }

  /* ============================================================
     ABOUT PHOTO — bloque de foto entre .coming-soon y .what-is-
     zuekin. Full-bleed como .coming-soon (fondo Lino a todo lo
     ancho); el padding de la propia sección ES el inset del bloque
     interior (Figma: 1380px interior sobre 1440px exterior ≈ 30px por
     lado, que es justo el padding de abajo) — no hace falta un
     max-width aparte en .about-photo__inner. Primera sección del
     sitio con esquinas redondeadas (--radius-soft) — ver :root para
     el porqué de la excepción.
     ============================================================ */
  .about-photo {
    width: 100%;
    background: var(--color-cream);
    display: flex;
    justify-content: center;
    padding: clamp(1.5rem, 3vw, 2rem);
  }

  .about-photo__inner {
    width: 100%;
    min-height: clamp(24rem, 40vw, 32rem);
    border-radius: var(--radius-soft);
    background-color: var(--color-ink-low);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    /* Mismo patrón --service-bg-image que las 8 service-cards y
       .closing-cta — no una propiedad nueva. */
    background-image: var(--service-bg-image, repeating-linear-gradient(
      135deg,
      var(--color-ink-low) 0px,
      var(--color-ink-low) 2px,
      transparent 2px,
      transparent 14px
    ));
  }

  /* Las 3 capturas reales de ViDay en /app/ — .about-photo__inner
     reutilizado tal cual (mismo patrón --service-bg-image que el resto
     del sitio), solo con proporción de pantalla de móvil en vez del
     min-height panorámico pensado para una única foto ancha. Ratio
     9/19.5 (no el 9/16 genérico de antes): las capturas reales miden
     2955×6400px, más altas/estrechas que un 9/16 — con ese ratio real
     se recorta lo mínimo posible en vez de perder barra de estado o
     navegación inferior de la captura. */
  .app-screens {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-4);
  }

  .app-screens .about-photo__inner {
    min-height: 0;
    aspect-ratio: 9 / 19.5;
  }

  @media (max-width: 640px) {
    .app-screens {
      grid-template-columns: 1fr;
    }
  }

  /* ============================================================
     WHAT IS ZUEKIN — sobre Lino (Cream), inverso de la mayoría de
     secciones del home. Reutiliza el MECANISMO de grid de
     .statement__inner (columna de label estrecha / contenido ancho,
     2fr 3fr, misma gap, mismo colapso a 1 columna en mobile) — no la
     clase en sí, porque .statement en sí trae fondo Carbon que no
     aplica aquí. .what-is-zuekin__lead usa un clamp propio (no el de
     .offer__title, que apunta a 36px — mucho más grande que los ~22px
     de la referencia): mismo método de las últimas secciones del home
     (dos puntos de referencia, cae en Xpx exactos a 1440px), no un
     valor inventado.
     ============================================================ */
  .what-is-zuekin {
    width: 100%;
    background: var(--color-cream);
    padding-block: clamp(2.5rem, 4vw, 3rem);
    padding-inline: var(--gutter);
    /* #what-is-zuekin es el destino de "Qué es Zuekin" en zuekin-nav
       (home.html) — mismo motivo que scroll-margin-top en .hero/.location. */
    scroll-margin-top: 4rem;
  }

  .what-is-zuekin__inner {
    max-width: var(--max-content-width);
    margin-inline: auto;
    display: grid;
    grid-template-columns: 2fr 3fr;
    gap: var(--space-6);
    align-items: start;
  }

  .what-is-zuekin__label {
    font-family: var(--font-display);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--tracking-display);
    font-size: var(--text-base);
    color: var(--color-ink);
  }

  .what-is-zuekin__label em {
    font-style: italic;
  }

  .what-is-zuekin__content {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
  }

  .what-is-zuekin__lead {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 700;
    text-transform: uppercase;
    /* ~22.1px a 1440px (Figma: 22px), suelo ~18px en móvil. */
    font-size: clamp(1.125rem, 1.04rem + .38vw, 1.625rem);
    line-height: var(--leading-snug);
    letter-spacing: var(--tracking-tight);
    color: var(--color-ink);
  }

  .what-is-zuekin__columns {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
  }

  .what-is-zuekin__col {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 500;
    text-transform: uppercase;
    font-size: var(--text-base);
    line-height: var(--leading-snug);
    color: var(--color-ink);
  }

  .what-is-zuekin__emphasis {
    text-decoration: underline;
    text-underline-offset: .2em;
  }

  @media (max-width: 640px) {
    .what-is-zuekin__inner {
      grid-template-columns: 1fr;
    }

    .what-is-zuekin__columns {
      grid-template-columns: 1fr;
    }
  }

  @media (max-width: 640px) {
    .philosophy__quote {
      max-width: 22rem;
    }
  }

  /* ============================================================
     STATEMENT — bloque editorial sobre Carbon, usado como intro de
     página de servicio individual (ej. /entrenamiento-funcional/).
     .statement__back vive dentro del mismo grid que el texto (columna
     1, misma fila) para compartir borde superior exacto con el texto
     — align-items: start en .statement__inner es lo que los alinea.
     .statement--left alinea el texto a la izquierda (por defecto, sin
     el modificador, queda a la derecha por si se reutiliza el patrón
     original en otra página).
     ============================================================ */
  .statement {
    position: relative;
    background: var(--color-ink);
    padding: var(--space-8) var(--gutter);
  }

  .statement__inner {
    max-width: var(--max-content-width);
    margin-inline: auto;
    display: grid;
    grid-template-columns: 2fr 3fr;
    gap: var(--space-6);
    align-items: start;
  }

  .statement__back {
    grid-column: 1;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 700;
    text-transform: uppercase;
    font-size: var(--text-sm);
    letter-spacing: var(--tracking-tight);
    color: var(--color-cream);
    text-decoration: none;
    text-underline-offset: .25em;
    opacity: .78;
    transition: opacity var(--duration-fast) var(--ease-out);
  }

  .statement__back:hover {
    opacity: 1;
    text-decoration: underline;
  }

  .statement__back svg {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    transition: transform var(--duration-fast) var(--ease-out);
    stroke: currentColor;
    stroke-width: 1.6;
    fill: none;
  }

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

  /* Mismo patrón que .hero__cta--secondary/.closing-cta__title svg —
     esta flecha tenía el hover pero no la excepción de
     prefers-reduced-motion, hueco real encontrado en la auditoría. */
  @media (prefers-reduced-motion: reduce) {
    .statement__back,
    .statement__back svg {
      transition: none !important;
    }
  }

  .statement__text {
    grid-column: 2;
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    text-align: right;
  }

  .statement--left .statement__text {
    text-align: left;
  }

  .statement__text p {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 700;
    text-transform: uppercase;
    font-size: var(--text-base);
    line-height: var(--leading-loose);
    letter-spacing: var(--tracking-tight);
  }

  .statement__text--strong {
    color: var(--color-cream);
  }

  .statement__text--muted {
    color: var(--color-arenisca);
  }

  @media (max-width: 640px) {
    .statement__inner {
      grid-template-columns: 1fr;
    }

    .statement__back {
      margin-bottom: var(--space-4);
    }

    .statement__text {
      grid-column: 1;
      text-align: left;
    }
  }

  /* ============================================================
     Teaser leftovers — wordmark central, info grid, footer
     ============================================================ */
  .stage {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-3);
    user-select: none;
  }
  
  .wordmark svg {
    height: var(--text-logo);
    width: auto;
    display: block;
    flex-shrink: 0;
  }
  
  .bottom {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    align-items: center;
  }
  
  .info-grid {
    display: grid;
    grid-template-columns: repeat(3, auto);
    gap: var(--space-5) var(--space-8);
    align-items: start;
  }
  
  .info-col {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
  }
  
  .info-label {
    font-size: var(--text-2xs);
    letter-spacing: var(--tracking-widest);
    text-transform: uppercase;
    color: var(--color-ink-mid);
    margin-bottom: var(--space-1);
  }
  
  .info-line {
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    line-height: var(--leading-loose);
    color: var(--color-ink);
    font-weight: 500;
  }
  
  .info-line a {
    color: inherit;
    text-decoration: none;
    padding-bottom: 1px;
    transition: border-color var(--duration-fast);
  }
  
  .info-line a:hover {
    border-color: var(--color-ink);
  }
  
  footer {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding-top: var(--space-3);
    width: 100%;
  }
  
  .footer-copy {
    font-size: var(--text-2xs);
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--color-ink-low);
  }
  
  /* ---- Typewriter ---- */
  .word-slot {
    position: relative;
    display: flex;
    align-items: baseline;
    overflow: hidden;
    transition: width 120ms var(--ease-out);
  }
  
  #typeText {
    font-family: var(--font-body);
    font-weight: 700;
    font-style: italic;
    letter-spacing: var(--tracking-tight);
    color: var(--color-ink);
    white-space: nowrap;
  }
  
  #cursor {
    display: inline-block;
    width: 2px;
    background: var(--color-ink);
    margin-left: var(--space-1);
    border-radius: var(--radius-sm);
    opacity: 0;
    vertical-align: middle;
    transform: skewX(-12deg);
  }
  
  #cursor.visible { opacity: 1; }
  
  #cursor.blink {
    animation: blink 900ms steps(1) infinite;
  }
  
  @keyframes blink {
    0%, 100% { opacity: 1; }
    50%       { opacity: 0; }
  }
  
  /* ============================================================
     Responsive — breakpoints documentados en :root, valores
     literales aquí por limitación de CSS (custom properties no
     funcionan dentro de @media).
     ============================================================ */
  @media (max-width: 640px) {
    .info-grid {
      grid-template-columns: 1fr 1fr;
    }
    footer {
      flex-direction: column;
      align-items: flex-start;
    }
  }
  
  @media (max-width: 380px) {
    .info-grid {
      grid-template-columns: 1fr;
    }
  }
  
  @media (prefers-reduced-motion: reduce) {
    #cursor { animation: none !important; }
    .word-slot { transition: none !important; }
    .philosophy__cta {
      transition: none !important;
    }
  }




  /* ============================================================
   SERVICES — 11 tarjetas (home): 7 de servicio real + 4 decorativas
   (posiciones 2, 4, 7, 11 de la fila) para romper el ritmo con imagen
   pura, sin plantear un octavo/noveno/etc. servicio que no existe.
   Antes eran 8 servicios (incluía Open Gym) — se quitó del todo, no se
   dejó un hueco vacío, porque Open Gym no es un servicio independiente
   (vive dentro de Entrenamiento Funcional). Layout de dos columnas:
   .services__intro (columna izquierda fija, no scrollea) +
   .services__track (scroll horizontal en el espacio restante).

   Altura dirigida por viewport, no aspect-ratio: la sección ocupa
   calc(100vh - padding-block*2) y tanto .services__track como cada
   .service-card se estiran (align-items: stretch, en cascada) para
   rellenar esa altura — así las tarjetas son tan altas como permita
   la ventana, no una proporción fija. padding-block en clamp() en vez
   del 50px fijo de Figma (--services-pad-block, 3.125rem ≈ 50px en el
   ancho de referencia de 1440px, se reduce en viewports pequeños). En
   el breakpoint apilado (≤900px, ver media query) se vuelve a
   aspect-ratio: 3/4 como fallback — con .services en columna ya no
   hay una altura de fila que estirar.

   Índice numerado 01-07: cuenta solo las tarjetas de SERVICIO (ignora
   los huecos decorativos), para que el badge lea "servicio X de 7" en
   vez de un número de posición en la fila que saltaría sin motivo
   aparente para quien lo mira. Las 4 decorativas NO llevan badge (ni
   título, ni descripción, ni link) — así lo pide la tarea: son foto
   pura, no una octava/novena tarjeta de servicio con contenido oculto.
   Título + descripción de las de servicio SIEMPRE visibles, ancladas
   abajo — nada detrás de hover.

   Colores de marca (Arenisca/Carbon/Musgo/Cream) en las 7 tarjetas de
   servicio, sin que dos ADYACENTES (vecinas reales en la fila, aunque
   una decorativa las separe) repitan tono. Con 7 tarjetas (número
   impar) ya no salen exactas 2 de cada color — la secuencia real es
   Carbon/Musgo/Cream/Arenisca/Musgo/Cream/Carbon (Arenisca queda con
   una sola tarjeta, Yoga). Terracota sigue fuera de la rotación: ni
   Cream ni Ink pasan el mínimo AA de 4.5:1 sobre ella (3.35:1 y 3.67:1
   respectivamente). El gradiente de .service-card::before sigue vivo
   también en las decorativas (mismo tratamiento de foto que las
   tarjetas de servicio con imagen, por consistencia visual) —
   .service-card--color lo desactiva solo en las de color sólido, que
   no lo necesitan. Sin controles ← →: solo scroll-snap/swipe nativo.
   ============================================================ */
.services {
  --services-gap: var(--space-4);
  --services-pad-block: clamp(1.5rem, 4vw, 3.125rem);
  max-width: var(--max-content-width);
  margin-inline: auto;
  display: flex;
  align-items: stretch;
  gap: var(--space-6);
  padding: var(--services-pad-block) var(--gutter);
  height: calc(100vh - var(--services-pad-block) * 2);
  overflow-y: hidden;
}

.services__intro {
  flex: 0 0 22rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.services__eyebrow {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  text-transform: uppercase;
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink);
}

.services__heading {
  font-size: clamp(1.5rem, 1.1rem + 1.8vw, 2.5rem);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-display);
  color: var(--color-ink);
}

.services__track {
  display: flex;
  flex-wrap: nowrap;
  /* Stretch, no flex-start: cada .service-card rellena la altura
     completa del track (que a su vez rellena .services, ver arriba). */
  align-items: stretch;
  /* Sin esto, un flex-item con overflow interno no se encoge por
     debajo del ancho de su contenido (min-width:auto por defecto) y
     puede desbordar en vez de scrollear. */
  min-width: 0;
  flex: 1 1 auto;
  overflow-x: auto;
  gap: var(--services-gap);
  /* Antes "mandatory" — obliga al navegador a snapear SIEMPRE al punto
     más cercano al final de cualquier gesto, por pequeño que sea. Con
     rueda/trackpad (gestos cortos y frecuentes, no un swipe largo) eso
     se siente como que el scroll se traba o se resiste a mitad de
     camino: cada micro-scroll es forzado de vuelta al borde de la
     tarjeta más próxima en vez de dejar avanzar el gesto. "proximity"
     solo snapea cuando el scroll ya termina cerca de un punto — deja
     el scroll libre de verdad y sigue asentando limpio en el borde de
     cada tarjeta al soltar cerca de uno. scroll-snap-stop no se toca
     (default "normal", no "always"): ya permitía saltar varias
     tarjetas en un fling rápido, eso nunca fue parte del problema. */
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  /* Antes el track ocupaba el ancho completo de .services y el fade
     de entrada (0 → gutter) tenía sentido en su borde izquierdo. Con
     la columna de intro fija a la izquierda, ese borde ya no es un
     límite de viewport — la primera tarjeta debe verse completa desde
     ya. Solo queda el fade de salida hacia el borde derecho. */
  -webkit-mask-image: linear-gradient(
    to right,
    black 0,
    black calc(100% - var(--gutter)),
    transparent 100%
  );
  mask-image: linear-gradient(
    to right,
    black 0,
    black calc(100% - var(--gutter)),
    transparent 100%
  );
}

.services__track::-webkit-scrollbar {
  display: none;
}

.service-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-start;
  /* +12% sobre el ancho "3 tarjetas exactas por tramo" — más espaciosas
     sin cambiar cuántas se ven por pantalla de forma perceptible (pasa
     de ~3.0 a ~2.7 tarjetas visibles, el ritmo de scroll-snap no
     cambia). ~300px → ~336px a 1440px de viewport. */
  flex: 0 0 calc(((100% - var(--services-gap) * 2) / 3) * 1.12);
  scroll-snap-align: start;
  /* Altura heredada del stretch de .services__track (ver arriba) — no
     aspect-ratio fija. En el breakpoint apilado (≤900px) vuelve el
     aspect-ratio como fallback (ver media query). */
  border-radius: var(--radius-soft);
  padding: var(--space-5);
  text-decoration: none;
  color: var(--color-white);
  background-color: var(--color-ink-low);
  /* overflow: clip, no solo hidden — "hidden" quita la barra de scroll
     pero sigue siendo técnicamente un scrollport: si algo dentro de la
     tarjeta sobresale (.service-card__photo en hover, transform:
     scale(1.08), bleedea un 8% más allá del propio borde), Chrome/
     WebKit permiten scrollear esa zona con rueda/trackpad aunque no
     haya scrollbar visible. clip desactiva ESE scroll puntual, hidden
     no. Se apilan los dos (hidden primero, clip después) por
     compatibilidad: un navegador sin soporte de overflow:clip (Safari
     <16) descarta la declaración que no entiende y conserva hidden, en
     vez de quedarse en "visible" (su valor inicial) sin control alguno.

     Aclaración importante: esto NUNCA fue la causa del "scroll se
     traba" que se reportó — ese bug era de .services__track (scroll-
     snap-type: mandatory, ver arriba), no de tarjetas individuales.
     Esta regla se queda tal cual porque es una mejora real y
     inofensiva (evita que una tarjeta capture scroll aislado por su
     propio bleed decorativo), pero no la borres pensando que resuelve
     el bug de scroll bloqueado del carrusel — ese vive en el track. */
  overflow: hidden;
  overflow: clip;
}

/* ---- Capa de foto (4 de las 8 tarjetas). Zoom en hover vía
   transform:scale en esta capa propia, no en background-size —
   background-size en % se deforma si la tarjeta y la foto no
   comparten proporción; transform:scale en una capa dedicada no. ---- */
.service-card__photo {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-color: var(--color-ink-low);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-image: var(--service-bg-image, repeating-linear-gradient(
    135deg,
    var(--color-ink-low) 0px,
    var(--color-ink-low) 2px,
    transparent 2px,
    transparent 14px
  ));
  transition: transform var(--duration-base) var(--ease-out);
}

.service-card:hover .service-card__photo,
.service-card:focus-visible .service-card__photo {
  transform: scale(1.08);
}

/* Gradiente de legibilidad — SIEMPRE activo en las tarjetas de foto
   (título+descripción están siempre visibles, así que la legibilidad
   no puede depender del hover). .service-card--color lo desactiva
   para las de color sólido, que no lo necesitan. */
.service-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    to top,
    rgba(20, 18, 16, .88) 0%,
    rgba(20, 18, 16, .55) 42%,
    rgba(20, 18, 16, .08) 78%
  );
  pointer-events: none;
}

.service-card__index {
  position: absolute;
  z-index: 2;
  top: var(--space-3);
  left: var(--space-3);
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 700;
  font-size: var(--text-base);
  color: var(--color-white);
}

.service-card__body {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
}

.service-card__title {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  text-transform: uppercase;
  /* Mismo clamp que .what-is-zuekin__lead — mismo objetivo ~22px a
     1440px, no un valor nuevo para el mismo tamaño. */
  font-size: clamp(1.125rem, 1.04rem + .38vw, 1.625rem);
  /* Sin esto heredaba --leading-body (1.7) de <body> — mismo ajuste
     que .service-card__desc, mismo token (--leading-tight, 1.286: el
     más ajustado de la escala; el objetivo pedido de 1.1-1.15 no
     tiene token propio). */
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--color-white);
}

.service-card__desc {
  font-family: var(--font-body);
  font-style: normal;
  font-weight: 400;
  font-size: var(--text-sm);
  /* --leading-tight (1.286) es el token más ajustado de la escala —
     el objetivo pedido (1.15-1.2) no tiene token propio, así que se
     reutiliza el más cercano en vez de escribir un 1.15-1.2 suelto. */
  line-height: var(--leading-tight);
  letter-spacing: normal;
  text-transform: none;
  color: rgba(255, 255, 255, .8);
  max-width: 30ch;
}

/* ---- Decorativas — las 4 tarjetas de foto pura (posiciones 2, 5, 8,
   12), sin badge/título/descripción/link. No es un <a> (no navegan a
   ningún sitio) — mismas dimensiones y radius que el resto vía
   .service-card base; solo aportan .service-card__photo. Comparten el
   mismo gradiente de legibilidad de .service-card::before por
   consistencia visual con las demás fotos del sitio, aunque aquí no
   haya texto que proteger. */
.service-card--decorative {
  cursor: default;
}

/* ---- Bloques de color — las 8 tarjetas de servicio (ver orden en el
   HTML). Colores reales del sitio (Carbon/Musgo/Arenisca + Cream como
   sustituto de "Lino", que no existe como token). Terracota queda
   fuera: ni Cream ni Ink pasan el mínimo AA de 4.5:1 sobre ella
   (3.35:1 y 3.67:1 respectivamente). Sin resize de ancho en hover —
   solo un brillo sutil, misma señal de siempre. */
.service-card--color {
  transition: filter var(--duration-base) var(--ease-out);
}

.service-card--color::before {
  content: none;
}

.service-card--color:hover,
.service-card--color:focus-visible {
  filter: brightness(1.08);
}

.service-card--carbon {
  background-color: var(--color-ink);
}

.service-card--carbon .service-card__index,
.service-card--carbon .service-card__title {
  color: var(--color-cream);
}

.service-card--carbon .service-card__desc {
  color: rgba(242, 237, 228, .85);
}

.service-card--musgo {
  background-color: var(--color-musgo);
}

.service-card--musgo .service-card__index,
.service-card--musgo .service-card__title {
  color: var(--color-cream);
}

.service-card--musgo .service-card__desc {
  color: rgba(242, 237, 228, .85);
}

.service-card--arenisca {
  background-color: var(--color-arenisca);
}

.service-card--arenisca .service-card__index,
.service-card--arenisca .service-card__title {
  color: var(--color-ink);
}

.service-card--arenisca .service-card__desc {
  color: rgba(44, 42, 37, .85);
}

/* "Lino" no es un token real del sitio (solo hay Carbon/Musgo/
   Arenisca/Terracota + los neutros ink/cream/white) — se usa
   --color-cream como el neutro claro más cercano, igual que ya hace
   el resto del sitio para texto/fondo claro. */
.service-card--cream {
  background-color: var(--color-cream);
}

.service-card--cream .service-card__index,
.service-card--cream .service-card__title {
  color: var(--color-ink);
}

.service-card--cream .service-card__desc {
  color: rgba(44, 42, 37, .85);
}

/* Columna de intro fija a 22rem: a partir de aquí para abajo (tablet/
   mobile) no queda ancho real para el track — mismo breakpoint que ya
   usa .location para su propio patrón "dos columnas → apiladas". */
@media (max-width: 900px) {
  .services {
    flex-direction: column;
    /* En columna ya no hay una fila que estirar hasta 100vh — la
       sección vuelve a su altura natural de contenido. */
    height: auto;
  }

  .services__intro {
    flex-basis: auto;
  }

  .service-card {
    aspect-ratio: 3 / 4;
  }
}

/* Mobile: variante más ajustada, ~1.5 tarjetas visibles (peek de la siguiente).
   Mismo +12% que la versión de escritorio, por consistencia. */
@media (max-width: 640px) {
  .service-card {
    flex-basis: calc(((100% - var(--services-gap)) / 1.5) * 1.12);
  }
}

@media (prefers-reduced-motion: reduce) {
  .service-card--color,
  .service-card__photo {
    transition: none !important;
  }
}

/* ============================================================
   OFFER PAGES — bloques reutilizables para páginas de servicio con
   una o varias modalidades (entrenamiento/, pilates/, yoga/...).
   Un .offer por modalidad: eyebrow + título + intro + lista +
   tabla de precios. .page-subnav es opcional, solo quando hay más
   de una modalidad en la misma página (ver /entrenamiento/).
   ============================================================ */
/* Sticky: full-bleed para que el fondo cubra todo el ancho, contenido
   centrado en .page-subnav__inner.
   top: 3.75rem para despejar la barra fija de zuekin-nav (a todo lo
   ancho, pegada a top: 0 — altura real ≈ 2.75rem de contenido +
   .5rem*2 de padding vertical). */
.page-subnav {
  position: sticky;
  top: 3.75rem;
  z-index: 10;
  background: var(--color-cream);
  border-bottom: var(--border-hairline);
}

.page-subnav__inner {
  max-width: var(--max-content-width);
  margin-inline: auto;
  padding: var(--space-4) var(--gutter);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
}

.page-subnav a {
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--color-ink-mid);
  text-decoration: none;
  text-underline-offset: .25em;
  padding: var(--space-2) var(--space-3);
  border-radius: 0;
  transition: color var(--duration-fast) var(--ease-out),
              background-color var(--duration-fast) var(--ease-out);
}

.page-subnav a:hover:not(.is-active) {
  color: var(--color-ink);
  background: var(--color-ink-low);
  text-decoration: underline;
}

/* Indicador de sección activa — mismo lenguaje que zuekin-nav:
   bloque rectangular relleno, no cápsula. */
.page-subnav a.is-active {
  color: var(--color-cream);
  background: var(--color-ink);
}

.offer {
  max-width: var(--max-content-width);
  margin-inline: auto;
  padding: var(--space-8) var(--gutter);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  border-top: var(--border-hairline);
}

.offer:first-of-type {
  border-top: none;
}

/* Mismo tratamiento que .services__eyebrow/.what-is-zuekin__label/
   .location__eyebrow en el home (display voice en bold italic
   uppercase, --text-sm, tracking-tight, color neutral) — antes era
   sans-serif diminuto (--text-2xs) en Terracota, un registro y un
   color de acento que no existe en ningún eyebrow del home. */
.offer__eyebrow {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  text-transform: uppercase;
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink);
}

.offer__title {
  font-size: clamp(1.5rem, 1.1rem + 2vw, 2.25rem);
  letter-spacing: var(--tracking-display-tight);
  color: var(--color-ink);
  max-width: 20ch;
}

.offer__intro {
  max-width: 42rem;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  color: var(--color-ink);
}

.offer__list {
  max-width: 42rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  list-style: none;
}

.offer__list li {
  padding-left: var(--space-4);
  position: relative;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-loose);
  color: var(--color-ink);
}

.offer__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .65em;
  width: 6px;
  height: 6px;
  background: var(--color-terracota);
}

.offer__pending {
  max-width: 42rem;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-style: italic;
  line-height: var(--leading-loose);
  color: var(--color-ink-mid);
}

.offer__pricing {
  max-width: 42rem;
  display: flex;
  flex-direction: column;
}

.offer__pricing-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-top: var(--border-hairline);
}

.offer__pricing-row:last-child {
  border-bottom: var(--border-hairline);
}

.offer__pricing-label {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink);
}

.offer__pricing-value {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: var(--text-base);
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink);
  white-space: nowrap;
}

/* ----------------------------------------------------------------
   Variante "color-block" de .offer — bloque a sangre completa
   diferenciado por color, en vez de por foto. Solo Cream sigue en
   uso (envoltorio Lino de los 3 calendarios); Carbon/Musgo/Arenisca
   se retiraron aquí porque se quedaron sin ningún consumidor cuando
   los calendarios pasaron a compartir fondo Lino con el color de
   servicio solo en la tarjeta de cada franja (.calendar__block--*).
   padding-block usa el mismo clamp que .what-is-zuekin (2.5rem→3rem),
   no el --space-8 (4rem→6rem) del resto de variantes .offer — esta
   sección debe respirar como las de home, no como las de .offer. */
.offer--cream {
  max-width: none;
  margin-inline: 0;
  padding: clamp(2.5rem, 4vw, 3rem) 0;
  border-top: none;
  position: relative;
  overflow: hidden;
  background: var(--color-cream);
  color: var(--color-ink);
  border-block: var(--border-hairline);
}

.offer__inner {
  max-width: var(--max-content-width);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  position: relative;
  z-index: 1;
}

.offer--centered .offer__inner {
  align-items: center;
  text-align: center;
}

.offer__col {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* ---- Cifra grande como ancla visual por sección — mismo lenguaje
   tipográfico que --text-display, a escala de sección, no de hero. ---- */
.offer__stat {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(2.5rem, 1.5rem + 5vw, 5.5rem);
  line-height: .95;
  letter-spacing: var(--tracking-display-tight);
  color: var(--color-ink);
}

.offer__stat span {
  display: block;
  font-family: var(--font-body);
  font-style: normal;
  font-weight: 400;
  text-transform: uppercase;
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-widest);
  margin-top: var(--space-2);
}

/* ---- Precios como tarjetas compactas — sustituye la tabla/lista de
   filas (.offer__pricing-row) solo donde se use este patrón; sin
   esquinas redondeadas, coherente con la geometría del resto del sitio. ---- */
.price-cards {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.price-card {
  border: 1px solid currentColor;
  padding: var(--space-4);
  min-width: 9rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.price-card__value {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: var(--text-logo);
  letter-spacing: var(--tracking-tight);
  line-height: 1;
}

.price-card__label {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  opacity: .75;
}

/* ---- Acento de textura — la misma trama placeholder de .service-card,
   en un papel secundario: esquina pequeña, no a sangre completa, y
   teñida vía currentColor + blend-mode para que se sienta "a medida"
   de cada bloque de color en vez de repetida sin más. ---- */
.offer__texture-accent {
  position: absolute;
  top: 0;
  right: 0;
  width: 14rem;
  height: 14rem;
  opacity: .35;
  pointer-events: none;
  background-image: repeating-linear-gradient(
    135deg,
    currentColor 0px,
    currentColor 2px,
    transparent 2px,
    transparent 14px
  );
  mix-blend-mode: overlay;
}

@media (max-width: 640px) {
  .offer__texture-accent {
    width: 8rem;
    height: 8rem;
  }
}

/* ----------------------------------------------------------------
   Cabecera del calendario — reutiliza el sistema tipográfico actual
   de home (.what-is-zuekin__label/.location__eyebrow y
   .what-is-zuekin__lead/.location__text), no el .offer__eyebrow/
   __title más antiguo que sigue usando el resto de páginas de
   servicio (nutrición, psicología, fisioterapia...). Mismos valores
   exactos que esas reglas, no una aproximación — ver comentarios ahí.
   Gap del wrapper (--space-3) calca el de .location__info, más
   ceñido que el --space-4 de .offer__col. ---------------------------------------------------------------- */
.calendar-header {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* = .what-is-zuekin__label / .location__eyebrow */
.calendar-header__eyebrow {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--tracking-display);
  font-size: var(--text-base);
  color: var(--color-ink);
}

/* = .what-is-zuekin__lead / .location__text */
.calendar-header__lead {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(1.125rem, 1.04rem + .38vw, 1.625rem);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink);
  max-width: 32ch;
}

/* ----------------------------------------------------------------
   Horario — calendario real (CSS Grid): columnas = días, filas =
   franjas de altura fija (--calendar-slot). Cada franja ocupada es
   su propia tarjeta independiente — misma unidad mínima que la hoja
   de origen (una hora con actividad = una entrada), sin fusionar
   horas consecutivas en un rectángulo. Las posiciones son datos, no
   un patrón CSS — se fijan por elemento vía style="" (grid-column/
   grid-row) en la plantilla. Cero border-radius: geometría angular
   igual que el resto del sitio.

   Líneas internas retiradas — antes había una marca horizontal por
   hora dibujada como fondo repetido en cada columna de día. Con
   franjas fusionadas en rectángulos grandes tenía sentido (ayudaba a
   leer dónde caía cada hora dentro del bloque); con una tarjeta por
   franja esa marca ya no aporta nada — cada tarjeta define su propio
   borde y su posición ya la da la etiqueta de hora a la izquierda,
   así que la línea de fondo solo añadía ruido de "hoja de cálculo".
   Se mantienen el borde de cabecera de día (separa nombres de días
   del cuerpo) y el borde de columna de horas (separa etiquetas de
   hora del resto) porque esos sí definen los ejes del calendario.

   Tarjeta — mismo lenguaje que .price-card (border: 1px solid, sin
   sombra, sin radius), no un color-fill nuevo: cada franja activa es
   una tarjeta con su propio borde en los 4 lados y un pequeño margen
   dentro de su celda de grid, para que se lea como una pieza flotando
   sobre el lienzo Lino en vez de un relleno pegado a la celda vecina.

   Lienzo — las 3 páginas comparten fondo Lino (el sitio no tiene ese
   token; se usa --color-cream como sustituto, misma convención que
   .service-card--cream). El color de servicio (Carbon/Cream/Arenisca,
   el mismo que su tarjeta en home) vive en la tarjeta de franja vía
   modificador .calendar__block--*, no en la sección entera.

   Contraste verificado (WCAG, luminancia relativa real, no asumida;
   sin cambios respecto al pase anterior, ver git history si hace
   falta recalcular): Carbon vs Lino = 12.29:1. Arenisca vs Lino =
   1.74:1 — invisible como relleno plano, por eso Cream/Arenisca
   llevan borde ink sólido (no el hairline de --border-hairline), que
   resuelve el 3:1 mínimo de WCAG 1.4.11 para límites de objetos
   gráficos con independencia del contraste del relleno. Etiqueta ink
   sobre Arenisca = 7.06:1. Etiqueta ink sobre Cream ≈ 12:1. Etiqueta
   cream sobre Carbon = 12.29:1. Todas por encima de 4.5:1 (AA). */
.calendar-wrap {
  overflow-x: auto;
  padding: var(--space-3) 0;
}

.calendar {
  --calendar-slot: 2.25rem;
  display: grid;
  grid-template-columns: minmax(3.75rem, auto) repeat(var(--calendar-days), minmax(5.5rem, 1fr));
  grid-template-rows: auto repeat(var(--calendar-slots), var(--calendar-slot));
  min-width: 36rem;
}

.calendar__day {
  grid-row: 1;
  padding: var(--space-4) var(--space-1);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-xs);
  text-transform: uppercase;
  text-align: center;
  letter-spacing: var(--tracking-wide);
  color: var(--color-ink-mid);
  border-bottom: var(--border-hairline);
}

.calendar__hour {
  grid-column: 1;
  padding: 0 var(--space-3) 0 0;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-ink-mid);
  text-align: right;
  border-right: var(--border-hairline);
  align-self: start;
  transform: translateY(-.5em);
}

.calendar__track {
  grid-row: 2 / -1;
  border-right: var(--border-hairline);
}

.calendar__block {
  margin: 2px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-2);
  text-align: center;
}

.calendar__block-label {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: var(--text-base);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
}

/* Entrenamiento Funcional — mismo Carbon que su tarjeta en home. Sin
   borde: 12.29:1 contra Lino, de sobra para leerse como tarjeta
   propia solo con el relleno. */
.calendar__block--carbon {
  background: var(--color-ink);
}
.calendar__block--carbon .calendar__block-label {
  color: var(--color-cream);
}

/* Pilates — mismo Cream que su tarjeta en home; idéntico al lienzo
   Lino (0:1 de contraste), así que un relleno sin borde sería
   literalmente invisible — no es un matiz estético, es la misma
   celda que una vacía. Sin `border` (como se pidió), pero el límite
   sigue haciendo falta: box-shadow inset del mismo grosor/color que
   el borde que sustituye, ya que no es una sombra decorativa (sin
   blur, sin offset) sino la única forma de dibujar ese límite sin la
   propiedad border. Nota: esto sí choca con el "cero sombras" que
   rige el resto del sitio (.price-card, etc.) — lo dejo señalado en
   vez de decidirlo en silencio. */
.calendar__block--cream {
  background: var(--color-cream);
  box-shadow: inset 0 0 0 var(--border-w) var(--color-ink);
}
.calendar__block--cream .calendar__block-label {
  color: var(--color-ink);
}

/* Yoga — mismo Arenisca que su tarjeta en home; 1.74:1 contra Lino,
   por debajo del mínimo de WCAG 1.4.11 (3:1) para límites de objetos
   gráficos — mismo problema y mismo tratamiento que Cream. */
.calendar__block--arenisca {
  background: var(--color-arenisca);
  box-shadow: inset 0 0 0 var(--border-w) var(--color-ink);
}
.calendar__block--arenisca .calendar__block-label {
  color: var(--color-ink);
}

/* Nota al pie del calendario — antes vivía arriba como .offer__pending
   (text-sm italic), compitiendo con el titular. Ahora es una leyenda
   discreta debajo de la rejilla: --text-2xs es el mismo token que ya
   usa el sitio para "footer / info-label", el registro correcto para
   una aclaración, no una segunda línea de copy. Vive en su propio
   .offer__col junto al calendario (gap más corto que el que separa
   la cabecera del calendario) para leerse pegada a lo que aclara. */
.calendar__footnote {
  font-family: var(--font-body);
  font-style: italic;
  font-size: var(--text-2xs);
  color: var(--color-ink-mid);
}

@media (max-width: 640px) {
  .calendar {
    --calendar-slot: 2rem;
  }

  .calendar__block-label {
    font-size: var(--text-sm);
  }
}

/* ---- CTA de cierre de página — full-bleed, misma foto vía
   --service-bg-image (o la textura placeholder si no se ha fijado
   ninguna todavía). Bloque entero clicable, como .service-card. ---- */
.closing-cta {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 24rem;
  text-decoration: none;
  color: var(--color-white);
  background-color: var(--color-ink-low);
  background-size: cover;
  background-position: center;
  background-image: var(--service-bg-image, repeating-linear-gradient(
    135deg,
    var(--color-ink-low) 0px,
    var(--color-ink-low) 2px,
    transparent 2px,
    transparent 14px
  ));
}

.closing-cta::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(20, 18, 16, .55);
  transition: background-color var(--duration-fast) var(--ease-out);
  pointer-events: none;
}

/* ---- Variante de color sólido (Musgo) — mismo criterio que
   .service-card--color en el home: fondo de marca en vez de foto, sin
   el overlay de contraste que las fotos sí necesitan (::before
   desactivado, mismo patrón que .service-card--color::before). Ninguna
   página de servicio tiene hoy una foto real asignada a su CTA de
   cierre (--service-bg-image nunca se fija ahí, solo cae en el
   placeholder rayado por defecto) — por eso esta variante es la que
   usan las 9 instancias actuales (7 páginas de servicio + open-gym +
   contacto). La clase base .closing-cta se queda intacta con su
   comportamiento de foto + overlay para el día que alguna sí tenga
   una foto real. ---- */
.closing-cta--color {
  background-image: none;
  background-color: var(--color-musgo);
}

.closing-cta--color::before {
  content: none;
}

.closing-cta:hover::before {
  background: rgba(20, 18, 16, .7);
}

.closing-cta__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
  padding: var(--space-6);
}

.closing-cta__subtext {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-widest);
  color: rgba(255, 255, 255, .75);
}

.closing-cta__title {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-size: clamp(2rem, 1.4rem + 3vw, 3.5rem);
}

.closing-cta__title svg {
  width: 1.5rem;
  height: 1.5rem;
  stroke: currentColor;
  stroke-width: 1.6;
  fill: none;
  transition: transform var(--duration-fast) var(--ease-out);
}

.closing-cta:hover .closing-cta__title svg {
  transform: translateX(.4rem);
}

@media (prefers-reduced-motion: reduce) {
  .closing-cta__title svg {
    transition: none !important;
  }
}

/* ---- Botones de tienda (App Store/Google Play), /app/ — URLs reales
   (ver templates/pages/app.html), ya no href="#" deshabilitado. Botón
   con borde en vez de relleno sólido: dos CTA uno junto al otro bajo
   el titular grande, un borde se lee como acción sin competir con
   .closing-cta__title. Mismo radius/duración que el resto de botones
   del sitio (--radius-sm). margin-top subido de --space-2 a --space-4:
   con los botones ya activos (antes atenuados/"próximamente") pesan
   más visualmente y piden más aire respecto al titular de arriba. ---- */
.closing-cta__store-links {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
}

.closing-cta__store-link {
  display: inline-block;
  border: 1px solid var(--color-cream);
  border-radius: var(--radius-sm);
  padding: .75rem 1.5rem;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  text-transform: uppercase;
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-tight);
  color: var(--color-cream);
  text-decoration: none;
  transition: transform var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out);
}

.closing-cta__store-link:hover,
.closing-cta__store-link:focus-visible {
  background: rgba(242, 237, 228, .12);
  transform: scale(1.03);
}

@media (prefers-reduced-motion: reduce) {
  .closing-cta__store-link {
    transition: none !important;
  }
}

/* ---- Pricing accordion — mismo mecanismo que .faq (<details>/<summary>,
   cero JS, marcador que rota vía [open]), pero como componente aparte:
   columna más estrecha que el texto de arriba (~60%, no a todo lo ancho),
   marcador SVG círculo+cruz en vez de un "+" por ::after, y el precio
   revelado a la escala tipográfica grande de .price-card__value. No
   toca .faq* en ningún momento — cero riesgo de afectar a la FAQ real. ---- */
.pricing-accordion {
  max-width: 26rem;
  display: flex;
  flex-direction: column;
}

/* Modificador opcional — columna ~60% en vez de la estrecha por defecto,
   para páginas donde la sección de precios es el bloque principal (ej.
   /entrenamiento-funcional/). No toca .pricing-accordion base, así que
   la instancia ya existente en /entrenamiento/ no se ve afectada. */
.pricing-accordion--wide {
  max-width: 60%;
}

@media (max-width: 640px) {
  .pricing-accordion--wide {
    max-width: 100%;
  }
}

.pricing-accordion__item {
  border-top: var(--border-hairline);
  padding: var(--space-3) 0;
}

.pricing-accordion__item:last-child {
  border-bottom: var(--border-hairline);
}

.pricing-accordion__question {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-inline: var(--space-2);
  margin-inline: calc(var(--space-2) * -1);
  /* Es un trigger clicable con fondo propio en hover — mismo radio que
     el resto de botones del sitio (--radius-sm), no las esquinas vivas
     a secas del resto de la fila (border-top de .pricing-accordion__item
     sigue recto, solo el fondo de hover redondea). */
  border-radius: var(--radius-sm);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: var(--text-base);
  letter-spacing: var(--tracking-tight);
  transition: background-color var(--duration-fast) var(--ease-out);
}

.pricing-accordion__question:hover {
  background: color-mix(in srgb, currentColor 8%, transparent);
}

.pricing-accordion__question::-webkit-details-marker {
  display: none;
}

.pricing-accordion__icon {
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
  stroke: currentColor;
  stroke-width: 1.4;
  fill: none;
  transition: transform var(--duration-fast) var(--ease-out);
}

.pricing-accordion__item[open] .pricing-accordion__icon {
  transform: rotate(45deg);
}

.pricing-accordion__question:hover .pricing-accordion__icon {
  transform: scale(1.15);
}

.pricing-accordion__item[open] .pricing-accordion__question:hover .pricing-accordion__icon {
  transform: rotate(45deg) scale(1.15);
}

.pricing-accordion__description {
  margin-top: var(--space-2);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-loose);
  opacity: .75;
}

.pricing-accordion__price {
  margin-top: var(--space-2);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: var(--text-logo);
  letter-spacing: var(--tracking-tight);
  line-height: 1;
}

@media (prefers-reduced-motion: reduce) {
  .pricing-accordion__icon {
    transition: none !important;
  }
}

/* ---- FAQ — acordeón nativo <details>/<summary>, cero JS nuevo.
   Reutiliza solo tokens ya existentes (espaciado, tipografía, color,
   hairline), ningún valor de diseño nuevo. ---- */
.faq {
  max-width: 42rem;
  display: flex;
  flex-direction: column;
}

/* Modificador opcional, mismo criterio que .pricing-accordion--wide:
   columna ~60% en vez de la estrecha por defecto. No toca .faq base,
   así que la FAQ real de /entrenamiento/ no se ve afectada. */
.faq--wide {
  max-width: 60%;
}

@media (max-width: 640px) {
  .faq--wide {
    max-width: 100%;
  }
}

.faq__item {
  border-top: var(--border-hairline);
  padding: var(--space-4) 0;
}

.faq__item:last-child {
  border-bottom: var(--border-hairline);
}

.faq__question {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-inline: var(--space-2);
  margin-inline: calc(var(--space-2) * -1);
  /* Mismo criterio que .pricing-accordion__question: trigger clicable
     con fondo propio en hover, mismo radio que el resto de botones del
     sitio (--radius-sm). */
  border-radius: var(--radius-sm);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: var(--text-base);
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink);
  transition: background-color var(--duration-fast) var(--ease-out);
}

.faq__question:hover {
  background: color-mix(in srgb, currentColor 8%, transparent);
}

.faq__question::-webkit-details-marker {
  display: none;
}

.faq__question::after {
  content: "+";
  flex-shrink: 0;
  font-family: var(--font-body);
  font-weight: 400;
  transition: transform var(--duration-fast) var(--ease-out);
}

.faq__item[open] .faq__question::after {
  transform: rotate(45deg);
}

.faq__question:hover::after {
  transform: scale(1.15);
}

.faq__item[open] .faq__question:hover::after {
  transform: rotate(45deg) scale(1.15);
}

.faq__answer {
  margin-top: var(--space-3);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-loose);
  color: var(--color-ink-mid);
}

@media (prefers-reduced-motion: reduce) {
  .faq__question::after {
    transition: none !important;
  }
}

  /* ============================================================
   LOCATION — .location__info es una sola columna (eyebrow + texto
   apilados, ambos left-aligned), no el mecanismo de grid de
   .what-is-zuekin__inner — decisión revisada: aquí el contenido es UN
   párrafo largo con enlaces, no un label + bloque de columnas
   separado, así que no gana nada partiéndolo en dos columnas y sí
   pierde ancho de lectura. El mapa sigue como bloque aparte debajo, a
   todo lo ancho. Full-bleed como .about-photo/.what-is-zuekin (el
   padding de la sección ES el inset, sin max-width extra encima).

   .location__text usa el mismo tratamiento display-voice (bold/
   italic/uppercase) que .what-is-zuekin__lead — mismo registro
   tipográfico que el resto de titulares/CTAs del sitio, no el cuerpo
   normal que llevaba antes. text-align: left explícito a propósito,
   para que quede claro que NO debe centrarse si algún estilo de
   sección padre cambia más adelante.
   ============================================================ */
.location {
  width: 100%;
  background: var(--color-cream);
  padding: clamp(2.5rem, 4vw, 3.125rem) var(--gutter);
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  /* #location es el destino de "Contacto" en zuekin-nav (home.html) —
     mismo motivo que scroll-margin-top en .hero. */
  scroll-margin-top: 4rem;
}

.location__info {
  max-width: var(--max-content-width);
  margin-inline: auto;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  text-align: left;
}

.location__eyebrow {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--tracking-display);
  font-size: var(--text-base);
  color: var(--color-ink);
}

.location__text {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  text-transform: uppercase;
  /* Mismo clamp que .what-is-zuekin__lead — mismo registro/tamaño de
     titular, reutilizado en vez de un valor nuevo sin relación. */
  font-size: clamp(1.125rem, 1.04rem + .38vw, 1.625rem);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink);
  text-align: left;
  max-width: 60ch;
}

.location__text a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color var(--duration-fast) var(--ease-out);
}

.location__text a:hover,
.location__text a:focus-visible {
  color: var(--color-musgo);
}

.location__text a:focus-visible {
  outline: 2px solid var(--color-ink);
  outline-offset: 3px;
}

/* Misma lógica de --radius-soft que .about-photo__inner. Altura del
   Figma (460px fijos) convertida a min-height fluido, no aspect-ratio
   ni valor fijo. */
.location__map {
  position: relative;
  min-height: clamp(22rem, 38vw, 30rem);
  border-radius: var(--radius-soft);
  overflow: hidden;
  background-color: var(--color-ink-low);
}

/* Se probó teñir el iframe vía filter (grayscale/sepia/hue-rotate)
   para acercar los colores de Maps a Arenisca/Musgo — descartado:
   un filter CSS afecta a TODO el iframe por igual, no puede tratar
   agua/parques/calles por separado, así que cualquier ajuste que
   mejora un elemento empeora otro. Colores de Maps sin tocar; el
   único camino real a un color de marca exacto es Google Maps
   JavaScript API + Styled Maps JSON (de pago), fuera de alcance. */
.location__map iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ============================================================
   VALORACIÓN CTA — última sección del home antes del footer. Mismo
   contenido que la antigua .closing-cta--bridge (ya no existe en el
   sitio), reconstruido como componente nuevo, no una restauración del
   código anterior — nombre propio (.valoracion-cta) para no generar
   confusión con esa clase retirada.

   Full-bleed (igual que .coming-soon/.about-photo): el padding de la
   sección ES el inset, sin max-width propio en el elemento raíz.
   .valoracion-cta__inner sí lleva max-width (44rem ≈ Figma 788px) y
   centra el contenido.

   Tamaños reutilizados, no inventados: __subtext usa el MISMO clamp
   que .coming-soon__text (~20px a 1440px, ya calculado para un texto
   de peso visual equivalente). __text usa --text-base (~16px,
   coincide con el 16px de Figma) + --leading-snug (1.3125, coincide
   con la proporción 16/21 del line-height de Figma) — .coming-soon no
   tiene una variante "muted" de tamaño propio (--muted allí solo
   cambia weight/style, no tamaño), así que no hay nada que reutilizar
   1:1 para eso; de ahí ir directo a los tokens base más cercanos.

   --radius-sm en el botón (no --radius-soft): es un botón, no un
   bloque de foto — ver comentario de --radius-sm en :root.
   ============================================================ */
.valoracion-cta {
  width: 100%;
  background: var(--color-musgo);
  display: flex;
  justify-content: center;
  padding-block: clamp(4rem, 7vw, 5.5rem);
  padding-inline: var(--gutter);
}

.valoracion-cta__inner {
  max-width: 44rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Ahora solo separa .valoracion-cta__copy del botón — el gap entre
     subtext y párrafo vive aparte, más ajustado (ver __copy). */
  gap: var(--space-6);
}

.valoracion-cta__copy {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

.valoracion-cta__subtext {
  font-size: clamp(1rem, .91rem + .38vw, 1.3rem);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-display);
  color: var(--color-cream);
  text-align: center;
}

.valoracion-cta__text {
  font-size: var(--text-base);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-display);
  color: var(--color-cream);
  text-align: center;
}

.valoracion-cta__button {
  display: inline-block;
  background: var(--color-cream);
  color: var(--color-ink);
  border-radius: var(--radius-sm);
  padding: clamp(.75rem, 1.5vw, 1rem) clamp(1.5rem, 3vw, 2rem);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--tracking-display-tight);
  font-size: var(--text-base);
  text-decoration: none;
  transition: transform var(--duration-fast) var(--ease-out);
}

.valoracion-cta__button:hover,
.valoracion-cta__button:focus-visible {
  transform: scale(1.03);
}

@media (prefers-reduced-motion: reduce) {
  .valoracion-cta__button {
    transition: none !important;
  }
}

/* ============================================================
   Site Footer — compartido por TODAS las páginas (ver
   scripts/build.mjs → renderFooter()/renderDocument()). Geometría
   angular como el resto del sitio: cero border-radius.

   4 columnas (Marca/Servicios/Centro/Contacto) sobre Carbon — por eso
   NO se reutiliza --border-hairline (var(--color-ink-low), pensado
   para fondos claros: sobre Carbon sería casi invisible). El divisor
   entre columnas y barra inferior usa un cream translúcido en su
   lugar, mismo criterio que .closing-cta__quote (rgba cream sobre
   fondo oscuro).
   ============================================================ */
.site-footer {
  width: 100%;
  background: var(--color-ink);
  /* Bottom reducido de --space-6 a --space-4: es lo que le da al bloque
     inferior (copyright/crédito) su aire por debajo — con --space-6 se
     leía como otro bloque más, no como una tira de cierre. */
  padding-block: var(--space-8) var(--space-4);
  padding-inline: var(--gutter);
  /* Todo el texto del footer en mayúsculas — puesto aquí en vez de en
     cada clase hija porque text-transform hereda: cubre título de
     columna (ya lo tenía explícito), links, tagline, dirección/email,
     copyright y crédito sin repetir la propiedad cinco veces. */
  text-transform: uppercase;
}

.site-footer__inner {
  max-width: var(--max-content-width);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  align-items: start;
  /* --space-4 en vez de --space-6 (mismo gap que .services__track entre
     tarjetas — --services-gap: var(--space-4) — para reutilizar un
     ritmo ya establecido en vez de un valor suelto). */
  gap: var(--space-4);
  padding-bottom: var(--space-7);
  border-bottom: 1px solid rgba(242, 237, 228, .15);
}

.site-footer__col {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.site-footer__logo {
  display: flex;
  color: var(--color-cream);
  width: 6.5rem;
}

.site-footer__logo svg {
  width: 100%;
  height: auto;
}

.site-footer__tagline {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-loose);
  color: rgba(242, 237, 228, .8);
  max-width: 26ch;
}

.site-footer__social {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.site-footer__social a {
  display: flex;
  align-items: center;
  color: rgba(242, 237, 228, .8);
  transition: color var(--duration-fast), transform var(--duration-fast);
  text-decoration: none;
}

.site-footer__social a:hover,
.site-footer__social a:focus-visible {
  color: var(--color-cream);
  transform: translateY(-2px);
}

.site-footer__social a:focus-visible {
  outline: 2px solid var(--color-cream);
  outline-offset: 3px;
}

.site-footer__social svg {
  width: var(--icon-social-size);
  height: var(--icon-social-size);
  fill: none;
  stroke: currentColor;
  stroke-width: var(--icon-social-stroke);
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Antes bold/italic/display — competía en peso visual con los propios
   links de abajo en vez de leerse como una etiqueta. Se reutiliza el
   mismo tratamiento que .closing-cta__subtext (label muda en
   mayúsculas sobre fondo oscuro, ya establecido en el sitio): sin
   negrita, sin cursiva, fuente body, tracking-widest, color atenuado —
   no compite con los links, los antecede con claridad. */
.site-footer__col-title {
  font-family: var(--font-body);
  /* text-transform: uppercase ya viene heredado de .site-footer. */
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-widest);
  color: rgba(242, 237, 228, .6);
}

.site-footer__links {
  display: flex;
  flex-direction: column;
  /* --space-1 en vez de --space-2: ritmo vertical más apretado entre
     links de la misma columna — --space-2 se leía como demasiado
     espacio para elementos tan afines entre sí. */
  gap: var(--space-1);
}

/* Subrayado direccional en vez de un cambio de color a secas: crece
   desde la izquierda al entrar el cursor, se retira hacia la derecha
   al salir — no un scaleX simétrico desde el centro. display:inline
   con position:relative es suficiente para anclar el ::after sin
   convertir el link en un bloque (mantendría el mismo layout de lista
   vertical que ya hay). */
.site-footer__links a {
  position: relative;
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: rgba(242, 237, 228, .8);
  text-decoration: none;
  transition: color var(--duration-fast);
}

.site-footer__links a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform var(--duration-base) var(--ease-in-out);
}

.site-footer__links a:hover,
.site-footer__links a:focus-visible {
  color: var(--color-cream);
}

.site-footer__links a:hover::after,
.site-footer__links a:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left center;
}

.site-footer__links a:focus-visible {
  outline: 2px solid var(--color-cream);
  outline-offset: 3px;
}

/* "Conoce nuestra app" — mismo criterio de disabled que .nav-link.
   is-disabled/.panel-link.is-disabled en zuekin-nav (opacidad reducida,
   cursor: not-allowed, sin el subrayado de hover que sí tienen los
   links reales): no puede ser la MISMA regla porque el nav vive en
   Shadow DOM, esta es su equivalente en el DOM claro. */
.site-footer__links .is-disabled {
  position: relative;
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: rgba(242, 237, 228, .4);
  cursor: not-allowed;
}

.site-footer__info {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.site-footer__info p,
.site-footer__info a {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  color: rgba(242, 237, 228, .8);
  text-decoration: none;
}

/* Mismo subrayado direccional que .site-footer__links — es un link de
   texto igual que esos, solo que vive en otra columna. */
.site-footer__info a {
  position: relative;
  display: inline-block;
}

.site-footer__info a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform var(--duration-base) var(--ease-in-out);
}

.site-footer__info a:hover,
.site-footer__info a:focus-visible {
  color: var(--color-cream);
}

.site-footer__info a:hover::after,
.site-footer__info a:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left center;
}

.site-footer__info a:focus-visible {
  outline: 2px solid var(--color-cream);
  outline-offset: 3px;
}

.site-footer__bottom {
  max-width: var(--max-content-width);
  margin-inline: auto;
  /* --space-4 en vez de --space-5: junto con el padding-bottom de
     .site-footer (también reducido), esta tira debe leerse fina, no
     como un bloque más del mismo peso que las columnas de arriba. */
  padding-top: var(--space-4);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-2) var(--space-5);
}

.site-footer__bottom p {
  font-family: var(--font-body);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide);
  color: rgba(242, 237, 228, .6);
}

.site-footer__bottom a {
  color: rgba(242, 237, 228, .6);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color var(--duration-fast);
}

.site-footer__bottom a:hover,
.site-footer__bottom a:focus-visible {
  color: var(--color-cream);
}

.site-footer__bottom a:focus-visible {
  outline: 2px solid var(--color-cream);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .site-footer__social a,
  .site-footer__links a,
  .site-footer__links a::after,
  .site-footer__info a::after {
    transition: none !important;
  }
}

@media (max-width: 900px) {
  .site-footer__inner {
    grid-template-columns: 1fr 1fr;
  }

  .site-footer__col--brand {
    grid-column: 1 / -1;
  }
}

@media (max-width: 640px) {
  .site-footer__inner {
    grid-template-columns: 1fr;
  }

  .site-footer__col--brand {
    grid-column: auto;
  }

  .site-footer__bottom {
    flex-direction: column;
  }
}

/* ============================================================
   CONTACTO — texto de email visible/seleccionable bajo el CTA
   mailto: de .closing-cta (ver templates/pages/contacto.html). No es
   un componente reutilizable en otras páginas, así que vive suelto
   aquí en vez de junto a un bloque de sección con su propio comentario
   de cabecera — solo aporta tipografía a partir de tokens ya
   existentes, nada nuevo.
   ============================================================ */
.contacto-email {
  max-width: 30rem;
  margin-inline: auto;
  padding: var(--space-6) var(--gutter);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  text-align: center;
  color: var(--color-ink);
}

.contacto-email strong {
  font-weight: 700;
}