/* ============================================================
   Essenzia — Design tokens (see DESIGN.md)
   ============================================================ */
:root {
  --color-matcha: #809671;
  --color-chai: #D2AB80;
  --color-vainilla: #E5D2B8;
  --color-vainilla-rgb: 229, 210, 184;
  --color-cream: #FBF7EF;
  --color-ink: #2B241F;
  --color-ink-muted: #5C5248;
  --color-hairline: rgba(43, 36, 31, 0.12);
  --color-hairline-on-dark: rgba(251, 247, 239, 0.28);
  --color-scrim-rgb: 20, 16, 12; /* espresso-ink, deepened for photo-legibility scrims only */

  --font-display: "Instrument Serif", Georgia, serif;
  --font-body: "Switzer", -apple-system, BlinkMacSystemFont, sans-serif;

  /* Type scale — see DESIGN.md Typography */
  --text-micro: 0.6875rem;
  --text-xs: 0.8125rem;
  --text-sm: 0.9375rem;
  --text-body: 1.0625rem;
  --text-md: 1.125rem;
  --text-quote: clamp(1.25rem, 1.7vw, 1.5rem);
  --text-title: 1.5rem;
  --text-h3: clamp(1.875rem, 2.5vw, 2.25rem);
  --text-headline-quote: clamp(2.5rem, 5vw, 3.5rem);
  --text-headline: clamp(2.125rem, 5vw, 3.5rem);
  --text-hero-brand: clamp(2.5rem, 6vw, 4.5rem);
  --text-menu-link: clamp(2.5rem, 7vw, 5rem);

  --space-xs: 0.5rem;
  --space-sm: 1rem;
  --space-md: 2rem;
  --space-lg: 4rem;
  --space-xl: 7.5rem;
  --space-xl-mobile: 4rem;

  --radius-pill: 999px;
  --radius-lg: 28px; /* hero-frame only — see DESIGN.md Shapes deviation note */
  --radius-lg-mobile: 18px;
  --container: 1280px;

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* Gates the hero's entrance animations (photo blur-in, mark/headline/
     tagline stagger) so they don't run — and finish — silently behind
     the preloader curtain before anyone can see them. js/main.js flips
     this to "running" the instant the curtain starts lifting. Defaults
     to "paused" only when a preloader is actually present and about to
     run it; see the reduced-motion override and js/main.js's no-
     preloader fallback for the two paths that release it immediately. */
  --hero-anim-state: paused;
}

/* ============================================================
   Reset
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body, h1, h2, h3, p, dl, dd, figure { margin: 0; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; background: none; border: none; cursor: pointer; }
ul { list-style: none; margin: 0; padding: 0; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0s !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }

  /* Hero cover transition is scroll-linked motion; disable the pin and
     force --hero-progress to 0 so the hero renders static, unblurred. */
  .hero-frame { position: static; --hero-progress: 0 !important; }

  /* Belt-and-suspenders alongside js/main.js's reduced-motion branch:
     even if script execution is somehow delayed, the hero never sits
     paused at its invisible "from" state under this preference. */
  :root { --hero-anim-state: running !important; }

  /* Gallery image reveal: force every photo fully visible and at true
     scale, regardless of whether JS has flipped data-revealed yet. */
  .gallery__item picture { clip-path: inset(0 0% 0 0) !important; transform: scale(1) !important; }
}

body {
  font-family: var(--font-body);
  color: var(--color-ink);
  background: var(--color-cream);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--color-ink);
  color: var(--color-cream);
  padding: 0.75rem 1.25rem;
  z-index: 1000;
}
.skip-link:focus {
  left: var(--space-sm);
  top: var(--space-sm);
}

:focus-visible {
  outline: 2px solid var(--color-matcha);
  outline-offset: 3px;
}

/* ============================================================
   Preloader — a brand curtain, not a progress bar: the mandala mark
   rotates into place (echoing its own pinwheel geometry) on Espresso
   Ink — the same dark surface as the hero frame's margin and Footer,
   the system's only two dark surfaces, so no new color enters — then
   the whole curtain rises to reveal the page underneath. "Ritual, not
   rutina" staged as a literal opening ritual before the page begins.
   Fixed authored timing driven from js/main.js (min/max budget, always
   the same choreography) rather than tied to network load — this is a
   rehearsed focal sequence, not a literal progress indicator, per
   animate.md. z-index sits above Nav (100) and the full-screen menu
   (200) but below the skip-link (1000), which must always win focus.
   The global prefers-reduced-motion reset above already zeroes these
   durations; js/main.js additionally skips the authored hold entirely
   in that case so reduced-motion users never stare at a static curtain.
   ============================================================ */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  background: var(--color-ink);
  transition: transform 0.7s var(--ease-out);
}
.preloader[data-exiting="true"] {
  transform: translateY(-100%);
}
.preloader__mark {
  display: block;
  width: 56px;
  height: 56px;
  color: var(--color-cream);
  opacity: 0;
  transform: scale(0.6) rotate(-70deg);
  animation: preloader-mark-in 0.8s var(--ease-out) 0.1s forwards;
}
.preloader__mark svg { width: 100%; height: 100%; }
/* Same lockup as the hero's own masthead (mark → brand name → tagline),
   at the same Hero Brand scale — the studio's name gets full presence
   here, not a shrunk-down afterthought, and the shared proportions are
   what make the curtain-lift read as one continuous reveal rather than
   a handoff between two differently-scaled brand marks. Reuses
   hero-rise-in verbatim (defined once, under Hero below) instead of a
   near-duplicate keyframe. */
.preloader__name {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-hero-brand);
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-cream);
  opacity: 0;
  animation: hero-rise-in 0.7s var(--ease-out) 0.35s forwards;
}
.preloader__tagline {
  font-family: var(--font-body);
  font-size: var(--text-micro);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-cream);
  opacity: 0;
  animation: preloader-tagline-in 0.6s var(--ease-out) 0.65s forwards;
}
@keyframes preloader-mark-in {
  to { opacity: 1; transform: scale(1) rotate(0deg); }
}
@keyframes preloader-tagline-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 0.75; transform: translateY(0); }
}

/* ============================================================
   Type utilities
   ============================================================ */
.eyebrow {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-matcha);
  margin-bottom: var(--space-sm);
}

.headline {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-headline);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--color-ink);
}

.title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-h3);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--color-ink);
}

/* ============================================================
   Buttons
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  padding: 1.125rem 2.5rem;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.08em;
  transition: background-color 0.25s var(--ease-out), color 0.25s var(--ease-out), border-color 0.25s var(--ease-out), transform 0.25s var(--ease-out);
  white-space: nowrap;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn--primary {
  background: transparent;
  color: var(--color-cream);
  border: 1px solid var(--color-cream);
}
.btn--primary:hover {
  background: var(--color-cream);
  color: var(--color-ink);
  border-color: var(--color-cream);
}

.btn--secondary {
  background: var(--color-ink);
  color: var(--color-cream);
  border: 1px solid var(--color-ink);
}
.btn--secondary:hover {
  background: var(--color-chai);
  border-color: var(--color-chai);
  color: var(--color-ink);
}

/* Chai fill — reserved for the trial-class CTA so it never reads as the
   same action as a future pricing "comprar paquete" button (btn--secondary,
   ink-filled). Inverse hover of btn--secondary on purpose: two buttons
   that swap fill/hover colors with each other read as clearly different
   actions, not just a different accent on the same button. */
.btn--chai {
  background: var(--color-chai);
  color: var(--color-ink);
  border: 1px solid var(--color-chai);
}
.btn--chai:hover {
  background: var(--color-ink);
  color: var(--color-cream);
  border-color: var(--color-ink);
}

/* ============================================================
   Nav
   ============================================================ */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  /* No fill — the nav stays fully transparent everywhere. Only its brand
     mark and menu-trigger text switch between cream and ink (below),
     keyed to whether the hero or the page's own light background sits
     behind the bar (see js/main.js). */
}

.nav__inner {
  max-width: var(--container);
  margin: 0 auto;
  padding: 1.25rem var(--space-md);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-md);
}

.nav__brand {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  color: var(--color-cream);
  transition: color 0.35s var(--ease-out);
}
.nav[data-scrolled="true"] .nav__brand { color: var(--color-ink); }

.nav__mark {
  width: 30px;
  height: 30px;
  display: block;
  flex-shrink: 0;
}
.nav__mark svg { width: 100%; height: 100%; }

.nav__wordmark {
  font-family: var(--font-display);
  font-size: var(--text-title);
  font-weight: 400;
  line-height: 1;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.nav__wordmark em {
  font-style: normal;
  font-family: var(--font-body);
  font-size: var(--text-micro);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0.75;
}

.nav__menu-btn {
  grid-column: 2;
  /* .site-menu is a DOM child of .nav (not a sibling), and it carries
     its own explicit z-index: 200. A plain grid item with no position
     of its own can't out-stack that regardless of .nav's z-index — only
     .nav's *other positioned children* compete with it directly. This
     is what actually restores DESIGN.md's documented "re-tapping Menú
     closes it too" behavior; without it, .site-menu's backdrop silently
     eats the click before it reaches this button. */
  position: relative;
  z-index: 201;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-cream);
  padding: 0.5rem 0.25rem;
  transition: color 0.35s var(--ease-out);
}
.nav[data-scrolled="true"] .nav__menu-btn { color: var(--color-ink); }
.nav[data-menu-open="true"] .nav__menu-btn { color: var(--color-cream) !important; }
.nav__menu-btn:hover { color: var(--color-matcha); }

/* ============================================================
   Site menu — full-screen takeover
   NOTE — deviation from DESIGN.md: this is the one place glass/blur
   appears in the system ("Don't introduce... glassmorphism"). Adopted
   deliberately, explicitly requested, for the menu backdrop only —
   every surface elsewhere stays flat/opaque per the standing system.
   ============================================================ */
/* The menu itself only scrolls (never clips) when its content is taller
   than the viewport. .site-menu is a plain single-column flex scroller
   (no centering here); .site-menu__scroll carries margin: auto 0 to do
   the actual centering. That split matters: centering via
   justify-content on the *scrollable* element lets overflowing content
   spill equally past both edges — including before the scrollable
   area's own start, which a straight overflow-y: auto can never reach,
   silently re-creating the exact "can't get to some of the menu"
   failure this was meant to fix. margin: auto instead resolves to 0
   once content is taller than the viewport, so the top of the content
   pins to the scroll start and 100% of it stays reachable. */
.site-menu {
  position: fixed;
  inset: 0;
  z-index: 200;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  pointer-events: none;
}
.site-menu[data-menu-open="true"] {
  pointer-events: auto;
}

.site-menu__backdrop {
  position: fixed;
  inset: 0;
  background: rgba(var(--color-scrim-rgb), 0);
  backdrop-filter: blur(0px);
  -webkit-backdrop-filter: blur(0px);
  /* Fast on close (matches the links' 0.35s) so the scrim never
     outlasts the content it's behind — see .site-menu__item a above. */
  transition: background-color 0.35s var(--ease-out), backdrop-filter 0.35s var(--ease-out), -webkit-backdrop-filter 0.35s var(--ease-out);
  will-change: background-color, backdrop-filter;
}
.site-menu[data-menu-open="true"] .site-menu__backdrop {
  /* Opaque enough to read on its own, blur is an enhancement on top —
     not the other way around. iOS Low Power Mode (and the system
     Reduce Transparency setting) disables backdrop-filter blur
     entirely; at the old 0.55 alpha that left only a faint tint, so
     the hero photo and headline underneath stayed fully legible and
     visually jumbled with the menu links on top of them — which is
     what read as the menu being "stuck"/broken on a real iPhone. */
  background: rgba(var(--color-scrim-rgb), 0.92);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  transition-duration: 0.8s;
}

.site-menu__scroll {
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  width: 100%;
  margin: auto 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-lg);
  padding: var(--space-xl) var(--space-md);
}

.site-menu__links {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: fit-content;
  max-width: 92vw;
}

.site-menu__item {
  overflow: hidden;
  text-align: center;
}
.site-menu__item + .site-menu__item {
  border-top: 1px solid transparent;
  transition: border-color 0.6s var(--ease-out);
}
.site-menu[data-menu-open="true"] .site-menu__item + .site-menu__item {
  border-color: var(--color-hairline-on-dark);
}
/* Closing was the actual mobile bug: the stagger (0/80/160/240ms) was a
   plain inline transition-delay, so it applied in BOTH directions. On
   open that reads as a nice cascade; on close it meant "Clases" (0ms
   delay) started retracting immediately while "Contacto" (240ms) was
   still fully visible for another quarter-second — and closing a link
   also navigates (Lenis smooth-scrolls to the target section), so the
   ~0.9s+240ms close was racing a ~1.1s scroll. For that whole window
   the still-animating menu sat at z-index 200 on top of a page that
   had already jumped to its destination underneath — which is exactly
   what read as "Clases stuck in overlay" with "a bounce". Fix: close
   is now fast and unstaggered (all links retract together in 0.35s,
   the same instant tap-to-close feels everywhere); the slow staggered
   rise is scoped to the open state only, via :nth-child instead of the
   old inline style attribute so it can never leak into the close. */
.site-menu__item a {
  display: inline-block;
  width: 100%;
  padding: 0.35em 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-menu-link);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--color-cream);
  transform: translateY(100%);
  transition: transform 0.35s var(--ease-out);
  will-change: transform;
}
.site-menu[data-menu-open="true"] .site-menu__item a {
  transform: translateY(0);
  transition: transform 0.9s var(--ease-out);
}
.site-menu[data-menu-open="true"] .site-menu__item:nth-child(1) a { transition-delay: 0ms; }
.site-menu[data-menu-open="true"] .site-menu__item:nth-child(2) a { transition-delay: 80ms; }
.site-menu[data-menu-open="true"] .site-menu__item:nth-child(3) a { transition-delay: 160ms; }
.site-menu[data-menu-open="true"] .site-menu__item:nth-child(4) a { transition-delay: 240ms; }
.site-menu__item a:hover { color: var(--color-matcha); }

/* ============================================================
   Hero
   ============================================================
   NOTE — deviation from DESIGN.md, requested explicitly via reference
   screenshot (framed/inset hero card): this is the one place in the
   system that uses border-radius on a content block (--radius-lg).
   Scoped to .hero-frame only; every other section stays flat/square
   per the standing system.
   ============================================================ */
.hero-stack {
  /* Bounds .hero-frame's sticky range to hero+mission only — once this
     wrapper scrolls out of view, the sticky hero releases naturally
     instead of staying pinned (and painting over, per stacking order)
     every section below it. */
  position: relative;
}

.hero-frame {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--color-ink);
  padding: var(--space-md);
  height: 100svh;
  box-sizing: border-box;
  --hero-progress: 0;
}

.hero {
  position: relative;
  height: 100%;
  border-radius: var(--radius-lg);
  overflow: hidden;
  filter:
    blur(calc(var(--hero-progress) * 6px))
    brightness(calc(1 - var(--hero-progress) * 0.35));
  will-change: filter;
}

.hero__media,
.hero__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 65% 25%;
}
.hero__media {
  transform:
    translateY(calc(var(--hero-progress) * -32px))
    scale(calc(1 + var(--hero-progress) * 0.08));
  will-change: transform;
}
.hero__media img {
  filter: saturate(0.92) brightness(1.04) contrast(0.98);
  animation: hero-photo-in 2.2s var(--ease-out) both;
  animation-play-state: var(--hero-anim-state);
  will-change: transform, filter;
}

/* The hero's one authored entrance: the photo arrives from a tighter,
   softer-focus crop and settles to true scale and clarity — a deliberate
   cinematic reveal, not the literal scale-from-zero a full-bleed cover
   photo would need (which reads as a glitch, not a moment). */
@keyframes hero-photo-in {
  from {
    transform: scale(1.32);
    filter: saturate(0.85) brightness(0.92) contrast(0.98) blur(18px);
  }
  to {
    transform: scale(1);
    filter: saturate(0.92) brightness(1.04) contrast(0.98) blur(0px);
  }
}

@keyframes hero-rise-in {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes hero-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.hero__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(var(--color-scrim-rgb), 0.6) 0%, rgba(var(--color-scrim-rgb), 0.4) 30%, rgba(var(--color-scrim-rgb), 0.44) 55%, rgba(var(--color-scrim-rgb), 0.76) 100%),
    linear-gradient(90deg, rgba(var(--color-scrim-rgb), 0.25) 0%, rgba(var(--color-scrim-rgb), 0.15) 100%);
}

.hero__content {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(calc(1 - var(--hero-progress, 0) * 0.06));
  opacity: calc(1 - var(--hero-progress, 0) * 0.5);
  z-index: 2;
  max-width: var(--container);
  width: 100%;
  padding: 0 var(--space-md);
  color: var(--color-cream);
  text-align: center;
  text-shadow: 0 1px 2px rgba(var(--color-scrim-rgb), 0.45), 0 8px 20px rgba(var(--color-scrim-rgb), 0.4);
}

.hero__mark {
  display: block;
  width: 56px;
  height: 56px;
  margin: 0 auto var(--space-sm);
  animation: hero-rise-in 0.7s var(--ease-out) 0.1s both;
}
.hero__mark svg { width: 100%; height: 100%; }

.hero__headline {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-hero-brand);
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: var(--space-xs);
  animation: hero-rise-in 0.8s var(--ease-out) 0.24s both;
}
.hero__headline-colon {
  color: var(--color-chai);
}

.hero__tagline {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-headline-quote);
  line-height: 1.1;
  margin: 0 auto var(--space-md);
  max-width: 26ch;
  animation: hero-rise-in 0.8s var(--ease-out) 0.38s both;
}

.hero__disciplines {
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(229, 210, 184, 0.85);
  margin: 0 auto var(--space-md);
  max-width: 46ch;
  animation: hero-rise-in 0.7s var(--ease-out) 0.52s both;
}

.hero__content .btn--primary {
  animation: hero-fade-in 0.6s var(--ease-out) 0.62s both;
}

.hero__meta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  margin-top: var(--space-md);
  font-size: var(--text-xs);
  color: rgba(251, 247, 239, 0.78);
  animation: hero-rise-in 0.7s var(--ease-out) 0.74s both;
  flex-wrap: wrap;
}

/* Every staggered hero-content entrance shares the same gate — see
   --hero-anim-state at :root. */
.hero__mark,
.hero__headline,
.hero__tagline,
.hero__disciplines,
.hero__content .btn--primary,
.hero__meta {
  animation-play-state: var(--hero-anim-state);
}
.hero__meta-divider {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.6;
}

/* ============================================================
   Mission
   ============================================================ */
.mission {
  position: relative;
  z-index: 2;
  padding: var(--space-xl) var(--space-md);
  background: var(--color-vainilla);
  box-shadow: 0 -32px 48px -24px rgba(var(--color-scrim-rgb), 0.4);
}
.mission__inner {
  max-width: 860px;
  margin: 0 auto;
  text-align: center;
}
.mission__headline {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-headline-quote);
  line-height: 1.1;
  margin-bottom: var(--space-md);
}
.mission__body {
  font-size: var(--text-md);
  line-height: 1.7;
  color: var(--color-ink-muted);
  max-width: 62ch;
  margin: 0 auto var(--space-md);
}
.mission__signature {
  font-family: var(--font-display);
  font-size: var(--text-md);
  color: var(--color-ink);
}

/* Word-by-word scroll reveal: [data-fill-text] words start blurred and
   faded, sharpening into place as the passage scrolls through view.
   See js/main.js for the scroll-linked progress calculation.
   No CSS transition here on purpose — the values are driven 1:1 from
   Lenis's own eased scroll tick, which is already the smoothing; a
   second, independently-timed transition retargeting on every update
   is what caused the stepped "lags then snaps into place" bug. */
.fill-word {
  display: inline-block;
  will-change: filter, opacity;
}

/* ============================================================
   Disciplines
   ============================================================ */
.disciplines {
  padding: var(--space-xl) var(--space-md);
  max-width: var(--container);
  margin: 0 auto;
}
.disciplines__head { margin-bottom: var(--space-lg); }

.disciplines__grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  border-top: 1px solid var(--color-hairline);
}
.discipline {
  padding: var(--space-md) var(--space-sm) var(--space-lg);
  border-right: 1px solid var(--color-hairline);
  border-bottom: 1px solid var(--color-hairline);
}
.discipline:last-child { border-right: none; }

.discipline:nth-child(1) { transition-delay: 0ms; }
.discipline:nth-child(2) { transition-delay: 70ms; }
.discipline:nth-child(3) { transition-delay: 140ms; }
.discipline:nth-child(4) { transition-delay: 210ms; }
.discipline:nth-child(5) { transition-delay: 280ms; }

.discipline__icon {
  width: 34px;
  height: 34px;
  color: var(--color-matcha);
  margin-bottom: var(--space-md);
}
.discipline .title { margin-bottom: 0.6rem; }
.discipline p {
  color: var(--color-ink-muted);
  font-size: var(--text-sm);
  line-height: 1.6;
}

.disciplines__foot {
  text-align: center;
  margin-top: var(--space-lg);
  font-family: var(--font-body);
  font-size: var(--text-sm);
}
.disciplines__foot a {
  color: var(--color-ink-muted);
  border-bottom: 1px solid var(--color-hairline);
  padding-bottom: 2px;
  transition: color 0.2s var(--ease-out), border-color 0.2s var(--ease-out);
}
.disciplines__foot a:hover { color: var(--color-matcha); border-color: var(--color-matcha); }

/* ============================================================
   Gallery — the one authored horizontal moment in the system.
   Desktop (>1024px) + no prefers-reduced-motion: .gallery__scroll is
   pinned (position: sticky) for a JS-computed vertical distance while
   js/main.js translates .gallery__track horizontally in lockstep with
   Lenis's scroll tick — the vertical scroll gesture sweeps through the
   photos left-to-right, then releases back into normal vertical flow.
   Tablet/mobile and reduced motion: .gallery__scroll never gets the
   `data-pinned="true"` flip, so it stays a plain native horizontally
   -scrollable strip with scroll-snap — swipeable, not scroll-hijacked.
   This is the default/no-JS state too, so the gallery is always usable.
   ============================================================ */
.gallery {
  padding: var(--space-xl) 0;
  background: var(--color-vainilla);
}
.gallery__head {
  max-width: var(--container);
  margin: 0 auto var(--space-lg);
  padding: 0 var(--space-md);
  text-align: center;
}
.gallery__head .eyebrow { justify-content: center; }

.gallery__scroll {
  position: relative;
}

.gallery__pin {
  display: flex;
  align-items: center;
}
.gallery__scroll[data-pinned="true"] .gallery__pin {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}

.gallery__track {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: 0 var(--space-md);
}
.gallery__scroll:not([data-pinned="true"]) .gallery__track {
  overflow-x: auto;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.gallery__track::-webkit-scrollbar { display: none; }

/* Right-edge fade on the swipeable (non-pinned) strip: a light cue that
   the track continues past the viewport. Kept narrow and low-opacity on
   purpose — the previous version faded all the way to solid background
   over 12vw, which wiped out the very peek it was supposed to reinforce
   and made the next item unreadable as a photo. */
.gallery__scroll:not([data-pinned="true"]) { position: relative; }
.gallery__scroll:not([data-pinned="true"])::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 28px;
  background: linear-gradient(to right, transparent, rgba(var(--color-vainilla-rgb), 0.55));
  pointer-events: none;
}

.gallery__item {
  flex: none;
  height: min(64vh, 560px);
  overflow: hidden;
  background: var(--color-hairline);
}
.gallery__scroll:not([data-pinned="true"]) .gallery__item {
  /* Sized so the widest (--wide) item stops well short of the viewport
     edge — the next item's photo (not just its sliver) peeks in to
     signal there's more to swipe, instead of the first photo filling
     the screen and looking final. */
  height: min(44vw, 300px);
  scroll-snap-align: start;
}
.gallery__item--wide { aspect-ratio: 16 / 10; }
.gallery__item--normal { aspect-ratio: 3 / 4; }
.gallery__item--narrow { aspect-ratio: 2 / 3; }

/* Image reveal: each photo wipes open left-to-right with a settling
   zoom as it scrolls into view (JS flips data-revealed on .gallery__item
   via IntersectionObserver — see js/main.js), rather than just
   appearing. The clip/scale live on .picture, a child of the observed
   .gallery__item — putting them on the observed element itself would
   make it permanently invisible to the observer (clipped to zero area
   reads as "not intersecting", so it could never reveal). Reduced
   motion forces the revealed state statically, below. */
.gallery__item picture {
  display: block;
  width: 100%;
  height: 100%;
  clip-path: inset(0 100% 0 0);
  transform: scale(1.12);
  transition: clip-path 900ms var(--ease-out), transform 1000ms var(--ease-out);
}
.gallery__item[data-revealed="true"] picture {
  clip-path: inset(0 0% 0 0);
  transform: scale(1);
}

.gallery__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: saturate(0.92) brightness(1.04) contrast(0.98);
  transition: transform 0.6s var(--ease-out);
}
.gallery__item:hover img { transform: scale(1.04); }

/* ============================================================
   Testimonials — pull-quotes, not cards. No border, no shadow, no
   fill; a hairline only separates the quote from its attribution,
   per the standing Cards philosophy (see DESIGN.md). Content is
   rendered from a data array in js/main.js, not hardcoded here.
   ============================================================ */
.testimonials {
  padding: var(--space-xl) var(--space-md);
  max-width: var(--container);
  margin: 0 auto;
}
.testimonials__head {
  max-width: var(--container);
  margin: 0 auto var(--space-lg);
  text-align: center;
}
.testimonials__head .eyebrow { justify-content: center; }

.testimonials__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-lg) var(--space-md);
  align-items: start;
}
/* Slight vertical stagger for organic rhythm instead of a rigid grid. */
.testimonial:nth-child(2) { margin-top: var(--space-lg); }
.testimonial:nth-child(3) { margin-top: var(--space-sm); }

.testimonial {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.testimonial__mark {
  /* Matches the glyph's own 32:20 viewBox exactly — a mismatched box
     ratio here would stretch the thin strokes non-uniformly. */
  width: 24px;
  height: 15px;
  color: var(--color-matcha);
  margin-bottom: var(--space-sm);
}
.testimonial__quote {
  margin: 0 0 var(--space-md);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-quote);
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--color-ink);
}
.testimonial__meta {
  margin-top: auto;
  padding-top: var(--space-sm);
  border-top: 1px solid var(--color-hairline);
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.testimonial__name {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--color-ink);
}
.testimonial__descriptor {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
}

/* ============================================================
   Trial class offer — a distinct entry offer between Testimonials and
   (eventually) Pricing, not a row of that table. Sits on --color-vainilla
   deliberately, so a future pricing block on --color-cream reads apart
   from it purely through the section's own background, matching how
   Mission/Gallery already alternate against the surrounding cream
   sections. Content is intentionally narrow and centered (unlike a
   pricing grid) so it never looks like the start of a package table.
   ============================================================ */
.trial {
  padding: var(--space-lg) var(--space-md);
  background: var(--color-vainilla);
}
.trial__inner {
  max-width: 620px;
  margin: 0 auto;
  text-align: center;
}
.trial__inner .eyebrow { justify-content: center; }
.trial__inner .headline { margin-bottom: var(--space-sm); }

.trial__lede {
  font-size: var(--text-md);
  color: var(--color-ink-muted);
  max-width: 44ch;
  margin: 0 auto var(--space-md);
}

.trial__price {
  margin-bottom: var(--space-md);
}
.trial__price-amount {
  display: block;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-headline-quote);
  line-height: 1;
  color: var(--color-ink);
}
.trial__price-currency {
  font-size: var(--text-md);
}
.trial__price-unit {
  display: block;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  margin-top: 0.4rem;
}

.trial .btn--chai { margin-bottom: var(--space-md); }

.trial__commitment {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-weight: 500;
  color: var(--color-ink);
  margin-bottom: var(--space-lg);
}
.trial__commitment svg {
  width: 16px;
  height: 16px;
  color: var(--color-matcha);
  flex-shrink: 0;
}

.trial__includes {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding-top: var(--space-md);
  border-top: 1px solid var(--color-hairline);
  margin-bottom: var(--space-md);
}
.trial__includes li {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

.trial__note {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
  opacity: 0.8;
}

/* ============================================================
   Pricing — a flat per-class rate list, then three discipline-scoped
   package groups below the trial offer. Content is rendered from
   `singleClasses` / `packageGroups` in js/main.js, not hardcoded here
   (real figures the founders supplied — see that file's header
   comment). Each group's featured (middle-tier) package is this
   section's one accent surface — matcha border/wash/badge — per the
   standing "One Accent Rule" (trial spent chai above; pricing spends
   matcha). Cards stay square (0 radius) per Shapes; only the CTA pills.
   ============================================================ */
.pricing {
  padding: var(--space-xl) var(--space-md);
  max-width: var(--container);
  margin: 0 auto;
}
.pricing__head {
  margin: 0 auto var(--space-lg);
  text-align: center;
}
.pricing__head .eyebrow { justify-content: center; }
.pricing__head .headline { margin-bottom: var(--space-sm); }
.pricing__note {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  max-width: 50rem;
  margin: 0 auto;
}

/* Flat per-discipline drop-in rates — a plain list, not cards, since
   there's nothing to compare feature-by-feature here (unlike the
   packages below), just a name and a number. */
.pricing__rates {
  max-width: 640px;
  margin: 0 auto var(--space-xl);
  text-align: center;
}
/* "00" opens the numbered sequence that continues into each package
   group below (01/02/03) — a quiet journal-index/folio device tying the
   flat rate list and the three card groups into one read instead of
   four unrelated blocks stacked on top of each other. Deliberately its
   own small serif mark, not a reuse of .eyebrow — a tracked uppercase
   label repeated four times in one section would read as decoration,
   not as the page-numbering device this is meant to be. */
.pricing__rates-index {
  display: block;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  margin-bottom: 0.4rem;
}
.pricing__rates-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-title);
  color: var(--color-ink);
  margin-bottom: var(--space-md);
}
.rate-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) 0;
  border-bottom: 1px solid var(--color-hairline);
}
.rate-row:last-child { border-bottom: none; }
.rate-row__name {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink);
}
/* Groups price + reserve link so both stay right-aligned and stack
   cleanly rather than fighting the name for horizontal space on
   narrow screens. */
.rate-row__right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.25rem;
}
.rate-row__price {
  font-family: var(--font-display);
  font-size: var(--text-title);
  color: var(--color-ink);
  white-space: nowrap;
}
.rate-row__price span {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
  margin-left: 0.3rem;
}
.rate-row__cta {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--color-ink-muted);
  border-bottom: 1px solid var(--color-hairline);
  padding-bottom: 1px;
  white-space: nowrap;
  transition: color 0.2s var(--ease-out), border-color 0.2s var(--ease-out);
}
.rate-row__cta:hover { color: var(--color-matcha); border-color: var(--color-matcha); }

/* Package groups — one .pricing__grid (unchanged) per discipline scope,
   stacked with generous rhythm so three groups of three cards each
   still read as distinct offers, not one long undifferentiated row. */
.pricing__groups {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
}
.pricing-group__head {
  text-align: center;
  margin-bottom: var(--space-md);
}
/* Same small serif folio mark as .pricing__rates-index above — continues
   that 00→03 sequence rather than introducing a second, differently
   styled numbering system. */
.pricing-group__index {
  display: block;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  margin-bottom: var(--space-sm);
}
/* Thin line icon, reused verbatim from the matching Disciplines card
   (see #clases) — the group literally borrows the discipline's own mark
   instead of inventing new iconography, the cheapest possible proof
   that this section belongs to the same visual system as the rest of
   the page. */
.pricing-group__icon {
  width: 28px;
  height: 28px;
  color: var(--color-matcha);
  margin: 0 auto var(--space-sm);
  display: block;
}
.pricing-group__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-h3);
  color: var(--color-ink);
  margin-bottom: var(--space-xs);
}
.pricing-group__note {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

/* align-items: end (not stretch) is what actually lets the featured
   card below rise above its siblings instead of being invisibly forced
   to their height — the missing piece that made all three cards in a
   row read as identical boxes regardless of the accent styling. */
.pricing__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-md);
  align-items: end;
}

.pricing-card {
  display: flex;
  flex-direction: column;
  padding: var(--space-md) var(--space-sm) var(--space-sm);
  border: 1px solid var(--color-hairline);
  text-align: center;
}

/* The one column allowed to lift off the row — literally: a negative
   top margin pulls it above the other two, on top of the background
   wash and matcha border already standing in for elevation (no shadow,
   per DESIGN.md). This is the same "break the grid on purpose" device
   Testimonials already uses (its column stagger), applied here instead
   of a plain color swap so the featured tier reads as a real rhythm
   break, not a tinted twin of its neighbors. */
.pricing-card--featured {
  border-color: var(--color-matcha);
  background: rgba(128, 150, 113, 0.06);
  padding-top: var(--space-lg);
  margin-top: calc(var(--space-md) * -1);
}

.pricing-card__badge {
  font-family: var(--font-body);
  font-size: var(--text-micro);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-matcha);
  margin: 0 0 var(--space-xs);
}

.pricing-card__name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-title);
  line-height: 1.25;
  color: var(--color-ink);
  margin-bottom: var(--space-md);
}

/* Variant selector (4 / 8 / 12 classes) — a segmented toggle, not tabs
   with separate panels, since only two numbers on screen change. */
.pricing-card__variants {
  display: inline-flex;
  align-self: center;
  border: 1px solid var(--color-hairline);
  margin-bottom: var(--space-md);
}
.pricing-card__variant-btn {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--color-ink-muted);
  padding: 0.5rem 1rem;
  transition: background-color 0.2s var(--ease-out), color 0.2s var(--ease-out);
}
.pricing-card__variant-btn + .pricing-card__variant-btn { border-left: 1px solid var(--color-hairline); }
.pricing-card__variant-btn:hover { color: var(--color-ink); }
.pricing-card__variant-btn[aria-pressed="true"] {
  background: var(--color-matcha);
  color: var(--color-cream);
}

/* Wraps .pricing-card__price (+ optional .pricing-card__price-total)
   so every card gets the same bottom margin whether or not it has a
   total-price line — the featured card's variant total is optional
   content, not a layout-affecting one. */
.pricing-card__price-block { margin-bottom: var(--space-md); }

.pricing-card__price {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.4rem;
}
.pricing-card__price-amount {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-headline-quote);
  line-height: 1;
  color: var(--color-ink);
}
.pricing-card--featured .pricing-card__price-amount { color: var(--color-matcha); }
.pricing-card__price-unit {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

.pricing-card__price-total {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
  margin-top: 0.35rem;
}

.pricing-card__includes {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: var(--space-md) 0;
  border-top: 1px solid var(--color-hairline);
  margin-bottom: var(--space-md);
}
.pricing-card__includes li {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

.pricing-card__value {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink);
  margin-bottom: var(--space-sm);
}
.pricing-card__secondary {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
  margin-bottom: var(--space-md);
}

.pricing-card__cta {
  margin-top: auto;
  align-self: center;
}
/* A lighter-weight sibling of .btn--secondary, not a new action —
   ink-outline instead of ink-fill, so the featured card's solid button
   reads as the one CTA with more contrast in the row. */
.pricing-card__cta--outline {
  background: transparent;
  color: var(--color-ink);
  border: 1px solid var(--color-ink);
}
.pricing-card__cta--outline:hover {
  background: var(--color-ink);
  color: var(--color-cream);
}

/* ============================================================
   Visit / location
   ============================================================ */
.visit {
  padding: var(--space-xl) var(--space-md);
  max-width: var(--container);
  margin: 0 auto;
}
.visit__inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-lg);
  align-items: center;
}
.visit__details {
  margin-top: var(--space-lg);
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}
.visit__details dt {
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-matcha);
  margin-bottom: 0.4rem;
}
.visit__details dd {
  font-family: var(--font-display);
  font-size: var(--text-title);
  line-height: 1.4;
}
.visit__details dd + dd { margin-top: 0.5rem; }
.visit__details a {
  border-bottom: 1px solid var(--color-hairline);
  transition: color 0.2s var(--ease-out), border-color 0.2s var(--ease-out);
}
.visit__details a:hover { color: var(--color-matcha); border-color: var(--color-matcha); }

.visit__map {
  aspect-ratio: 4 / 3.4;
  border: 1px solid var(--color-hairline);
}
.visit__map iframe {
  width: 100%;
  height: 100%;
  border: 0;
  filter: grayscale(0.4) sepia(0.2) saturate(0.75) contrast(0.92) brightness(1.03);
}

/* ============================================================
   Footer
   ============================================================ */
.footer {
  background: var(--color-ink);
  color: var(--color-cream);
  padding: var(--space-xl) var(--space-md) var(--space-md);
}
.footer__inner {
  max-width: var(--container);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: var(--space-lg);
  padding-bottom: var(--space-lg);
  border-bottom: 1px solid var(--color-hairline-on-dark);
}
.footer__brand { display: flex; flex-direction: column; gap: var(--space-sm); }
.footer .nav__mark { color: var(--color-cream); }
.footer__tagline {
  font-family: var(--font-display);
  font-size: var(--text-title);
  color: var(--color-vainilla);
}
.footer__col { display: flex; flex-direction: column; gap: 0.85rem; }
.footer__col .eyebrow { color: var(--color-chai); margin-bottom: 0.4rem; }
.footer__col a, .footer__col p { font-size: var(--text-sm); color: rgba(251, 247, 239, 0.82); line-height: 1.6; }
.footer__col a:hover { color: var(--color-cream); }
.footer__col .btn--secondary {
  background: var(--color-chai);
  border-color: var(--color-chai);
  color: var(--color-ink);
  align-self: flex-start;
  margin-bottom: 0.5rem;
  padding: 0.85rem 1.75rem;
  font-size: var(--text-sm);
}
.footer__col .btn--secondary:hover { background: var(--color-cream); border-color: var(--color-cream); }

.footer__bottom {
  max-width: var(--container);
  margin: 0 auto;
  padding-top: var(--space-md);
  font-size: var(--text-sm);
  color: rgba(251, 247, 239, 0.55);
}

/* ============================================================
   Scroll reveal
   ============================================================ */
.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.9s var(--ease-out), transform 0.9s var(--ease-out);
}
.reveal[data-visible="true"] {
  opacity: 1;
  transform: translateY(0);
}

/* ============================================================
   Booking modal — shared overlay for every "Reservar" CTA sitewide,
   wired to the PilatOS CRM (js/booking.js: GET /sessions, POST
   /reservations, POST /leads). Deliberately flat and opaque, not
   glass — DESIGN.md's one glassmorphism exception is the full-screen
   menu; this reuses the overlay *pattern* only, staying flat/hairline
   per the standing rule ("modals-that-don't-exist-yet" stay flat).
   Content block, so 0 radius throughout, same as cards.
   ============================================================ */
.booking-modal {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-md);
  pointer-events: none;
}
.booking-modal[data-open="true"] { pointer-events: auto; }

.booking-modal__backdrop {
  position: fixed;
  inset: 0;
  background: rgba(var(--color-scrim-rgb), 0);
  transition: background-color 0.35s var(--ease-out);
}
.booking-modal[data-open="true"] .booking-modal__backdrop {
  background: rgba(var(--color-scrim-rgb), 0.72);
}

.booking-modal__panel {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 560px;
  max-height: min(680px, 88vh);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--color-cream);
  border: 1px solid var(--color-hairline);
  padding: var(--space-lg) var(--space-md) var(--space-md);
  opacity: 0;
  transform: translateY(16px) scale(0.98);
  transition: opacity 0.3s var(--ease-out), transform 0.3s var(--ease-out);
}
.booking-modal[data-open="true"] .booking-modal__panel {
  opacity: 1;
  transform: translateY(0) scale(1);
}

.booking-modal__close {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-ink-muted);
  transition: color 0.2s var(--ease-out);
}
.booking-modal__close svg { width: 16px; height: 16px; }
.booking-modal__close:hover { color: var(--color-matcha); }

.booking-modal__head { margin-bottom: var(--space-md); padding-right: var(--space-md); }
.booking-modal__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-h3);
  line-height: 1.1;
  color: var(--color-ink);
}
.booking-modal__subtitle {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  margin-top: 0.4rem;
}

.booking-modal__loading {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  text-align: center;
  padding: var(--space-lg) 0;
}

.booking-modal__note {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
  margin-bottom: var(--space-sm);
}

/* Notice/error panels reuse --color-vainilla (already the system's
   alternate-emphasis surface, see Trial) instead of introducing a new
   alarm/red token that has no place in this palette. */
.booking-modal__notice {
  background: var(--color-vainilla);
  padding: var(--space-md);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6rem;
}
.booking-modal__notice p {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink);
}
.booking-modal__notice .btn { margin-top: 0.2rem; }

.session-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  margin-bottom: var(--space-md);
}
.session-day__label {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-matcha);
  margin-bottom: 0.5rem;
}
.session-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  width: 100%;
  padding: 0.85rem 0.75rem;
  border: 1px solid var(--color-hairline);
  border-left: 3px solid transparent;
  text-align: left;
  transition: border-color 0.2s var(--ease-out), background-color 0.2s var(--ease-out);
}
.session-row + .session-row { margin-top: 0.5rem; }
.session-row:hover { border-color: var(--color-matcha); }
.session-row.is-selected {
  border-color: var(--color-matcha);
  border-left-color: var(--color-matcha);
  background: rgba(128, 150, 113, 0.08);
}
.session-row__main { display: flex; flex-direction: column; gap: 0.2rem; }
.session-row__class {
  font-family: var(--font-display);
  font-size: var(--text-title);
  color: var(--color-ink);
}
.session-row__meta {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
}
.session-row__spots {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
  white-space: nowrap;
}

.booking-form { display: flex; flex-direction: column; gap: var(--space-sm); }
.booking-field { display: flex; flex-direction: column; gap: 0.35rem; }
.booking-field label {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}
.booking-field input {
  font-family: var(--font-body);
  font-size: var(--text-body);
  color: var(--color-ink);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--color-hairline);
  border-radius: 0;
  padding: 0.5rem 0.1rem;
  transition: border-color 0.2s var(--ease-out);
}
.booking-field input:focus {
  outline: none;
  border-color: var(--color-matcha);
}
.booking-field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-sm);
}
.booking-field__hint {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
  margin-top: -0.3rem;
}

.booking-modal__form-notice {
  background: var(--color-vainilla);
  padding: var(--space-sm);
}
.booking-modal__form-notice p {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink);
}
.booking-modal__form-notice .btn { margin-top: 0.6rem; }

.booking-modal__submit { align-self: flex-start; margin-top: 0.4rem; }
.booking-modal__submit:disabled { opacity: 0.55; cursor: default; }

.booking-modal__success {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6rem;
  padding: var(--space-md) 0;
}
.booking-modal__success svg {
  width: 28px;
  height: 28px;
  color: var(--color-matcha);
}
.booking-modal__success p {
  font-family: var(--font-body);
  font-size: var(--text-md);
  color: var(--color-ink);
}

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 1024px) {
  .disciplines__grid { grid-template-columns: repeat(2, 1fr); }
  .discipline:nth-child(2n) { border-right: none; }
  .discipline:last-child { border-right: 1px solid var(--color-hairline); }

  .testimonials__grid { grid-template-columns: 1fr; gap: var(--space-xl); }
  .testimonial:nth-child(2), .testimonial:nth-child(3) { margin-top: 0; }

  .pricing__grid { grid-template-columns: 1fr; gap: var(--space-lg); }
  .pricing-card--featured { padding-top: var(--space-md); margin-top: 0; }

  .visit__inner { grid-template-columns: 1fr; }
  .footer__inner { grid-template-columns: 1fr 1fr; row-gap: var(--space-lg); }
}

@media (max-width: 720px) {
  :root { --space-xl: var(--space-xl-mobile); }

  /* Nav reduces to mark + "Essenzia" + "Menú" on mobile — the tagline
     line was wrapping to 2-3 lines at narrow widths (it's sized for the
     desktop bar) and crowding the "Menú" trigger next to it. */
  .nav__wordmark em { display: none; }

  /* "Menú" moves to the right edge on mobile (column 3, the balancing
     track that's otherwise empty) instead of true-centered like
     desktop — a right-aligned trigger next to the logo is the more
     familiar mobile pattern. Once open, "Cerrar" moves back to column
     2 to be genuinely centered — deliberately a different position
     than the closed button, not a shared one. */
  .nav__menu-btn { grid-column: 3; justify-self: end; }
  /* True pixel-center, not the 1fr-auto-1fr grid trick above: that
     trick only self-balances when both flanking columns' content is
     equal width, and the logo+"Essenzia" column is wider than the
     empty one, so the grid-column: 2 approach visibly leaned right.
     Positioning directly against .nav (position: fixed, full viewport
     width) sidesteps that entirely. */
  .nav[data-menu-open="true"] .nav__menu-btn {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
  }

  .hero-frame { padding: var(--space-sm); }
  .hero { border-radius: var(--radius-lg-mobile); }

  .mission { padding-left: var(--space-sm); padding-right: var(--space-sm); }

  .disciplines { padding-left: var(--space-sm); padding-right: var(--space-sm); }
  .disciplines__grid { grid-template-columns: 1fr; }
  .discipline { border-right: none !important; }

  .gallery__head { padding-left: var(--space-sm); padding-right: var(--space-sm); }
  .gallery__track { padding-left: var(--space-sm); padding-right: var(--space-sm); }

  .testimonials { padding-left: var(--space-sm); padding-right: var(--space-sm); }

  .trial { padding-left: var(--space-sm); padding-right: var(--space-sm); }

  .pricing { padding-left: var(--space-sm); padding-right: var(--space-sm); }

  .visit { padding-left: var(--space-sm); padding-right: var(--space-sm); }

  .footer { padding-left: var(--space-sm); padding-right: var(--space-sm); }
  .footer__inner { grid-template-columns: 1fr; gap: var(--space-md); }

  .booking-modal { padding: var(--space-sm); }
  .booking-modal__panel { padding: var(--space-lg) var(--space-sm) var(--space-sm); max-height: 92vh; }
  .booking-field-row { grid-template-columns: 1fr; gap: 0.5rem; }
  .session-row { flex-direction: column; align-items: flex-start; gap: 0.35rem; }
}
