/* =============================================================================
   PILATES HUNTER — landing page styles
   -----------------------------------------------------------------------------
   Direction: "Calm strength". A warm, airy boutique-studio look — soft serif
   headlines in sentence case (Fraunces), warm off-white grounds, rounded cards
   and images, pill buttons. Red is kept as a refined accent, not a wall.

   Contents
   1.  Design tokens (:root)
   2.  Reset & base
   3.  Typography helpers (.h2 .lead .eyebrow .accent .dot)
   4.  Layout primitives (.container .section)
   5.  Buttons & link CTAs
   6.  Header + navigation
   7.  Hero
   8.  Why / benefits
   9.  Classes, programs & class dialogs
   10. Instructor
   11. Gallery
   12. Lineage
   12b. Accordion (Policy/FAQ) — removed with its sections; see the note there
   13. Contact
   14. Footer
   15. Scroll-reveal + motion
   16. Responsive
   17. Reduced motion & print
   ========================================================================== */

/* 1. ----------------------------------------------------------- DESIGN TOKENS */
/* branch: BSD runs a SAGE GREEN accent where Kemang runs the brand red.
   -----------------------------------------------------------------------------
   Why the accent may differ from the logo at all: the wordmark is a fixed
   oxblood PNG hotlinked from pilateshunter.com and is the same on every branch
   — that is the brand anchor, and it is kept untouched in --logo below. The
   ACCENT is the branch's own voice, and swapping it is what makes a visitor
   register "this is the BSD page" within a second of landing, without moving a
   single element on the page.

   The neutrals move with it. Leaving the warm cream under a green accent is
   what makes a recolour look like a mistake rather than a decision, so the
   off-white, the rule lines and the ink all shift a few degrees cooler. The
   result reads "modern minimalist" against Kemang's "soft earthy".

   Every value below is contrast-checked, not eyeballed:
     white on --accent ............ 4.91:1  (AA, button labels)
     --accent on --cream .......... 4.56:1  (AA, link + .accent text)
     --accent-deep on --accent-soft 6.28:1  (AA, chips and icon badges)
     --ink on --cream ............. 13.65:1 (AAA, body copy)
     --ink-soft on --cream ........ 5.19:1  (AA, secondary copy)
   If you change one of these, re-check the pair it belongs to. --accent is
   deliberately the darkest green that still reads as "fresh" rather than
   "forest": a lighter sage (#6B8E6B) drops white-on-accent to 3.68:1 and fails.
   -------------------------------------------------------------------------- */
:root {
  /* Palette — cool neutrals + one sage-green accent */
  --ink:       #232a25;   /* cooled from Kemang's warm #2a2420 */
  --ink-soft:  #5f6b60;
  --paper:     #ffffff;
  --cream:     #f6f7f3;   /* cool off-white — alternating sections */
  --accent-soft:  #e6ede3;   /* pale sage — chips, icon badges */
  --accent:       #4f7a5e;
  --accent-deep:  #3a5c46;
  --logo:      #8a1f1f;   /* oxblood of the studio wordmark — BRAND, do not
                             recolour per branch; the PNG itself is this red */
  --mist:      #8c978b;
  --line:      #e2e7dc;

  /* Typography */
  --serif:  "Fraunces", "Iowan Old Style", Georgia, "Times New Roman", serif;
  --sans:   "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif;

  --fs-hero: clamp(2.5rem, 1.5rem + 3.8vw, 4.5rem);
  --fs-h2:   clamp(1.9rem, 1.4rem + 2vw, 2.8rem);
  --fs-h3:   clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
  --fs-lead: clamp(1.1rem, 1rem + 0.45vw, 1.28rem);
  --fs-body: 1.05rem;

  /* Shape & depth */
  --radius:    18px;
  --radius-sm: 10px;
  --shadow-sm: 0 1px 2px rgba(35, 42, 37, 0.04), 0 8px 24px rgba(35, 42, 37, 0.06);
  --shadow-md: 0 14px 44px rgba(35, 42, 37, 0.13);

  /* Spacing */
  --pad-section: clamp(4rem, 2.5rem + 6.5vw, 8rem);
  --container:   1200px;
  --gutter:      clamp(1.25rem, 0.5rem + 4vw, 3rem);
  /* How far a section's ground takes to arrive at the next one. Not a colour:
     every transition below blends between the tokens above, so the page reads
     as one continuous warm ground instead of a stack of bands. Kept well
     inside --pad-section so a fade always lands in a section's padding and
     never behind its text. */
  --blend:       clamp(2.5rem, 6vw, 6rem);

  /* Motion */
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
}

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: 5.5rem; /* clear the sticky header on anchor jumps */
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

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

a { color: inherit; text-decoration: none; }

button,
input,
select,
textarea { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 3px;
}

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

/* Foto Wawa: Lebih besar, posisi diturunkan sedikit, background cleared (transparan/tidak berwarna) */
img[src*="WAWA.jpeg"] {
  width: 240px !important;
  height: 240px !important;
  object-fit: contain;
  object-position: center 70%;   /* Menurunkan posisi fokus foto ke bawah */
  background-color: transparent !important; /* Cleared / transparan */
  display: block !important;
  margin: 74px auto 0 auto !important; /* Jarak atas 12px untuk menurunkan posisi elemen */
}

.skip-link {
  position: fixed;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 200;
  padding: 0.6rem 1.1rem;
  background: var(--ink);
  color: #fff;
  font-size: 0.8rem;
  font-weight: 600;
  border-radius: 999px;
  transform: translateY(-160%);
  transition: transform 0.2s var(--ease);
}
.skip-link:focus { transform: translateY(0); }

/* 3. -------------------------------------------------------------- TYPOGRAPHY */
.h2 {
  font-family: var(--serif);
  font-optical-sizing: auto;
  font-weight: 430;
  font-size: var(--fs-h2);
  line-height: 1.12;
  letter-spacing: -0.012em;
  text-wrap: balance;
}

.lead {
  font-size: var(--fs-lead);
  line-height: 1.6;
  color: var(--ink-soft);
}

p + p { margin-top: 1em; }

/* Small caps-y section label with a short red rule */
/* 1.5rem, matching .hero__eyebrow, so the eyebrow -> h2 gap is one value on
   every section head including the hero. It was 1rem here, which combined
   with .section__head .h2's own 0.5rem margin-top to make 1.5rem inside a
   .section__head and only 1rem in the sections that lay their head out
   loose — the same two elements, two different gaps. The h2 margin is now 0
   and this single value carries the gap everywhere. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.8rem;
  margin-bottom: 1.5rem;
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}
.eyebrow::before {
  content: "";
  width: 1.75rem;
  height: 1px;
  background: currentColor;
}

.accent { color: var(--accent); font-style: italic; }

.dot { color: var(--ink-soft); opacity: 0.55; padding: 0 0.4em; }

/* 4. -------------------------------------------------------- LAYOUT PRIMITIVES */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: var(--pad-section); }

/* The alternating warm ground. This was a flat `background: var(--cream)`,
   which drew a hard horizontal line wherever a stone section met a paper one
   — three of them on this page. Same two tokens, no new colour: the section
   simply starts and ends at --paper (what its neighbours are) and is --cream
   through the middle, so the two tones meet as a fade inside the section's own
   padding rather than as an edge between sections. */
.section--stone {
  background: linear-gradient(
    180deg,
    var(--paper) 0%,
    var(--cream) var(--blend),
    var(--cream) calc(100% - var(--blend)),
    var(--paper) 100%
  );
}

/* One definition of eyebrow -> h2 -> lead, and one definition of the gap from
   a section head to the section body. Every section head on the page uses
   .section__head so this is the only place those three numbers exist. */
.section__head {
  max-width: 44rem;
  margin-bottom: clamp(2.5rem, 5vw, 4rem);
}
.section__head .h2 { margin-top: 0; }
.section__head .lead { margin-top: 1rem; }

/* 5. -------------------------------------------------------- BUTTONS & LINK CTAS */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.95rem 1.8rem;
  font-family: var(--sans);
  font-size: 0.98rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
  border: 1.5px solid transparent;
  border-radius: 999px;
  cursor: pointer;
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease),
              border-color 0.25s var(--ease), transform 0.25s var(--ease),
              box-shadow 0.25s var(--ease);
}
.btn--solid { background: var(--accent); color: #fff; }
.btn--solid:hover,
.btn--solid:focus-visible {
  background: var(--accent-deep);
  color: #fff;
  transform: translateY(-2px);
  /* branch: the lift under a hovered/focused primary button is a tint of the
     ACCENT, not a neutral drop shadow — so it has to move with it. This was
     rgba(216, 30, 52, …), the Kemang red, which glowed pink under a green
     button. Kept as a literal because a CSS custom property cannot supply
     just the RGB channels of an rgba() in this codebase's no-build setup. */
  box-shadow: 0 12px 26px rgba(79, 122, 94, 0.28);
}
.btn--ghost-light {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.5);
}
.btn--ghost-light:hover,
.btn--ghost-light:focus-visible {
  background: rgba(255, 255, 255, 0.16);
  border-color: #fff;
  color: #fff;
}
.btn--sm { padding: 0.6rem 1.25rem; font-size: 0.9rem; }
.btn--full { width: 100%; justify-content: center; margin-top: 0.5rem; }
.btn:disabled {
  opacity: 0.45;
  box-shadow: none;
  transform: none;
  pointer-events: none;
}
.btn__arrow { transition: transform 0.25s var(--ease); }
.btn:hover .btn__arrow { transform: translateY(3px); }

.link-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--accent);
  padding-bottom: 2px;
  background: linear-gradient(currentColor, currentColor) 0 100% / 0% 1.5px no-repeat;
  transition: background-size 0.3s var(--ease);
}
.link-cta:hover,
.link-cta:focus-visible { background-size: 100% 1.5px; }
.link-cta span { transition: transform 0.25s var(--ease); }
.link-cta:hover span { transform: translateX(3px); }
.link-cta--sm { font-size: 0.85rem; }

/* 6. ---------------------------------------------------------- HEADER + NAV */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  border-bottom: 1px solid transparent;
  transition: background-color 0.35s var(--ease), box-shadow 0.35s var(--ease),
              border-color 0.35s var(--ease);
}
/* Soft gradient so the wordmark and nav stay legible over the hero photo */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 150px;
  z-index: -1;
  pointer-events: none; /* purely decorative — must never block clicks on page
                            content once the sticky header's dead zone (it is
                            taller than the header's own content) scrolls over it */
  background: linear-gradient(180deg, rgba(26, 20, 17, 0.42), rgba(26, 20, 17, 0));
  transition: opacity 0.35s var(--ease);
}
.site-header.is-scrolled::before,
.site-header.nav-open::before { opacity: 0; }

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding-block: clamp(0.85rem, 1.8vw, 1.3rem);
}

.site-header.is-scrolled,
.site-header.nav-open {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom-color: var(--line);
  box-shadow: 0 2px 30px rgba(35, 42, 37, 0.07);
}

/* Wordmark — the studio's real logo mark, then a branch label.
   Two <img> logos (white / colour) are stacked in the header; CSS toggles
   which is visible so the mark stays legible over the hero photo and once
   the header goes solid on scroll. The footer (always on a dark ground)
   only needs the white version. */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  flex: none;
  color: #fff;
  transition: color 0.3s var(--ease);
}
.wordmark__logo {
  display: block;
  height: 2.19rem;
  width: auto;
}
.wordmark__logo--color { display: none; }
.site-header.is-scrolled .wordmark__logo--white,
.site-header.nav-open .wordmark__logo--white { display: none; }
.site-header.is-scrolled .wordmark__logo--color,
.site-header.nav-open .wordmark__logo--color { display: block; }
.wordmark__branch {
  font-family: var(--sans);
  font-weight: 600;
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding-left: 0.6rem;
  border-left: 1px solid currentColor;
  opacity: 0.75;
}
.site-header.is-scrolled .wordmark,
.site-header.nav-open .wordmark { color: var(--logo); }

.nav {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 2.2rem);
}
.nav a {
  position: relative;
  font-size: 0.95rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.88);
  padding: 0.3rem 0;
  transition: color 0.2s var(--ease);
}
.nav a::after {
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: -1px;
  height: 1.5px;
  background: currentColor;
  transition: right 0.28s var(--ease);
}
.nav a:hover,
.nav a:focus-visible { color: #fff; }
.nav a:hover::after,
.nav a:focus-visible::after { right: 0; }
.site-header.is-scrolled .nav a,
.site-header.nav-open .nav a { color: var(--ink-soft); }
.site-header.is-scrolled .nav a:hover,
.site-header.is-scrolled .nav a:focus-visible,
.site-header.nav-open .nav a:hover,
.site-header.nav-open .nav a:focus-visible { color: var(--accent); }

.site-header__actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex: none;
}

.nav-toggle {
  display: none;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  color: #fff;
}
.site-header.is-scrolled .nav-toggle,
.site-header.nav-open .nav-toggle { color: var(--ink); }
.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: "";
  display: block;
  width: 22px;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform 0.3s var(--ease), opacity 0.2s var(--ease);
}
.nav-toggle__bars { position: relative; }
.nav-toggle__bars::before { position: absolute; top: -7px; left: 0; }
.nav-toggle__bars::after  { position: absolute; top: 7px; left: 0; }
.site-header.nav-open .nav-toggle__bars { background: transparent; }
.site-header.nav-open .nav-toggle__bars::before { transform: translateY(7px) rotate(45deg); }
.site-header.nav-open .nav-toggle__bars::after  { transform: translateY(-7px) rotate(-45deg); }

/* 7. --------------------------------------------------------------------- HERO */
.hero {
  position: relative;
  isolation: isolate;
  min-height: min(92vh, 880px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: clamp(7rem, 16vw, 11rem) clamp(4rem, 9vw, 7rem);
  margin-top: calc(-1 * (clamp(0.85rem, 1.8vw, 1.3rem) * 2 + 42px));
  color: #fff;
  overflow: hidden;
}
.hero__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 28%;
  z-index: -2;
}
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(24, 18, 15, 0.4) 0%, rgba(24, 18, 15, 0.1) 24%, rgba(24, 18, 15, 0.66) 100%),
    linear-gradient(90deg, rgba(24, 18, 15, 0.78) 0%, rgba(24, 18, 15, 0.45) 38%, rgba(24, 18, 15, 0.12) 72%, rgba(24, 18, 15, 0) 100%);
}

/* The hero photo used to stop dead against #why's paper. This carries its
   bottom edge into that ground instead. It sits above the scrim (z-index -1)
   and below .hero__inner (z-index 1), inside .hero's own isolation, and it is
   --blend tall against a hero of at least 88vh — the title and CTA never
   reach it. Same trick, same token, as the .program-hero bands below. */
.hero::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--blend);
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0), var(--paper));
}

.hero__inner { position: relative; z-index: 1; }
.hero__eyebrow,
.hero__title,
.hero__lead,
.hero__cta { max-width: 40rem; }
.hero__eyebrow {
  margin-bottom: 1.5rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.9);
}
.hero__eyebrow .dot { color: rgba(255, 255, 255, 0.5); opacity: 1; }

.hero__title {
  font-family: var(--serif);
  font-optical-sizing: auto;
  font-weight: 470;
  font-size: var(--fs-hero);
  line-height: 1.06;
  letter-spacing: -0.015em;
  text-shadow: 0 1px 2px rgba(12, 9, 7, 0.35), 0 4px 34px rgba(12, 9, 7, 0.45);
}

.hero__lead {
  margin-top: 1.6rem;
  max-width: 34rem;
  font-size: var(--fs-lead);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.9);
}

.hero__cta {
  margin-top: 2.4rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
}

/* 8. -------------------------------------------------------------- WHY / BENEFITS */
.why__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2.5rem, 6vw, 4.5rem);
  align-items: start;
}
@media (min-width: 920px) {
  .why__grid { grid-template-columns: 1fr 1fr; }
}
/* #why lays its head out across the two-column grid — the eyebrow above it,
   the h2 and lead in the left column — so it cannot use .section__head as a
   wrapper. It matches its numbers instead: the eyebrow's own 1.5rem
   margin-bottom carries the gap to the h2, and this is .section__head .lead's
   1rem margin-top expressed from the other side. It was 1.25rem. */
.why__intro { max-width: 38rem; }
.why__intro .h2 { margin-bottom: 1rem; }
.why__intro .lead { margin-bottom: 1rem; }

.benefits {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(1.25rem, 2.5vw, 1.75rem);
}
.benefit {
  padding: clamp(1.4rem, 3vw, 1.9rem);
  background: var(--cream);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: box-shadow 0.3s var(--ease), transform 0.3s var(--ease),
              background-color 0.3s var(--ease);
}
.benefit:hover {
  background: var(--paper);
  box-shadow: var(--shadow-md);
  transform: translateY(-3px);
}
.benefit__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: 999px;
  background: var(--accent-soft);
  margin-bottom: 1.1rem;
}
.benefit__icon svg {
  width: 1.5rem;
  height: 1.5rem;
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.benefit__icon svg .fill { fill: var(--accent); stroke: none; }
.benefit__title {
  font-family: var(--serif);
  font-weight: 470;
  font-size: var(--fs-h3);
  letter-spacing: -0.01em;
  margin-bottom: 0.4rem;
}
.benefit__text { font-size: 0.95rem; color: var(--ink-soft); line-height: 1.6; }

/* 9. -------------------------------------------------------- CLASSES & PROGRAMS */
.class-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
.class-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  padding-bottom: 1.6rem;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.3s var(--ease), transform 0.3s var(--ease);
}
.class-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-4px);
}
.class-card__media {
  aspect-ratio: 4 / 5;
  overflow: hidden;
}
.class-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s var(--ease);
}
.class-card:hover .class-card__media img { transform: scale(1.04); }
.class-card__ratio {
  align-self: flex-start;
  margin: 1.4rem 1.5rem 0;
  padding: 0.3rem 0.75rem;
  background: var(--accent-soft);
  color: var(--accent-deep);
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.class-card__title {
  font-family: var(--serif);
  font-weight: 470;
  font-size: 1.4rem;
  letter-spacing: -0.01em;
  margin: 0.8rem 1.5rem 0;
}
.class-card__text {
  margin: 0.5rem 1.5rem 0;
  font-size: 0.95rem;
  color: var(--ink-soft);
  line-height: 1.6;
}
.class-card__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin: auto 1.5rem 0;
  padding-top: 1.2rem;
}
/* .link-cta is used on both <a> and <button>; strip the UA button chrome
   wherever it lands on a button so the two render identically. */
button.link-cta {
  background: none;
  border: 0;
  padding: 0 0 2px;
  cursor: pointer;
}

/* The stacked .programs__list / .program rows that used to live here were
   replaced by the full-width parallax hero sections in js/programs.js
   (renderProgramHeroes) and css/programs.css — the brief for this refresh
   forbids a mini-card/list treatment for the specialized programs. Confirmed
   zero remaining references to .programs, .programs__list or .program before
   deleting (see the branch's commit for the grep). */

/* The .class-dialog block that used to live here (native <dialog> for class
   detail) was replaced by the shared #detail-dialog in css/programs.css and
   js/programs.js — confirmed zero references left in index.html or js/*.js,
   so it and its dedicated @keyframes (dialogIn/backdropIn, also duplicated
   into programs.css) were removed rather than kept as dead weight. */

/* 10. ------------------------------------------------------------- INSTRUCTOR */
.instructor__grid {
  display: grid;
  grid-template-columns: 0.8fr 1.2fr;
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: center;
}
.instructor__portrait {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}
.instructor__portrait img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.instructor__tag {
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(4px);
  color: var(--accent-deep);
  border-radius: 999px;
  padding: 0.45rem 1rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
/* Same rhythm as .section__head, reached the same way: the eyebrow's own
   margin carries the gap above (so no margin-top here), and the gap below the
   h2 is the 1rem every other head puts between its h2 and the line under it. */
.instructor__body .h2 { margin: 0 0 1rem; }
.instructor__cred { font-size: 0.9rem; color: var(--ink-soft); margin-bottom: 1.25rem; }
.instructor__pai { width: 108px; height: auto; opacity: 0.85; }

/* 10b. ------------------------------------------------------- INSTRUCTOR TEAM
   18-card grid for the teaching team below Charles Xu. Reuses the same card
   idiom as .class-card (radius, shadow, hover lift, type scale) rather than
   inventing a new visual language. */
/* No margin-top: the gap from the section head to this grid is .section__head's
   own margin-bottom, the same gap every other section body starts after. The
   ad-hoc 2.5rem that used to be here stacked on top of it. */
.instructor-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: clamp(1.25rem, 2vw, 1.75rem);
}
.instructor-card {
  appearance: none;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  padding: 0;
  margin: 0;
  text-align: left;
  font: inherit;
  color: inherit;
  transition: box-shadow 0.3s var(--ease), transform 0.3s var(--ease);
}
.instructor-card:hover,
.instructor-card:focus-visible {
  box-shadow: var(--shadow-md);
  transform: translateY(-4px);
}
.instructor-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.instructor-card__media {
  /* A <span> inside the card <button> (a button may only contain phrasing
     content — see renderInstructorCards in js/programs.js), so it needs the
     block display the <div> it replaced had by default. */
  display: block;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--cream);
}
.instructor-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s var(--ease);
}
.instructor-card:hover .instructor-card__media img { transform: scale(1.04); }
.instructor-card__name {
  /* Also a <span> now, for the same reason — it used to be an <h3>. */
  display: block;
  font-family: var(--serif);
  font-weight: 470;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
  margin: 0.9rem 1rem 0;
}
.instructor-card__badge {
  align-self: flex-start;
  margin: 0.5rem 1rem 1rem;
  padding: 0.28rem 0.65rem;
  background: var(--accent-soft);
  color: var(--accent-deep);
  border-radius: 999px;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.05em;
}

/* 11. --------------------------------------------------------------- GALLERY */
/* The gallery is a .section wrapped in a .container like everything else now.
   It used to set `padding-block: clamp(3.5rem, 7vw, 6rem)` — its own rhythm,
   noticeably tighter than --pad-section — and re-implement .container's
   max-width + padding-inline separately on .gallery__label and .gallery__grid.
   Both are gone; the shared primitives do the work. */
.gallery__label {
  margin-bottom: 1.5rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.gallery__label .dot { color: var(--accent); opacity: 1; }
.gallery__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(0.75rem, 1.5vw, 1.15rem);
}
.gallery__item {
  overflow: hidden;
  border-radius: var(--radius-sm);
  aspect-ratio: 4 / 3;
}
.gallery__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease);
}
.gallery__item:hover img { transform: scale(1.05); }

/* --------------------------------------------------- FACE-AWARE IMAGE FRAMING
   Every photo below is cropped by object-fit: cover somewhere on this page.
   Left at the default 50% 50% the crop is blind to where the people actually
   are — worst on the class cards, whose 340x426 portrait frame throws away 47%
   of a 1000x667 landscape source, pushing the subjects of the Private photo
   (who sit left of centre) toward the edge.

   Each value is the measured centre of the face mass in that source, read off
   a percentage grid overlaid on the full-resolution file. With cover, the
   source point at fraction f lands at fraction f of the box, so the measured
   value can be used directly.

   Keyed on the filename rather than on nth-child or a utility class so the
   value travels with the photograph: reorder the gallery, or reuse a photo
   somewhere else, and its framing still follows it. The photos owned by
   js/data.js (instructors, programs, price cards) carry their focal point in
   the data instead — see photoFocal / profileFocal / imageFocal there. */
.class-card__media img[src$="Service-Our-Class-Private.webp"] { object-position: 33% 45%; }
.class-card__media img[src$="Service-Our-Class-Semi-Private.webp"] { object-position: 45% 45%; }
.class-card__media img[src$="Service-Our-Class-Group.webp"] { object-position: 55% 55%; }
.gallery img[src$="IMG_0541-scaled.jpg"] { object-position: 45% 55%; }
.gallery img[src$="IMG_0527-scaled.jpg"] { object-position: 35% 42%; }
.gallery img[src$="DSC07745-scaled.jpg"] { object-position: 60% 50%; }
.gallery img[src$="IMG_0531-scaled.jpg"] { object-position: 60% 48%; }
.gallery img[src$="OS-Pilates-Student-1.webp"] { object-position: 32% 28%; }
.gallery img[src$="OS-Pilates-Student-3.webp"] { object-position: 50% 52%; }

/* 12. ---------------------------------------------------------------- LINEAGE
   Plain explainer, not testimonials: .section__head/.lead for the intro,
   the existing .benefits/.benefit fact-card component (see WHY / BENEFITS
   above) for the two lineage facts — no quote/blockquote/figcaption
   semantics, since none of PAI, the Corps or Charles Xu said these words. */
/* This photo is 450x600 — a PORTRAIT, and the largest the studio publishes
   (the URL previously used here was a 196x190 thumbnail, stretched about 5.6x
   across a full-width band: the blurriest image on the site). It was also
   forced to aspect-ratio 21/9, which cropped a horizontal slice out of the
   middle and cut the heads off all three people in it. It is now shown at a
   width its own resolution can actually carry, in a portrait-leaning frame,
   focused on the faces. Do not widen it back out — there is no larger source
   (School-Our-background-scaled.jpeg and the 2023/10 path both 404). */
.lineage__photo {
  width: min(100%, 360px);
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 48% 32%;
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  margin-bottom: clamp(1.75rem, 3vw, 2.5rem);
}
.lineage__body { display: grid; gap: clamp(1.75rem, 3vw, 2.5rem); }
@media (min-width: 900px) {
  /* Photo column is the photo's own max width, so it is never stretched past
     what its 450x600 source can carry. */
  .lineage__body { grid-template-columns: 360px 1fr; align-items: start; }
  .lineage__body .lineage__photo { margin-bottom: 0; }
  .lineage__body .lineage__facts { margin-bottom: 0; }
}
.lineage__facts { margin-bottom: clamp(1.75rem, 3vw, 2.5rem); }
.lineage__pai { margin: 0 auto; }

/* 12b. -------------------------------------- ACCORDION (POLICY/FAQ) — REMOVED
   The .accordion / .accordion__item / .accordion__summary / .accordion__panel
   rules stood here. Their only two consumers, #policies and #faq, were removed
   from index.html at the owner's request (see the REMOVED: STUDIO POLICY
   comment there), and grepping index.html, css/*.css and js/*.js found no
   other reference to any of the four classes — nothing renders a <details>
   accordion anywhere else — so the block is deleted rather than left as dead
   weight. It comes back with the sections, from commit cee52d2. */

/* 13. --------------------------------------------------------------- CONTACT */
/* .contact__inner holds only the studio details and the map — #contact's
   eyebrow/h2/lead moved out into a .section__head above the booking form. The
   three `.contact__inner .eyebrow/.h2/.lead` rules that used to sit here
   matched nothing (grepped index.html: .contact__inner contains a <dl> and the
   map embed, no head elements), and one of them was an ad-hoc h2 margin
   competing with .section__head's. Deleted rather than left to mislead. */
.contact__inner {
  max-width: 44rem;
  text-align: center;
}

.contact__details {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.75rem 2rem;
  max-width: 30rem;
  margin-inline: auto;
  text-align: left;
  border-top: 1px solid var(--line);
  padding-top: clamp(2rem, 4vw, 2.75rem);
}
.contact__details dt {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.35rem;
}
.contact__details dd { font-size: 0.95rem; color: var(--ink-soft); line-height: 1.55; }
.contact__details a {
  color: var(--ink);
  border-bottom: 1px solid var(--line);
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.contact__details a:hover { color: var(--accent); border-color: var(--accent); }

/* Embedded studio map */
.map-embed {
  margin-top: 2rem;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--accent-soft);
}
.map-embed__frame {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}
.map-embed__link {
  display: inline-block;
  margin-top: 0.9rem;
  color: var(--accent);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s var(--ease);
}
.map-embed__link:hover,
.map-embed__link:focus-visible { border-color: var(--accent); }

/* 14. ------------------------------------------------------------------ FOOTER */
.site-footer {
  /* Fades in from the paper ground #contact ends on rather than starting as a
     hard dark edge. The fade lands entirely in the footer's own top padding. */
  background: linear-gradient(180deg, var(--paper) 0, var(--ink) var(--blend));
  background-color: var(--ink);
  color: rgba(255, 255, 255, 0.66);
  padding-block: clamp(3.5rem, 6vw, 5rem) 2rem;
}
.site-footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem 2rem;
  padding-bottom: 2rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.wordmark--footer { color: #fff; }
.wordmark--footer .wordmark__logo { height: 2.56rem; }
.wordmark--footer .wordmark__branch { border-color: rgba(255, 255, 255, 0.3); opacity: 0.8; }
.site-footer__tag {
  margin-top: 0.5rem;
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.6);
}
.site-footer__social { display: flex; gap: 0.6rem; }
.site-footer__social a {
  display: inline-flex;
  width: 2.4rem;
  height: 2.4rem;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.site-footer__social a:hover,
.site-footer__social a:focus-visible { background: var(--accent); border-color: var(--accent); }
.site-footer__social svg {
  width: 1.15rem;
  height: 1.15rem;
  fill: none;
  stroke: #fff;
  stroke-width: 1.6;
}
.site-footer__social svg .fill { fill: #fff; stroke: none; }

.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: 1.5rem;
  font-size: 0.78rem;
  color: rgba(255, 255, 255, 0.45);
}

/* 15. ------------------------------------------------------ SCROLL REVEAL + MOTION */
.js .reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}
.js .reveal.is-visible {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: no-preference) {
  .hero__eyebrow,
  .hero__title,
  .hero__lead,
  .hero__cta { animation: rise 0.9s var(--ease) backwards; }
  .hero__eyebrow { animation-delay: 0.1s; }
  .hero__title { animation-delay: 0.22s; }
  .hero__lead { animation-delay: 0.4s; }
  .hero__cta { animation-delay: 0.52s; }

  html { scroll-behavior: smooth; }
}

@keyframes rise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

/* 16. ---------------------------------------------------------- RESPONSIVE */
@media (max-width: 960px) {
  .instructor__grid { grid-template-columns: 1fr; }
  .instructor__portrait { max-width: 22rem; }
  .class-grid { grid-template-columns: 1fr 1fr; }
  .gallery__grid { grid-template-columns: repeat(2, 1fr); }
}

/* Collapse the nav into a toggle */
@media (max-width: 900px) {
  .nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    box-shadow: 0 20px 40px rgba(35, 42, 37, 0.1);
    padding: 0.5rem 0 0.75rem;
    max-height: 0;
    overflow: hidden;
    visibility: hidden;
    transition: max-height 0.35s var(--ease), visibility 0s linear 0.35s;
  }
  .site-header.nav-open .nav {
    max-height: 75vh;
    visibility: visible;
    transition: max-height 0.35s var(--ease), visibility 0s;
  }
  .nav a {
    color: var(--ink);
    padding: 0.95rem var(--gutter);
    font-size: 1.05rem;
  }
  .nav a::after { display: none; }
  .nav a:hover,
  .nav a:focus-visible { color: var(--accent); background: var(--cream); }
  .nav-toggle { display: inline-flex; }
}

@media (max-width: 760px) {
  .contact__details { grid-template-columns: 1fr; text-align: center; }
}

@media (max-width: 620px) {
  .benefits { grid-template-columns: 1fr; }
  .class-grid { grid-template-columns: 1fr; }
  .class-card__media { aspect-ratio: 16 / 11; }

  .wordmark { gap: 0.5rem; }
  .wordmark__logo { height: 1.83rem; }
  .wordmark__branch { font-size: 0.6rem; letter-spacing: 0.1em; padding-left: 0.5rem; }
  .site-header__inner { gap: 0.75rem; }

  .hero { min-height: min(88vh, 720px); justify-content: flex-end; }
  .hero__bg { object-position: 42% 30%; }

  .site-footer__inner { flex-direction: column; align-items: flex-start; }
}

@media (max-width: 400px) {
  /* keep the header from overflowing on the narrowest phones */
  .wordmark__logo { height: 1.7rem; }
  .wordmark__branch { font-size: 0.56rem; padding-left: 0.4rem; }
  .site-header__actions .btn--sm { padding: 0.5rem 0.9rem; font-size: 0.85rem; }
}

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

/* 17. -------------------------------------------------- REDUCED MOTION & PRINT */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .js .reveal { opacity: 1; transform: none; }
}

@media print {
  .site-header, .nav, .nav-toggle, .map-embed, .skip-link { display: none; }
  .hero { min-height: auto; color: var(--ink); margin-top: 0; }
  .hero__scrim, .hero__bg { display: none; }
  * { color: #000 !important; }
}
