/* ==========================================================================
   MyZen — Lido, Funchal
   Mobile-first. Desktop layout begins at 900px.
   Palette and type follow the MyZen brand guidelines.
   ========================================================================== */

:root {
  --paper:      #FAF6EF;
  --cream:      #F4E9D8;
  --sage:       #B7B5A8;
  --moss:       #67664C;
  --terracotta: #9E6D4E;
  /* The brand terracotta above is a fill colour, not a text colour: at 11px on
     paper it reaches 4.1:1 and on cream 3.68:1, so every eyebrow, role line and
     "Read more" on the site sat under AA. This is the same hue at 82%, the
     lightest step that clears 4.5:1 on all four grounds those elements
     actually sit on — paper 5.65, cream 5.07, the founder panel 5.16, and 4.57
     even where a leaf shadow darkens that panel. Backgrounds, the focus ring
     and the nav underline keep --terracotta; only text moves. */
  --terracotta-ink: #825940;
  --tan:        #AE9077;
  --espresso:   #33271C;
  --ink:        #1B150E;

  --serif:   'EB Garamond', Georgia, 'Times New Roman', serif;
  --display: 'Italiana', 'EB Garamond', Georgia, serif;
  --hand:    'Shadows Into Light', 'EB Garamond', cursive;

  --pad: 24px;
  --maxw: 1440px;
  --ease: cubic-bezier(.22, .61, .36, 1);
}

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: 90px; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--espresso);
  font-family: var(--serif);
  font-size: 17.5px;
  line-height: 1.78;
  letter-spacing: .012em;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, video { display: block; max-width: 100%; height: auto; }
a { color: var(--terracotta-ink); text-decoration: none; }
a:hover { color: var(--moss); }

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

/* Hidden from sight, still read by screen readers. Not the same thing as .skip
   below, which is a visible pill parked off-screen until it takes focus. */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; white-space: nowrap;
  clip: rect(0 0 0 0); clip-path: inset(50%);
}

.skip {
  position: absolute; left: 16px; top: -60px; z-index: 200;
  padding: 12px 20px; background: var(--moss); color: var(--cream);
  border-radius: 999px; font-size: 12px; letter-spacing: .22em; text-transform: uppercase;
  transition: top .2s ease;
}
.skip:focus { top: 16px; color: var(--cream); }

.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--pad); }

/* --- Type ----------------------------------------------------------------- */

.eyebrow {
  font-size: 10px; letter-spacing: .34em; text-transform: uppercase;
  color: var(--terracotta-ink); margin: 0 0 16px;
}
/* Italiana is the brand's display face, and it only earns its keep set large:
   one weight, no italic, strokes that disappear at reading size. So it takes
   h1 and h2 and nothing else — EB Garamond keeps h3, the UI labels and every
   line of body copy. */
h1, h2 { font-family: var(--display); }
h1, h2, h3 { font-weight: 400; margin: 0; }
/* balance evens every line, which suits a short standalone headline. On the
   section headings it fought the copy — "A sanctuary for the / body, mind &
   soul" balanced into "A SANCTUARY FOR / THE body, mind & soul", orphaning the
   article onto the italic line. They take pretty instead, which only guards
   the last line. */
h1 { text-wrap: balance; }
h2, h3 { text-wrap: pretty; }

/* Size and tracking deliberately move in opposite directions. Tracking set in
   em grows with the type, which at 90px turns a headline into a fence, so it
   is set in px and rises far more slowly than the size does — roughly .21em at
   the small end down to .11em at the large one. */
/* The hero headline has to hold one line on desktop: two lines of Italiana at
   this size run up into the sticky nav and the opening badge. The curve is
   tuned so the line stays inside the container all the way down to the 900px
   breakpoint, where it hands over to the 30px floor and is allowed to wrap.
   Retune the 6.41/12.8 pair if the hero copy ever changes length. */
h1 {
  font-size: clamp(30px, calc(6.41vw - 12.8px), 78px);
  line-height: 1.16; letter-spacing: clamp(7px, .68vw, 9px);
  text-transform: uppercase;
}
/* Capped at 56 by the same constraint that used to cap it at 49: the longest
   caps phrase on the site ("A sanctuary for the") has to hold one line, and
   above that it strands "THE" on the italic line. What changed is the grid —
   MyStudio's copy column went from .95fr to 1.26fr, which bought the 100px
   the larger size needs. */
h2 {
  font-size: clamp(27px, 4.4vw, 56px);
  line-height: 1.22; letter-spacing: clamp(4.4px, .38vw, 4.9px);
  text-transform: uppercase; margin-bottom: 22px;
}
h3 { font-size: 18px; line-height: 1.35; letter-spacing: .13em; text-transform: uppercase; }

/* The italic half of a headline stays EB Garamond: Italiana has no italic, and
   the contrast between its caps and Garamond's italic lowercase is what the
   headings are actually built on. */
h1 em, h2 em, h3 em {
  font-family: var(--serif);
  font-style: italic; text-transform: lowercase; letter-spacing: .01em; font-size: 1.06em;
}
h3 em { font-size: 1.14em; }

/* balance evens the lines of a short block — it is what stops the hero
   subhead breaking as "…refuge from the / city's noise". pretty only fixes the
   last line, which is the right treatment for a real paragraph. */
.lead { font-size: clamp(18.5px, 2.1vw, 22px); line-height: 1.7; margin: 0; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }
.muted   { color: rgba(51, 39, 28, .74); }
.muted-2 { color: rgba(51, 39, 28, .58); }
.small   { font-size: 18px; line-height: 1.6; }
.label   { font-size: 16px; letter-spacing: .18em; text-transform: uppercase; margin: 0; }
.ph      { border-bottom: 1px dotted rgba(130, 89, 64, .7); color: var(--terracotta-ink); }
.rule    { height: 1px; background: rgba(103, 102, 76, .22); border: 0; margin: 0; }

/* --- Buttons -------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 52px; padding: 15px 30px;
  border: 1px solid transparent; border-radius: 999px;
  background: var(--moss); color: var(--cream);
  font-family: var(--serif); font-size: 11px; letter-spacing: .24em; text-transform: uppercase;
  cursor: pointer; transition: background-color .3s ease, color .3s ease, border-color .3s ease;
}
.btn:hover { background: var(--espresso); color: var(--cream); }
.btn--ghost { background: transparent; border-color: rgba(51, 39, 28, .32); color: var(--espresso); }
.btn--ghost:hover { background: rgba(51, 39, 28, .06); border-color: var(--espresso); color: var(--espresso); }
.btn--light { background: transparent; border-color: rgba(244, 233, 216, .62); color: var(--cream); }
.btn--light:hover { background: rgba(244, 233, 216, .14); color: #fff; }
.btn--tan { background: var(--tan); color: var(--ink); }
.btn--tan:hover { background: var(--cream); color: var(--espresso); }
.btn--sm { min-height: 44px; padding: 12px 24px; }
.btn--block { width: 100%; }

.arrowlink {
  display: inline-flex; align-items: center; gap: 12px;
  font-size: 11px; letter-spacing: .24em; text-transform: uppercase;
}

/* --- Image shapes --------------------------------------------------------- */

.arch { border-radius: 50% 50% 18px 18px / 28% 28% 18px 18px; object-fit: cover; width: 100%; }
.round { border-radius: 999px; object-fit: cover; }
.soft { border-radius: 20px; object-fit: cover; width: 100%; }
.feature-img { height: 400px; }

/* --- Sticky nav ----------------------------------------------------------- */
/* Transparent over the hero video, condensing to a solid bar on scroll.
   Fails safe: without JS the .is-solid class is never added and it stays clear. */

.nav-sticky { position: sticky; top: 0; z-index: 60; height: 0; }

.nav {
  background-color: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color .5s ease, border-color .5s ease, box-shadow .5s ease;
}
.nav__inner {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding-top: 16px; padding-bottom: 12px;
  transition: padding .5s ease;
}
.nav__links, .nav__links--right { display: none; }
.nav a.navlink {
  font-size: 16px; letter-spacing: .07em; color: var(--cream);
  transition: color .4s ease; white-space: nowrap;
}
.nav a.navlink:hover { color: #fff; }

.logo {
  position: relative; display: flex; align-items: center; justify-content: center;
  width: 64px; height: 82px;
  transition: width .5s ease, height .5s ease;
}
.logo img { position: absolute; }
.logo__full { width: 64px; opacity: 1; transition: opacity .35s ease, transform .5s ease; }
.logo__mark { width: 28px; opacity: 0; transition: opacity .35s ease; }

.acct {
  display: none; align-items: center; gap: 9px;
  padding: 10px 20px; border: 1px solid rgba(244, 233, 216, .45); border-radius: 999px;
  color: var(--cream); font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  transition: color .4s ease, border-color .4s ease;
}

.nav.is-solid {
  background-color: rgba(250, 246, 239, .95);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-bottom-color: rgba(103, 102, 76, .16);
  box-shadow: 0 10px 34px rgba(51, 39, 28, .07);
}
.nav.is-solid .nav__inner { padding-top: 10px; padding-bottom: 10px; }
.nav.is-solid a.navlink { color: rgba(51, 39, 28, .82); }
.nav.is-solid a.navlink:hover { color: var(--espresso); }
.nav.is-solid .acct { color: var(--espresso); border-color: rgba(51, 39, 28, .3); }
.nav.is-solid .logo { width: 36px; height: 36px; }
.nav.is-solid .logo__full { opacity: 0; transform: scale(.5); }
.nav.is-solid .logo__mark { opacity: 1; }
.nav.is-solid .burger span { background: var(--espresso); }

/* Burger */
.burger {
  display: inline-flex; flex-direction: column; gap: 6px;
  align-items: flex-start; justify-content: center;
  width: 44px; height: 44px; margin-left: -10px;
  background: none; border: 0; padding: 0; cursor: pointer;
}
.burger span { display: block; height: 1px; background: var(--cream); transition: background-color .4s ease; }
.burger span:nth-child(1) { width: 24px; }
.burger span:nth-child(2) { width: 16px; }

/* Language toggle */
.lang { display: flex; align-items: center; gap: 8px; font-size: 10.5px; letter-spacing: .12em; }
.lang__opt {
  padding-bottom: 2px; border-bottom: 1px solid transparent;
  color: rgba(244, 233, 216, .6); transition: color .4s ease;
}
.lang__opt:hover { color: var(--cream); }
.lang__opt.is-on { color: #FAF6EF; border-bottom-color: currentColor; }
.lang__track {
  position: relative; width: 34px; height: 18px; border-radius: 999px;
  background: rgba(244, 233, 216, .34); transition: background-color .4s ease;
}
.lang__knob {
  position: absolute; top: 3px; left: 19px; width: 12px; height: 12px;
  border-radius: 999px; background: #FAF6EF; transition: left .35s ease;
}
.nav.is-solid .lang__opt { color: rgba(51, 39, 28, .5); }
.nav.is-solid .lang__opt.is-on { color: var(--espresso); }
.nav.is-solid .lang__track { background: rgba(51, 39, 28, .22); }

/* --- Mobile menu ---------------------------------------------------------- */

.menu {
  position: fixed; inset: 0; z-index: 90;
  background: var(--ink); color: var(--cream);
  display: flex; flex-direction: column; padding: 22px var(--pad) 26px;
  opacity: 0; visibility: hidden; transform: translateY(-8px);
  transition: opacity .35s ease, transform .35s ease, visibility .35s;
}
.menu.is-open { opacity: 1; visibility: visible; transform: none; }
.menu__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .15; }
.menu__veil {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(27,21,14,.93) 0%, rgba(27,21,14,.97) 55%, var(--ink) 100%);
}
.menu__body { position: relative; display: flex; flex-direction: column; height: 100%; }
.menu__top { display: flex; align-items: center; justify-content: space-between; }
.menu__close {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin-left: -10px;
  background: none; border: 0; color: var(--cream); cursor: pointer;
}
.menu nav { margin-top: 32px; }
.menu__item {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  min-height: 60px; padding: 19px 0;
  border-bottom: 1px solid rgba(244, 233, 216, .13);
  color: var(--cream);
}
.menu__item:last-child { border-bottom: 0; }
.menu__item:hover { color: var(--tan); }
.menu__item b { font-weight: 400; font-size: 25px; letter-spacing: .1em; }
.menu__item span { font-size: 12px; letter-spacing: .2em; text-transform: uppercase; color: rgba(244, 233, 216, .42); }
.menu__foot { margin-top: auto; display: flex; flex-direction: column; gap: 18px; }
.menu .lang__opt { color: rgba(244, 233, 216, .55); }
.menu .lang__opt.is-on { color: #FAF6EF; }

body.menu-open { overflow: hidden; }

/* --- MyCommunity ----------------------------------------------------------
   The testimonial sits inside the studio's own circle of light. The disc is a
   square crop of the real wall, masked so its corners fall away to paper —
   which is what stops it reading as a photograph pasted onto the section, and
   why the crop can keep the glow and the little monk at the foot of it.

   The whole section is centred now. It used to be a two-column split with the
   quote on a torn-paper card and a signup form beside it; the form has moved
   to the footer, because a section about the people in the room should show
   them rather than ask for an address. */
.community__head { text-align: center; max-width: 620px; margin: 0 auto; }

/* Full-bleed: the room runs the width of the page, and on desktop the quote
   sits on the disc itself. The two percentages below are where the circle
   actually falls in the frame — if the photograph is ever recropped, those are
   the numbers to redo.

   On a phone the quote comes out of the disc and sits under the photograph
   instead. At 390px the disc renders about 150px across and the quote needs
   270 to be readable, so there is no font size that both fits inside it and
   can be read; pretending otherwise would just produce a smudge. */
.voice { position: relative; width: 100vw; margin: 34px 0 0 calc(50% - 50vw); }
/* the photograph is a pseudo-element rather than the block's own background,
   so on a phone the quote can flow underneath it instead of being trapped
   inside the aspect-ratio box and landing on top of the picture */
.voice::before {
  content: ''; display: block; width: 100%; aspect-ratio: 2000 / 1333;
  background: url('../img/community-room.jpg') center / cover no-repeat;
  /* soft top and bottom only, so the photograph dissolves into the paper above
     and below while running clean off both sides */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 16%, #000 84%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0%, #000 16%, #000 84%, transparent 100%);
}
.voice blockquote {
  margin: 26px auto 0; width: min(100% - 48px, 420px); text-align: center;
  font-family: var(--hand); color: var(--espresso);
  font-size: 16px; line-height: 1.55;
}

@media (min-width: 900px) {
  .voice { margin-top: 52px; }
  /* the disc is 38.6% of the frame wide; the quote stays inside about four
     fifths of it, and scales with the frame rather than sitting at one size */
  .voice blockquote {
    position: absolute; left: 49.3%; top: 42.8%; transform: translate(-50%, -50%);
    margin: 0; width: 30%;
    font-size: clamp(15px, 1.45vw, 25px);
  }
}

/* The section is centred, so the caption sits under the circles rather than
   beside them — as a row, the group reads visibly off-axis. */
.community__close {
  max-width: 660px; margin: 44px auto 0; text-align: center;
}
.community__close .label { color: var(--terracotta-ink); margin-bottom: 18px; }
.community__close .lead { color: rgba(51, 39, 28, .8); }

@media (min-width: 900px) {
  .faces { margin-top: 52px; }
  .community__close { margin-top: 68px; }
}

/* --- The newsletter, in the footer ----------------------------------------
   Same component, dark ground: the light-theme borders and placeholder would
   all but vanish on espresso, so each one is restated against it. */
.foot .signup {
  padding: 0 0 34px; margin: 0 0 42px;
  border-top: 0; border-bottom: 1px solid rgba(244, 233, 216, .16);
}
.foot .signup .label { color: var(--tan); }
.foot .signup .signup__blurb { color: rgba(244, 233, 216, .66); margin-top: 12px; max-width: 46ch; }
.foot .signup input {
  border-color: rgba(244, 233, 216, .28); color: var(--cream);
}
.foot .signup input::placeholder { color: rgba(244, 233, 216, .42); }
.foot .signup input:focus-visible { border-color: rgba(244, 233, 216, .55); }

@media (min-width: 900px) {
  .foot .signup {
    display: grid; grid-template-columns: 1fr 1fr; gap: 48px; align-items: center;
  }
  .foot .signup form { margin-top: 0; }
}

/* --- The studio film ------------------------------------------------------
   Portrait 9:16 footage, so it takes the arch rather than sitting behind the
   section: as a full-width background it would be cropped to a letterbox
   sliver of itself. Muted, because no browser autoplays sound — the button
   over it is what turns the singing bowl on. */
.studiofilm { position: relative; }
.studiofilm__video { display: block; background: var(--sage); }

.studiofilm__sound {
  position: absolute; right: 16px; bottom: 16px; z-index: 2;
  display: inline-flex; align-items: center; gap: 9px;
  padding: 7px 15px 7px 7px; border: 0; border-radius: 999px;
  /* its own scrim, so the label stays legible over whatever frame is showing */
  background: rgba(27, 21, 14, .46);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  color: rgba(244, 233, 216, .88); font-family: var(--serif);
  font-size: 10.5px; letter-spacing: .22em; text-transform: uppercase;
  cursor: pointer; transition: background-color .4s ease, color .4s ease;
}
.studiofilm__sound:hover { background: rgba(27, 21, 14, .62); color: var(--paper); }
.studiofilm__sound i {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 999px;
  border: 1px solid rgba(244, 233, 216, .38);
}
/* one icon per state, swapped on aria-pressed so the control never lies about
   what the next click does. Shared with the hero's button — both are views of
   the same site-wide sound. */
[data-sound] .snd-on { display: none; }
[data-sound][aria-pressed="true"] .snd-on { display: block; }
[data-sound][aria-pressed="true"] .snd-off { display: none; }
.studiofilm__sound[aria-pressed="true"] {
  background: var(--moss); color: var(--cream);
}
.studiofilm__sound[aria-pressed="true"] i { border-color: rgba(244, 233, 216, .5); }

@media (min-width: 900px) {
  .studiofilm__sound { right: 22px; bottom: 22px; }
}

/* --- Motion ---------------------------------------------------------------
   Two pieces, both additive: if either fails to run the page is simply the
   page, with nothing hidden and nothing waiting.

   The opening. Only the hero is choreographed, and only its copy plus the media
   wrapper — the still itself already carries the slow `filmdrift` cinemagraph,
   so animating the wrapper leaves that alone. The nav is deliberately not in
   the sequence: hiding navigation for the first second buys atmosphere at the
   cost of someone being able to use the site.

   The drift. A scroll-linked parallax on the three large feature images, driven
   by `animation-timeline: view()` — no JS, off the main thread, and behind an
   @supports guard so a browser without it just shows the images where they have
   always been. 40px of travel across the entire time an image is on screen: it
   should register as depth rather than as an effect. */
@media (prefers-reduced-motion: no-preference) {
  .hero__media      { animation: heroSettle 1900ms var(--ease) both; }
  .hero__badge      { animation: heroRise 800ms var(--ease) 150ms both; }
  .hero__copy h1    { animation: heroRise 900ms var(--ease) 260ms both; }
  .hero__nature    { animation: heroRise 900ms var(--ease) 330ms both; }
  .hero__copy .lead { animation: heroRise 900ms var(--ease) 380ms both; }
  .hero__cta        { animation: heroRise 900ms var(--ease) 500ms both; }
}
@keyframes heroSettle { from { transform: scale(1.045); } to { transform: scale(1); } }
@keyframes heroRise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* `translate` rather than `transform`, so this can never clobber a
       transform the element is already carrying */
    /* img only — the studio film shares the .feature-img class for sizing, and
       driving a scroll-linked transform on a playing video buys nothing you can
       see while forcing it off the compositor's fast path on every frame. */
    img.feature-img, .founder img {
      animation: imgDrift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
  }
}
@keyframes imgDrift { from { translate: 0 20px; } to { translate: 0 -20px; } }

/* --- Paper grain ----------------------------------------------------------
   The palette is named for paper and cream but rendered as perfectly flat
   colour, which is the tell that separates a screen design from a printed one.
   A fractal-noise overlay at 3.5% gives the flat fields a material surface and
   reads as film grain over the photographs.

   Inline SVG rather than an image: about 300 bytes, no request, no cache. It is
   `fixed`, so it never repaints while scrolling, and `pointer-events: none` so
   it cannot intercept a click. z-index 1 keeps it under the sticky nav (60) and
   the mobile menu. */
body::after {
  content: '';
  position: fixed; inset: 0; z-index: 1;
  pointer-events: none;
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}
/* the grain is texture, not information — drop it where the display cannot
   render it usefully, and on print where real paper does the job */
@media print { body::after { display: none; } }

/* --- Hero ----------------------------------------------------------------- */

/* The 560px floor was not enough room for the copy stack once the nav's logo
   is standing in the top ~100px of it: on a 375x667 phone the badge already
   sat 24px inside the logo before the "we are nature" line existed, and on a
   320x568 one it sat 136px inside. Letting the hero be a little taller than a
   short screen is the honest fix — the alternative is cramming six elements
   into 460px and calling it a design. */
.hero { position: relative; height: 88svh; min-height: 640px; max-height: 900px; overflow: hidden; background: var(--espresso); }
.hero__media { position: absolute; inset: 0; }

/* The narrowest phones still cannot hold the stack: at 320px the headline
   takes three lines and the lead two, and the wordmark occupies the top
   100px. Rather than crush the type, the hero grows past the viewport there
   and the buttons sit just below the fold — which is what a 320x568 screen
   costs, with or without this line of copy. */
@media (max-width: 360px) {
  .hero { min-height: 760px; }
}
.hero__still {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 52% 62%;
  animation: filmdrift 18s ease-in-out infinite alternate;
}
@keyframes filmdrift {
  from { transform: scale(1.045) translate3d(-1.1%, .7%, 0); }
  to   { transform: scale(1.115) translate3d(1.5%, -.9%, 0); }
}
.hero__light {
  position: absolute; inset: -22%; pointer-events: none; mix-blend-mode: soft-light;
  background:
    radial-gradient(28% 32% at 72% 36%, rgba(255,244,222,.6), rgba(255,244,222,0) 70%),
    radial-gradient(44% 28% at 22% 15%, rgba(255,246,228,.34), rgba(255,246,228,0) 72%);
  animation: lightpass 15s ease-in-out infinite alternate;
}
@keyframes lightpass {
  from { transform: translate3d(-6%, -2%, 0); opacity: .5; }
  to   { transform: translate3d(7%, 3%, 0); opacity: .82; }
}
.hero__veil {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(27,21,14,.60) 0%, rgba(27,21,14,.30) 22%, rgba(27,21,14,.56) 58%, rgba(27,21,14,.80) 100%);
}
.hero__copy {
  position: relative; z-index: 2; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  text-align: center;
  /* Bottom-anchored, so the stack grows upward toward the logo. Fluid rather
     than fixed: on a short screen the padding gives way before the copy has
     to climb into the nav. */
  padding-bottom: clamp(48px, 11svh, 110px);
}
.hero__copy h1 { color: var(--paper); text-shadow: 0 2px 30px rgba(27,21,14,.35); }
.hero__copy .lead { margin-top: 16px; color: rgba(250,246,239,.88); max-width: 620px; }
.hero__cta { display: flex; flex-direction: column; gap: 12px; margin-top: 28px; width: 100%; max-width: 340px; }
.hero__sound {
  position: absolute; right: var(--pad); bottom: 108px; z-index: 2;
  display: none; align-items: center; gap: 10px;
  background: none; border: 0; cursor: pointer;
  color: rgba(244,233,216,.75); font-family: var(--serif);
  font-size: 10.5px; letter-spacing: .24em; text-transform: uppercase;
}
.hero__sound i {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border: 1px solid rgba(244,233,216,.4); border-radius: 999px;
}
.hero__sound[aria-pressed="true"] { color: var(--paper); }
.hero__sound[aria-pressed="true"] i { border-color: rgba(244,233,216,.8); }
.hero__seam {
  position: absolute; left: -18%; right: -18%; bottom: -2px; z-index: 3;
  height: 74px; background: var(--paper);
  border-radius: 50% 50% 0 0 / 100% 100% 0 0;
}

/* --- Reveal on scroll ----------------------------------------------------- */
/* Fail-safe: the hidden state only applies once JS adds .reveal-ready. */

.reveal-ready [data-reveal] {
  opacity: 0; transform: translateY(16px);
  transition: opacity .85s var(--ease), transform .85s var(--ease);
}
.reveal-ready [data-reveal].is-shown { opacity: 1; transform: none; }

/* --- Sections ------------------------------------------------------------- */

section { padding: 66px 0; }
.sec--cream { background: var(--cream); }
.sec--sage  { background: var(--sage); }
/* clip, not hidden: hidden would make the section a scroll container and a
   stray vw rounding error would show as a horizontal scrollbar */
#mytea, #mycommunity { overflow-x: clip; }
.sec--dark  { background: var(--espresso); color: var(--cream); }
.sec--dark .eyebrow { color: var(--tan); }
.sec--dark .muted { color: rgba(244,233,216,.78); }
.sec--dark .muted-2 { color: rgba(244,233,216,.55); }
.sec--sage .eyebrow { color: var(--espresso); }
.sec--sage .muted { color: rgba(27,21,14,.75); }

.intro { position: relative; padding-top: 20px; overflow: hidden; }
.intro .wrap { position: relative; }

.values { display: none; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 28px; }
.chip {
  padding: 9px 15px; border: 1px solid rgba(103,102,76,.3); border-radius: 999px;
  color: var(--moss); font-size: 10px; letter-spacing: .26em; text-transform: uppercase;
}

/* Hairline rules rather than filled boxes. A rounded rectangle with a fill is
   the most generic shape on the web, and three of them in a row was the least
   considered moment on the page. The rule and the space do the same grouping
   work with far less enclosure — which is also the more restful reading, and
   it is the pattern MyTea's price list already used. */
.facts { display: flex; flex-direction: column; gap: 0; margin-top: 26px; }
.fact {
  display: flex; align-items: center; gap: 14px;
  padding: 18px 0; border-top: 1px solid rgba(103, 102, 76, .2);
}
.fact:last-child { border-bottom: 1px solid rgba(103, 102, 76, .2); }
.fact svg { flex-shrink: 0; }

/* Schedule */

/* Price list */
.pricelist { margin-top: 32px; }
.price-row {
  display: flex; justify-content: space-between; gap: 16px; padding: 18px 0;
  border-top: 1px solid rgba(244,233,216,.16);
}
.price-row:last-child { border-bottom: 1px solid rgba(244,233,216,.16); }

/* Cards */
.cards { display: grid; grid-template-columns: 1fr; gap: 14px; margin-top: 26px; }
.cards:has(.card:only-child) { max-width: 620px; }
/* Hairline rule rather than a filled panel, matching the facts, the newsletter
   and the pricing tiles. The rule is ink rather than the moss used elsewhere:
   moss on the sage ground is almost invisible. The photograph keeps a shape of
   its own — an image needs an edge in a way a block of text does not. */
.card { display: flex; flex-direction: column; border-top: 1px solid rgba(27, 21, 14, .24); }
.card img { width: 100%; height: 190px; object-fit: cover; border-radius: 14px; margin-top: 20px; }
.card__body { padding: 20px 0 0; display: flex; flex-direction: column; gap: 12px; flex-grow: 1; }
.card__foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: auto; padding-top: 12px; }

/* Cream, but not quite opaque: the leaf-shadow clip hanging from the top-left
   of the shadow band runs 345px down behind this panel, and at full opacity the
   panel cut a hard rectangle out of it. At .82 the branch keeps drifting
   faintly across the top of the box. Any lower and the panel stops reading as
   a panel — it is only two shades off the paper it sits on to begin with. */
.founder { padding: 26px; background: rgba(244, 233, 216, .82); border-radius: 22px; margin-top: 24px; }
.founder img { height: 340px; }
.sig { font-family: var(--hand); font-size: 26px; color: var(--moss); margin-top: 18px; }

/* --- Teachers ------------------------------------------------------------- */

.teachers { display: grid; grid-template-columns: 1fr; gap: 40px; margin-top: 32px; align-items: start; }
/* The portrait sits in its own frame so it can move without the arch moving
   with it: the frame carries the shape and clips, the image scales inside it.
   Scaling the arch itself would grow the silhouette, which reads as a wobble
   rather than as a breath. */
.teacher__frame {
  overflow: hidden; width: 100%; aspect-ratio: 1 / 1;
  border-radius: 50% 50% 18px 18px / 28% 28% 18px 18px;
}
/* the shape lives on the frame now, so the child gives it up — scoped tightly
   enough to beat the .arch rule that raises the radius at desktop width */
.teacher .teacher__frame > * {
  width: 100%; height: 100%; display: block;
  border-radius: 0;
  transition: transform 1.1s var(--ease), filter 1.1s var(--ease);
}
/* slow and small on purpose — the whole argument of the page is against hurry,
   so the portrait settles rather than snaps */
.teacher:hover .teacher__frame > * { transform: scale(1.045); filter: saturate(1.05); }
.teacher h3 { transition: color .5s var(--ease); }
.teacher:hover h3 { color: var(--terracotta-ink); }
@media (prefers-reduced-motion: reduce) {
  .teacher .teacher__frame > * { transition: none; }
  .teacher:hover .teacher__frame > * { transform: none; }
}

.teacher img, .teacher .arch { width: 100%; height: auto; aspect-ratio: 1 / 1; }

/* Tablet: two up, so the arch is not letterboxed across a full-width column. */
@media (min-width: 620px) and (max-width: 899px) {
  .teachers { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 36px 24px; }
}

.teacher h3 { margin-top: 22px; font-size: 20px; letter-spacing: .12em; }
.teacher__role {
  margin-top: 7px; color: var(--terracotta-ink);
  font-size: 10.5px; letter-spacing: .26em; text-transform: uppercase;
}
.teacher__lede { margin-top: 16px; color: rgba(51, 39, 28, .8); }

/* Portrait still to come — a deliberate placeholder, not a broken image. */
.teacher__await {
  display: flex; align-items: flex-end; justify-content: center;
  padding-bottom: 26px;
  background: rgba(183, 181, 168, .38);
  border: 1px solid rgba(103, 102, 76, .16);
}
.teacher__await .label { color: rgba(51, 39, 28, .5); }

/* Read more — native <details>, so it works with JavaScript disabled. */
.bio { margin-top: 16px; }
.bio summary {
  display: inline-flex; align-items: center; gap: 10px;
  cursor: pointer; list-style: none;
  color: var(--terracotta-ink);
  font-size: 11px; letter-spacing: .24em; text-transform: uppercase;
  padding: 6px 0; min-height: 34px;
}
.bio summary::-webkit-details-marker { display: none; }
.bio summary::marker { content: ''; }
.bio summary:hover { color: var(--moss); }
.bio summary svg { transition: transform .35s var(--ease); }
.bio[open] summary svg { transform: rotate(180deg); }
.bio__less { display: none; }
.bio[open] .bio__more { display: none; }
.bio[open] .bio__less { display: inline; }
.bio__body { display: flex; flex-direction: column; gap: 15px; margin-top: 10px; }
.bio__body p { color: rgba(51, 39, 28, .74); }

/* Community note */
.note { position: relative; margin-top: 26px; }
.note img { width: 100%; transform: rotate(-1.4deg); filter: drop-shadow(0 16px 30px rgba(51,39,28,.14)); }
.note blockquote {
  position: absolute; top: 20%; left: 11%; right: 11%; margin: 0;
  font-family: var(--hand); font-size: clamp(14px, 3.6vw, 21px); line-height: 1.8;
  color: var(--espresso); text-align: center; transform: rotate(-1.4deg);
}
.faces { display: flex; gap: 12px; align-items: center; margin-top: 30px; flex-wrap: wrap; }
/* the three portraits stay a row inside the column */
#mycommunity .faces { display: grid; grid-template-columns: repeat(3, auto); justify-content: center; gap: 20px; }
.faces img { width: 104px; height: 104px; }

.signup {
  margin-top: 30px; padding: 26px 0 0;
  border-top: 1px solid rgba(103, 102, 76, .24);
}
.signup form { display: flex; flex-direction: column; gap: 10px; margin-top: 18px; }
.signup input {
  min-height: 54px; padding: 15px 22px; border: 1px solid rgba(51,39,28,.2);
  border-radius: 999px; background: transparent; color: var(--espresso);
  font-family: var(--serif); font-size: 16.5px;
}
.signup input::placeholder { color: rgba(51,39,28,.42); }

/* Membership */

/* Two bands, so the two commitment models never get compared as one flat list:
   a monthly membership and a one-off pass are different promises and the prices
   only make sense once you can see which is which. */
.band + .band { margin-top: 44px; }
.band__label {
  font-family: var(--display); font-size: 21px; letter-spacing: .1em;
  text-transform: uppercase; margin: 0;
}
.band__note { margin-top: 6px; }

/* The chooser. Nine products in two models is a lot to compare by eye, so it
   asks one question instead and marks the plan that actually costs least for
   that answer. It never hides anything — every plan stays where it was. */
.chooser { margin-top: 30px; }
.chooser__q { color: var(--moss); }
.chooser__opts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.chooser__opt {
  padding: 10px 18px; border-radius: 999px;
  border: 1px solid rgba(51, 39, 28, .18); background: none;
  color: rgba(51, 39, 28, .66); font-family: var(--serif);
  font-size: 13px; letter-spacing: .1em; text-transform: uppercase;
  white-space: nowrap; cursor: pointer;
  transition: background-color .3s ease, border-color .3s ease, color .3s ease;
}
.chooser__opt:hover { border-color: rgba(51, 39, 28, .42); color: var(--espresso); }
.chooser__opt.is-on { background: var(--moss); border-color: var(--moss); color: var(--cream); }
.chooser__note { margin-top: 14px; min-height: 1.6em; }
.chooser + .band { margin-top: 38px; }

/* The answer, immediately under the buttons that asked the question. The
   marked tile can sit hundreds of px further down — at "now and then" it is
   the drop-in, which lives in the second band — so without this you press a
   button and, from where you are standing, nothing happens. */
.pickout { display: none; }
.pickout.is-on {
  display: flex; flex-direction: column; align-items: flex-start; gap: 18px;
  margin-top: 22px; padding: 22px 0;
  border-top: 1px solid rgba(103, 102, 76, .28);
  border-bottom: 1px solid rgba(103, 102, 76, .28);
  animation: pickIn .5s var(--ease) both;
}
.pickout__body { display: flex; flex-direction: column; gap: 6px; }
.pickout__tag {
  align-self: flex-start;
  padding: 5px 13px; border-radius: 999px;
  background: var(--moss); color: var(--cream);
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
}
.pickout__name {
  font-family: var(--display); font-size: 25px;
  letter-spacing: .06em; text-transform: uppercase; margin: 4px 0 0;
}
.pickout__price { font-family: var(--display); font-size: 32px; line-height: 1; margin: 2px 0 0; }
.pickout__price .cur { color: rgba(51, 39, 28, .42); }
.pickout__maths { color: rgba(51, 39, 28, .55); margin-top: 4px; }

@keyframes pickIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .pickout.is-on { animation: none; }
}

/* A plan that cannot cover the chosen month stays on the page and comparable,
   it just steps back. Removing it would answer the question by hiding the
   alternatives, which is the opposite of what the section is for. */
.plan--out { opacity: .52; }
.plan { transition: opacity .4s var(--ease); }

/* The marked plan. A ring rather than a fill, so it can land on the featured
   tile without fighting the moss it already has. */
/* Floated above the tile's top edge rather than placed in flow: on mobile
   .plan is a two-column grid and an in-flow flag row eats a cell, pushing the
   name and price sideways. */
.plan__flags {
  position: absolute; top: -13px; left: 0;
  display: flex; align-items: center; gap: 8px;
}
.plan__pick {
  display: none;
  padding: 5px 13px; border-radius: 999px;
  background: var(--moss); color: var(--cream);
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase; white-space: nowrap;
}
.plan--pick .plan__pick { display: inline-block; }
.plan--pick { box-shadow: 0 0 0 1.5px var(--moss); border-radius: 16px; }
.plan--featured.plan--pick { box-shadow: 0 0 0 3px rgba(103, 102, 76, .32); }
.plan--featured .plan__pick { background: var(--cream); color: var(--espresso); }
.plan__per { font-family: var(--serif); font-size: 14px; letter-spacing: .04em; }
/* line-height and min-height are the same value on purpose: the line is empty
   until a frequency is picked, and any mismatch makes every tile grow by a few
   px the moment it fills, which reads as the row twitching. */
.plan__maths {
  margin-top: 6px; color: rgba(51, 39, 28, .52);
  font-size: 14px; line-height: 1.5; min-height: 1.5em;
  /* the mobile tile is a two-column grid, and in the narrow left cell this
     line wraps to two the moment it fills — which grew every tile at once.
     It takes the whole row instead, the same as the button does. */
  grid-column: 1 / -1;
}
.plan--featured .plan__maths { color: rgba(244, 233, 216, .68); }

.plans { display: flex; flex-direction: column; gap: 12px; margin-top: 26px; }
/* The plain tiles lose their fill; the featured one keeps it, and reads far
   louder for being the only filled thing in the row. */
.plan {
  position: relative;
  padding: 22px 14px; border-top: 1px solid rgba(103, 102, 76, .2);
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 14px 16px;
}
.plan:last-child { border-bottom: 1px solid rgba(103, 102, 76, .2); }
.plan .btn { grid-column: 1 / -1; }
.plan--featured {
  background: var(--moss); color: var(--cream); position: relative;
  padding: 22px 20px; border-top-color: transparent; border-radius: 20px;
}
.plan__badge {
  padding: 6px 16px; border-radius: 999px;
  background: var(--terracotta); color: var(--paper);
  font-size: 10px; letter-spacing: .24em; text-transform: uppercase; white-space: nowrap;
}
.plan .label { color: var(--moss); }
.plan__note { margin-top: 8px; }
.plan--featured .label { color: rgba(244,233,216,.72); }
.plan--featured .muted-2 { color: rgba(244,233,216,.7); }
.plan__price { font-family: var(--display); font-size: 30px; line-height: 1; white-space: nowrap; }
.plan__price .cur { color: rgba(51,39,28,.42); }
.plan--featured .plan__price .cur { color: rgba(244,233,216,.55); }
.plan--featured .ph { color: var(--cream); border-color: rgba(244,233,216,.6); }
/* The featured tile sits on moss, so its button inverts to cream-on-espresso. */
.plan--featured .btn { background: var(--cream); color: var(--espresso); }

/* Tablet: two up. Must sit after the base .plans rule above — a media query does
   not raise specificity, so an earlier rule would simply be overridden. */
@media (min-width: 620px) and (max-width: 899px) {
  .plans { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
}

/* Footer */
.foot { background: var(--ink); color: var(--cream); padding: 60px 0 34px; text-align: center; }
.foot img.mark { width: 84px; margin: 0 auto; }
/* The blurb is capped at 340px so it breaks into two comfortable lines. On the
   stacked footer everything else is centred, but a capped block is still
   left-aligned in its column, so the paragraph sat off to one side while the
   text inside it was centred. Centre the box itself; the desktop footer is a
   three-column grid where it belongs hard left, so that width puts it back. */
.foot__blurb { margin-left: auto; margin-right: auto; }

.foot a { color: rgba(244,233,216,.75); }
.foot a:hover { color: var(--tan); }
.foot .ph { color: rgba(244,233,216,.7); border-color: rgba(174,144,119,.6); }
.social { display: flex; gap: 12px; justify-content: center; margin-top: 28px; }
.social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border: 1px solid rgba(244,233,216,.28); border-radius: 999px;
  color: var(--cream);
}
.social a:hover { border-color: var(--tan); color: var(--tan); }

/* ==========================================================================
   Desktop
   ========================================================================== */

@media (min-width: 900px) {
  :root { --pad: 80px; }
  html { scroll-padding-top: 110px; }
  body { font-size: 18.5px; }

  section { padding: 120px 0; }
  .intro { padding-top: 40px; padding-bottom: 130px; }

  .eyebrow { font-size: 11px; letter-spacing: .38em; margin-bottom: 26px; }
  h2 { margin-bottom: 28px; }

  .hero { height: 830px; max-height: none; }
  .hero__still { object-position: 56% 58%; }
  /* The copy is anchored to the bottom, so anything it gains grows upward
     toward the centred logo — adding the "we are nature" line put the badge
     24px inside it. Sitting the block lower buys the clearance back without
     touching the type, and there was 292px of slack under the buttons. */
  .hero__copy { padding-bottom: clamp(96px, 17svh, 150px); }
  .hero__cta { flex-direction: row; max-width: none; justify-content: center; margin-top: 38px; }
  .hero__sound { display: flex; bottom: 130px; }
  .hero__seam { height: 130px; left: -12%; right: -12%; }

  /* Deliberately uneven. Every section used to be a near-even split, which is
     what makes a page read as templated rather than art-directed. The ratios
     now differ by section and by which column is carrying the argument:
     --text-major gives MyStudio's copy the room its headline needs, which is
     also what let h2 go back up to 56px. */
  .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 90px; align-items: center; }
  .grid-2--top { align-items: start; }
  .grid-2--wide-left { grid-template-columns: 1.28fr .72fr; }
  .grid-2--wide-right { grid-template-columns: .92fr 1.08fr; }
  .grid-2--text-major { grid-template-columns: .74fr 1.26fr; gap: 76px; }
  /* MyWorkshops mirrors MyTea: the photograph leaves the grid, but off the
     LEFT edge, so the two do not read as the same slide twice. Same negative
     margin, same 660px, and the radii swap hands — the arch is on the inner
     (right) side and the bleeding edge squares off, because a rounded corner
     hanging at the viewport boundary just looks like a mistake. */
  .grid-2--image-left { grid-template-columns: 1.08fr .92fr; }
  #myworkshops .grid-2 > div:first-child {
    margin-left: calc(-1 * (var(--pad) + max(0px, (100vw - var(--maxw)) / 2)));
  }
  #myworkshops .feature-img {
    height: 660px;
    border-radius: 0 50% 18px 0 / 0 30% 18px 0;
  }

  /* MyTea's image runs off the right-hand edge of the page. Every image on the
     site otherwise sits inside the same gutters at roughly the same scale,
     which is what makes a layout read as a template; one deliberate break gives
     the page a change of register, and the dark section is the right place for
     it. The right-hand corners square off, since a rounded edge hanging at the
     viewport boundary just looks like a mistake. */
  #mytea .grid-2 > div:last-child {
    margin-right: calc(-1 * (var(--pad) + max(0px, (100vw - var(--maxw)) / 2)));
  }
  #mytea .feature-img {
    height: 660px;
    border-radius: 50% 0 0 18px / 30% 0 0 18px;
  }

  /* Body copy takes a measure. Display type can run the full width of its
     column; a paragraph cannot — past roughly 75 characters the eye starts
     losing the line return. Widening MyStudio's column made this necessary:
     without a cap that paragraph ran to 102 characters a line. */
  .grid-2 p.muted, .grid-2 p.small { max-width: 62ch; }
  .values { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 34px; }
  .chips { display: none; }
  .facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 34px; margin-top: 46px; }
  .fact {
    flex-direction: column; align-items: flex-start; gap: 0;
    padding: 22px 0 0; border-top: 1px solid rgba(103, 102, 76, .2);
  }
  /* three columns already read as a row, so the closing rule is redundant */
  .fact:last-child { border-bottom: 0; }
  .fact .label { margin-top: 16px; }
  .fact p.small { margin-top: 8px; }

  .arch, .teacher__frame { border-radius: 50% 50% 20px 20px / 30% 30% 20px 20px; }
  .teachers { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 40px 32px; margin-top: 56px; }

  /* --card-cols is set by schedule.js from the number of workshops on the
     calendar. Fixed at three, two workshops left the whole right-hand column
     empty directly under the photograph, which read as a layout that had lost
     something rather than a section with two things in it. */
  .cards { grid-template-columns: repeat(var(--card-cols, 3), minmax(0, 1fr)); gap: 28px; margin-top: 48px; }
  .card img { height: 300px; }
  .card__body { padding: 34px 32px 36px; gap: 16px; }
  .card__foot { padding-top: 24px; }

  /* --plan-cols is set by pricing.js from the number of plans the app returns;
     the 5 here is the fallback for the static markup and for no-JS. */
  .plans { display: grid; grid-template-columns: repeat(var(--plan-cols, 5), minmax(0, 1fr)); gap: 16px; margin-top: 66px; }
  .feature-img { height: 660px; }
  .band + .band { margin-top: 64px; }
  .band__label { font-size: 27px; }
  .chooser { margin-top: 44px; }
  .chooser__note { margin-top: 16px; }
  .chooser + .band { margin-top: 58px; }
  /* on a wide row the answer and its button sit on one line */
  .pickout.is-on {
    flex-direction: row; align-items: center; justify-content: space-between;
    gap: 40px; padding: 26px 0;
  }
  .pickout__body { flex-direction: row; align-items: baseline; gap: 26px; flex-wrap: wrap; }
  .pickout__tag { align-self: center; }
  .pickout__name { margin: 0; }
  .pickout__price { margin: 0; }
  .pickout__maths { margin-top: 0; }
  .plans { gap: 16px 26px; }
  /* Bottom padding matches the top so the ring on the marked tile has the same
     room under the button as it has above the name. It goes on every tile, not
     just the marked one, so selecting a frequency cannot make the row jump. */
  .plan { display: flex; flex-direction: column; align-items: stretch; gap: 14px; padding: 30px 14px; }
  .plan:last-child { border-bottom: 0; }
  .plan--featured { padding: 30px 22px; border-radius: 24px; }
  .plan__price { font-size: 38px; margin: 8px 0 0; }
  .plan .btn { margin-top: auto; padding-left: 16px; padding-right: 16px; font-size: 10.5px; letter-spacing: .18em; }
  .account-feats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 32px; margin-top: 64px; padding-top: 52px; border-top: 1px solid rgba(103,102,76,.22); }
  .account-feat { display: flex; gap: 16px; }

  .signup { margin-top: 48px; padding: 34px 0 0; }
  .signup form { flex-direction: row; margin-top: 24px; }
  .signup input { flex-grow: 1; }
  .faces img { width: 152px; height: 152px; }
  .note blockquote { font-size: 21px; }

  .foot { padding: 110px 0 0; text-align: left; }
  .foot__cols { display: grid; grid-template-columns: 1.1fr 1fr 1fr; gap: 70px; align-items: start; }
  .foot__blurb { margin-left: 0; margin-right: 0; }
  .foot img.mark { margin: 0; width: 108px; }
  .social { justify-content: flex-start; }
  .foot__tag { text-align: center; margin-top: 96px; }
  .foot__legal {
    display: flex; justify-content: space-between; align-items: center; gap: 30px;
    margin-top: 60px; padding: 26px 0 34px; border-top: 1px solid rgba(244,233,216,.14);
  }
}

/* ==========================================================================
   Reduced motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .hero__still, .hero__light { animation: none !important; }
  .reveal-ready [data-reveal] { opacity: 1 !important; transform: none !important; transition: none !important; }
  *, *::before, *::after { transition-duration: .01ms !important; }
}

/* ==========================================================================
   Print
   ========================================================================== */

@media print {
  .nav-sticky, .menu, .hero__sound, .signup form { display: none; }
  body { background: #fff; }
}

/* ==========================================================================
   Opening night — time-limited
   ==========================================================================
   Delete this block, the .launch <aside> and the .hero__badge markup once
   MyZen has opened.
   ========================================================================== */

.hero__badge {
  margin: 0 0 22px;
  padding: 9px 20px;
  border: 1px solid rgba(244, 233, 216, .45);
  border-radius: 999px;
  color: var(--cream);
  font-size: 10.5px; letter-spacing: .26em; text-transform: uppercase;
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}

.launch { background: var(--espresso); color: var(--cream); padding: 60px 0; }
.launch__inner { display: flex; flex-direction: column; gap: 30px; }
.launch__date {
  font-family: var(--display);
  font-size: clamp(40px, 9vw, 62px); line-height: .95;
  color: var(--cream); margin: 0;
}
.launch__time {
  margin-top: 12px;
  color: var(--tan);
  font-size: 11px; letter-spacing: .26em; text-transform: uppercase;
}
.launch__body .lead { color: rgba(244, 233, 216, .82); max-width: 520px; }
.launch__cta { display: flex; flex-direction: column; gap: 12px; margin-top: 26px; }

@media (min-width: 620px) {
  .launch__cta { flex-direction: row; }
}

@media (min-width: 900px) {
  .launch { padding: 84px 0; }
  .launch__inner {
    flex-direction: row; align-items: center; justify-content: space-between;
    gap: 80px;
  }
  .launch__when { flex-shrink: 0; }
  .launch__body { max-width: 560px; }
}

/* ==========================================================================
   Schedule — rendered from the app's public API
   ========================================================================== */

.schedule { margin-top: 30px; min-height: 200px; }
.schedule__day { color: rgba(51, 39, 28, .5); margin: 30px 0 14px; }
.schedule__day:first-child { margin-top: 0; }
.schedule__empty {
  padding: 40px 0; text-align: center;
  color: rgba(51, 39, 28, .55); font-size: 17px;
}

/* The list opens on a week and grows in weeks. Centred and quiet: it is a way
   to carry on reading, not a call to action competing with the Book buttons
   just above it. */
.schedule__more {
  display: block; margin: 26px auto 0;
  padding: 13px 30px; border-radius: 999px;
  border: 1px solid rgba(51, 39, 28, .2); background: none;
  color: rgba(51, 39, 28, .68); font-family: var(--serif);
  font-size: 12.5px; letter-spacing: .18em; text-transform: uppercase;
  cursor: pointer;
  transition: border-color .3s ease, color .3s ease;
}
.schedule__more:hover { border-color: rgba(51, 39, 28, .45); color: var(--espresso); }

.srows { display: flex; flex-direction: column; gap: 10px; }

.srow {
  display: flex; flex-direction: column; gap: 12px;
  padding: 22px; background: #fff; border-radius: 18px;
  transition: background-color .45s var(--ease), box-shadow .45s var(--ease);
}
/* A row is a whole class you might book, so the whole row answers to the
   pointer — a lift off the page rather than a colour change, which would fight
   the white the schedule reads on. Pointer-only: a touch device would leave
   the last-tapped row stuck in its hover state. */
@media (hover: hover) {
  .srow:hover { box-shadow: 0 10px 30px rgba(51, 39, 28, .09); }
  .srow:hover .srow__time { color: var(--terracotta-ink); }
}
.srow__time { transition: color .45s var(--ease); }
.srow__time { font-size: 19px; letter-spacing: .1em; margin: 0; }
.srow__dur  { font-size: 15px; color: rgba(51, 39, 28, .5); margin: 4px 0 0; }
.srow__main h3 { font-size: 17px; }
.srow__desc { font-size: 15px; color: rgba(51, 39, 28, .6); margin-top: 6px; }
.srow__teacher { display: flex; flex-wrap: wrap; gap: 10px; font-size: 15px; color: rgba(51, 39, 28, .72); }
.tperson { display: inline-flex; align-items: center; gap: 9px; }
.tperson__name { white-space: nowrap; }
/* 42px rather than 32: at the smaller size the portrait was a token beside the
   name rather than a face you could recognise, which is most of what it is
   there for. The source images are 64px, so this still renders under 1:1. */
.tavatar {
  flex-shrink: 0; width: 42px; height: 42px; border-radius: 999px;
  object-fit: cover; background: rgba(103, 102, 76, .12);
}
.tavatar--initials {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--sage); color: var(--espresso);
  font-size: 14.5px; letter-spacing: .06em;
}
.srow__meta    { display: flex; flex-direction: column; gap: 4px; }
.srow__level   { font-size: 15px; color: rgba(51, 39, 28, .5); }
.srow__price   { font-size: 15px; color: rgba(51, 39, 28, .5); }
/* mobile stacks, so drop cells that would read as orphaned lines */
.srow__teacher:empty, .srow__meta:empty { display: none; }
.srow__act {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-top: 4px;
}
.srow__spots { font-size: 15px; white-space: nowrap; }
.srow__spots--ok   { color: rgba(51, 39, 28, .55); }
.srow__spots--few  { color: var(--terracotta-ink); }
.srow__spots--full { color: var(--terracotta-ink); }

.card__date { color: var(--terracotta-ink); }

@media (min-width: 900px) {
  .schedule { margin-top: 40px; }
  .srows { gap: 12px; }
  /* the five-column row moved to its own breakpoint below — see "Wide rows" */
  /* keep the columns aligned even when a class has no teacher or level set */
  .srow__teacher:empty { display: block; }
  .srow__meta:empty { display: flex; }
  .srow__act { justify-content: flex-end; gap: 20px; margin-top: 0; }
}

/* --- Loading skeleton -----------------------------------------------------
   No spinner: this brand's whole argument is against hurry. The placeholders
   breathe instead — roughly the pace of a slow exhale — with each row a beat
   behind the last so it reads as organic rather than as one blinking block. */

.skel { display: flex; flex-direction: column; gap: 10px; }

.skel__bar, .skel__pill, .skel__thumb, .skel__day {
  display: block;
  background: rgba(103, 102, 76, .14);
  border-radius: 999px;
  animation: breathe 4.2s ease-in-out infinite;
}

.skel__day { width: 168px; height: 11px; margin: 26px 0 6px; }
.skel__day:first-child { margin-top: 0; }

.skel__row {
  display: flex; flex-direction: column; gap: 14px;
  padding: 22px; background: #fff; border-radius: 18px;
}
.skel__when, .skel__main { display: flex; flex-direction: column; gap: 9px; }

.skel__bar--time  { width: 62px;  height: 15px; }
.skel__bar--dur   { width: 44px;  height: 11px; }
.skel__bar--title { width: 62%;   height: 14px; }
.skel__bar--desc  { width: 84%;   height: 11px; }
.skel__bar--who   { width: 40%;   height: 11px; }
.skel__bar--meta  { width: 30%;   height: 11px; }
.skel__pill       { width: 104px; height: 44px; border-radius: 999px; }
.skel__thumb      { width: 100%;  height: 190px; border-radius: 14px; }

/* a beat between rows, so they do not pulse in lockstep */
.skel__row:nth-child(2) .skel__bar,
.skel__row:nth-child(2) .skel__pill { animation-delay: .45s; }
.skel__row:nth-child(4) .skel__bar,
.skel__row:nth-child(4) .skel__pill { animation-delay: .9s; }
.skel--card:nth-child(2) .skel__bar,
.skel--card:nth-child(2) .skel__thumb { animation-delay: .6s; }

/* mirrors .card exactly, so nothing shifts when the real workshops land */
.skel--card {
  gap: 12px; padding: 20px 0 0; border-top: 1px solid rgba(27, 21, 14, .24);
}
.skel--card .skel__bar--desc  { width: 46%; }
.skel--card .skel__bar--title { width: 74%; height: 14px; }
.skel--card .skel__bar--who   { width: 90%; height: 11px; }

/* On the sage panel a moss-tinted placeholder nearly disappears — go lighter
   there so the blocks read as pale paper instead. */
.sec--sage .skel__bar,
.sec--sage .skel__pill,
.sec--sage .skel__thumb { background: rgba(250, 246, 239, .55); }

@keyframes breathe {
  0%, 100% { opacity: .45; }
  50%      { opacity: .95; }
}

@media (prefers-reduced-motion: reduce) {
  .skel__bar, .skel__pill, .skel__thumb, .skel__day { animation: none; opacity: .7; }
}

@media (min-width: 900px) {
  .skel__day { margin: 30px 0 8px; }
  .skel__row {
    /* mirrors .srow, which is now defined at 1140px — see "Wide rows" */
  }
  .skel__pill { justify-self: end; }
  .skel--card .skel__thumb { height: 300px; }
}

/* --- The horizontal nav ---------------------------------------------------
   It used to appear at 900px, where it could not possibly fit: measured, the
   full-size version needs 1264px of viewport (left group 391 + logo 92 + right
   group 557 + gaps 64 + gutters 160), so between 900 and 1264 it silently ran
   off the right-hand edge — MyCommunity clipped and MyAccount disappeared.

   Two changes. Gaps and link size now ride a clamp rather than sitting at their
   widest, and MyAccount drops to its icon until there is room for the word —
   that label alone was spending 158px, a seventh of the bar, on a secondary
   action. Even tightened the row still measures 843px of content, so it waits
   for 1100px; below that the burger menu takes over, which it already did
   before 900px and is the better answer at tablet width than seven crammed
   links. 1040 would technically fit, with 10px to spare — not enough, since a
   fallback face renders wider than Garamond while the webfont is still
   swapping in. At 1100 there is 60px. The pill returns at 1360. */
@media (min-width: 1100px) {
  .nav__inner {
    display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
    gap: clamp(20px, 2.3vw, 32px);
    padding-top: 30px; padding-bottom: 22px;
  }
  .nav.is-solid .nav__inner { padding-top: 11px; padding-bottom: 11px; }
  .nav__links, .nav__links--right {
    display: flex; align-items: center; gap: clamp(20px, 2.4vw, 34px);
  }
  .nav__links--right { justify-content: flex-end; }
  .nav a.navlink { font-size: clamp(14.5px, 1.2vw, 16px); }
  .acct { display: inline-flex; }
  .burger, .menu, .lang--mobile { display: none; }
  .logo { width: 92px; height: 116px; }
  .logo__full { width: 92px; }
  .logo__mark { width: 36px; }
  .nav.is-solid .logo { width: 44px; height: 44px; }
  .lang { font-size: 11.5px; letter-spacing: .14em; gap: 10px; }
  .lang__track { width: 40px; height: 21px; }
  .lang__knob { left: 22px; width: 15px; height: 15px; }

  /* icon alone until there is room for the word */
  .acct { padding: 0; width: 40px; height: 40px; justify-content: center; }
  .acct__label { display: none; }
}

@media (min-width: 1360px) {
  .acct { width: auto; height: auto; padding: 10px 20px; }
  .acct__label { display: inline; }
}

/* --- Wide rows -----------------------------------------------------------
   The five-column schedule row and the founder block both used fixed pixel
   columns from 900px, and neither fits there. Measured at 960px: the row's
   flexible name column collapsed to 93px and the class description wrapped to
   eight lines; the founder's text column collapsed to 128px.

   The arithmetic is unforgiving — 128 + 180 + 140 + 236 of fixed columns, plus
   gaps and the row's own padding, is already more than the 740px of content a
   900px viewport has. So both wait until there is genuinely room and use the
   stacked layout until then, which is a perfectly good card. minmax() on the
   flexible column means it can never be squeezed to nothing again. */
@media (min-width: 1140px) {
  .srow, .skel__row {
    display: grid; grid-template-columns: 116px minmax(200px, 1fr) 164px 128px 212px;
    align-items: center; gap: 20px; padding: 26px 28px; border-radius: 20px;
  }
  .srow__when { display: block; }
  .srow__meta { display: flex; }

  .founder {
    display: grid; grid-template-columns: clamp(340px, 32vw, 470px) 1fr;
    gap: 56px; align-items: center; padding: 44px; border-radius: 28px; margin-top: 86px;
  }
  .founder img { height: 560px; }
  /* the text column runs to 670px+ on a wide screen, so it takes a measure the
     same way the .grid-2 copy does */
  .founder p { max-width: 62ch; }
}

@media (min-width: 1400px) {
  .srow, .skel__row { grid-template-columns: 128px minmax(240px, 1fr) 180px 140px 236px; gap: 24px; padding: 26px 32px; }
  .founder { gap: 80px; padding: 56px; }
}

/* --- Schedule controls: filters and view toggle --------------------------- */

.sched-bar {
  display: flex; flex-direction: column; gap: 16px;
  margin-top: 30px; padding-bottom: 4px;
}
.sched-filters { display: flex; flex-direction: column; gap: 12px; }
.fgroup { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.fgroup__label {
  font-size: 11px; letter-spacing: .24em; text-transform: uppercase;
  color: rgba(51, 39, 28, .42);
}

/* A pill-shaped select that reads as the same family as .btn--ghost and the
   view toggle. The chevron is a background image so it travels with the
   control; `appearance: none` is what removes the platform one. */
.fselect {
  -webkit-appearance: none; appearance: none;
  width: 100%; max-width: 100%;
  padding: 11px 42px 11px 18px; border-radius: 999px;
  border: 1px solid rgba(51, 39, 28, .16); background-color: transparent;
  color: rgba(51, 39, 28, .62); font-family: var(--serif);
  font-size: 13px; letter-spacing: .12em; text-transform: uppercase;
  text-overflow: ellipsis; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%2333271C' stroke-opacity='.55' stroke-width='1.2' stroke-linecap='round'%3E%3Cpath d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 17px center;
  background-size: 11px 7px;
  transition: background-color .3s ease, border-color .3s ease, color .3s ease;
}
.fselect:hover { border-color: rgba(51, 39, 28, .4); color: var(--espresso); }
/* the moss fill marks a facet that is actually narrowing the list, so an
   active filter is visible without opening anything */
.fselect--on {
  background-color: var(--moss); border-color: var(--moss); color: var(--cream);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%23F4E9D8' stroke-width='1.2' stroke-linecap='round'%3E%3Cpath d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
}
.fselect--on:hover { color: var(--cream); }
/* the open list is the platform's own, so drop the display styling there and
   let it be plainly readable */
.fselect option {
  text-transform: none; letter-spacing: normal; font-size: 14px;
  color: var(--espresso); background: var(--paper);
}
.fselect option:disabled { color: rgba(51, 39, 28, .35); }

.sched-views {
  display: inline-flex; align-self: flex-start;
  padding: 4px; border-radius: 999px; background: rgba(103, 102, 76, .1);
}
.vbtn {
  padding: 9px 20px; border: 0; border-radius: 999px; background: none;
  color: rgba(51, 39, 28, .6); font-family: var(--serif);
  font-size: 13px; letter-spacing: .14em; text-transform: uppercase;
  cursor: pointer; transition: background-color .3s ease, color .3s ease;
}
.vbtn:hover { color: var(--espresso); }
.vbtn--on { background: var(--moss); color: var(--cream); }

.sched-body { margin-top: 18px; }

/* --- Week view ------------------------------------------------------------ */

/* A real time grid: a sticky hour gutter plus seven day columns, with each
   class drawn at its own position and height. On a phone seven columns cannot
   fit, so the grid keeps a usable column width and scrolls sideways under a
   pinned gutter rather than shrinking into unreadable slivers. */
/* the week's date range is a much longer label than the month view's, so it
   sizes down to stay on one line at phone widths */
.wk .cal__head { gap: 14px; }
.wk .cal__month { font-size: 19px; white-space: nowrap; }

.wk__scroll { overflow-x: auto; overscroll-behavior-x: contain; }
.wk__grid {
  --wk-hour: 46px;
  display: grid;
  grid-template-columns: 46px repeat(7, minmax(96px, 1fr));
  min-width: 100%;
}

.wk__corner, .wk__gutter {
  position: sticky; left: 0; z-index: 2; background: var(--paper);
}
.wk__day {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 0 4px 10px;
  border-bottom: 1px solid rgba(51, 39, 28, .14);
}
.wk__dow {
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: rgba(51, 39, 28, .45);
}
.wk__date { font-family: var(--display); font-size: 19px; line-height: 1.1; }
.wk__day--today .wk__dow { color: var(--terracotta-ink); }
.wk__day--today .wk__date { color: var(--terracotta-ink); }

.wk__gutter { display: grid; grid-auto-rows: var(--wk-hour); }
.wk__hour {
  padding-right: 8px; text-align: right;
  font-size: 10px; letter-spacing: .08em;
  color: rgba(51, 39, 28, .38);
  /* sit the label on its own hour line rather than below it */
  transform: translateY(-5px);
}

.wk__col {
  position: relative;
  height: calc(var(--wk-rows) * var(--wk-hour));
  border-left: 1px solid rgba(51, 39, 28, .08);
  background-image: repeating-linear-gradient(
    to bottom, rgba(51, 39, 28, .09) 0 1px, transparent 1px var(--wk-hour));
}
/* moss, not terracotta — the classes themselves carry the terracotta tint, and
   two terracottas at different strengths just read as a smudge */
.wk__col--today { background-color: rgba(103, 102, 76, .06); }

/* the same washed terracotta the month grid uses for its class chips, so the
   two calendar views read as one family */
.wk__ev {
  position: absolute; overflow: hidden; box-sizing: border-box;
  display: flex; flex-direction: column; gap: 1px;
  min-height: 30px; padding: 5px 7px; margin-left: 1px;  /* 1px keeps neighbouring events apart */
  border-radius: 9px;
  background: rgba(158, 109, 78, .12); color: var(--espresso);
  text-decoration: none; line-height: 1.25;
  transition: background-color .3s ease;
}
.wk__ev:hover { background: rgba(158, 109, 78, .22); }
/* the secondary lines are 10px, so they stay at an alpha that still clears
   4.5:1 against the tinted block rather than fading to decoration */
.wk__ev-time { font-size: 10px; letter-spacing: .08em; color: rgba(51, 39, 28, .7); }
.wk__ev-name {
  font-size: 12px; letter-spacing: .02em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wk__ev-who {
  font-size: 10px; color: rgba(51, 39, 28, .7);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* A full class is still information — when it runs, and who teaches it, so you
   can pick another day. So it is marked unavailable with a dashed outline and a
   drained fill rather than by fading the text, which would put the message
   below readable contrast and carry it on colour alone. */
.wk__ev--full {
  background: rgba(103, 102, 76, .07);
  border: 1px dashed rgba(103, 102, 76, .5);
  padding: 4px 6px; color: rgba(51, 39, 28, .82);
}
.wk__ev--full:hover { background: rgba(103, 102, 76, .15); }
.wk__ev--full .wk__ev-time,
.wk__ev--full .wk__ev-who { color: rgba(51, 39, 28, .72); }

/* --- Calendar view -------------------------------------------------------- */

.cal__head {
  display: flex; align-items: center; justify-content: center; gap: 22px;
  margin: 6px 0 20px;
}
.cal__month {
  font-family: var(--display); font-size: 27px; margin: 0;
  min-width: 190px; text-align: center;
}
.cal__step {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 999px;
  border: 1px solid rgba(51, 39, 28, .2); background: none;
  color: var(--espresso); cursor: pointer; transition: border-color .3s ease;
}
.cal__step:hover { border-color: var(--espresso); }

.cal__grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 5px; }
.cal__wd {
  text-align: center; padding-bottom: 8px;
  font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
  color: rgba(51, 39, 28, .42);
}
.cal__pad { display: block; }

.cal__day {
  display: flex; flex-direction: column; align-items: flex-start; gap: 5px;
  min-height: 66px; padding: 8px; border: 0; border-radius: 14px;
  background: rgba(103, 102, 76, .05); font-family: var(--serif);
  text-align: left;
  transition: background-color .3s ease, box-shadow .3s ease;
}
/* the date is the button that opens the day; the classes beside it are their own links */
.cal__num {
  font-size: 15px; color: rgba(51, 39, 28, .55);
  border: 0; background: none; padding: 0; font-family: inherit; cursor: pointer;
}
.cal__num:disabled { cursor: default; }
.cal__day--has { background: #fff; }
.cal__day--has:hover { box-shadow: 0 6px 20px rgba(51, 39, 28, .08); }
.cal__day--has .cal__num { color: var(--espresso); }
.cal__day--on { background: var(--moss); }
.cal__day--on .cal__num { color: var(--cream); }

.cal__chips { display: flex; flex-wrap: wrap; gap: 3px; width: 100%; }
.cal__chip {
  /* phone: the label will not fit, so each class becomes a dot */
  width: 6px; height: 6px; border-radius: 999px; overflow: hidden;
  background: var(--terracotta); color: transparent; font-size: 0;
  text-decoration: none; cursor: pointer;
}
/* Hover has to set the text as well as the fill. It set only the fill, so at the width
   where a chip shows its label the dark espresso text landed on dark moss and vanished. */
.cal__chip:hover, .cal__chip:focus-visible { background: var(--moss); color: var(--cream); }
.cal__chip:focus-visible { outline: 2px solid var(--terracotta); outline-offset: 2px; }
.cal__day--on .cal__chip:hover, .cal__day--on .cal__chip:focus-visible { background: var(--cream); color: var(--espresso); }
.cal__day--on .cal__chip { background: var(--cream); }
.cal__more { font-size: 11px; color: rgba(51, 39, 28, .45); }
.cal__day--on .cal__more { color: rgba(244, 233, 216, .8); }

.cal__panel { margin-top: 26px; }

@media (min-width: 900px) {
  .sched-bar {
    flex-direction: row; align-items: center; justify-content: space-between;
    gap: 30px; margin-top: 40px;
  }
  .sched-filters { flex-direction: row; gap: 20px; align-items: flex-start; flex: 1 1 auto; }
  /* share the row evenly but never grow past a comfortable reading width */
  .fgroup { flex: 1 1 0; max-width: 270px; }
  .sched-body { margin-top: 26px; }

  .wk .cal__head { gap: 22px; }
  .wk .cal__month { font-size: 25px; }
  .wk__grid { --wk-hour: 58px; grid-template-columns: 56px repeat(7, minmax(0, 1fr)); }
  .wk__hour { font-size: 11px; padding-right: 11px; }
  .wk__date { font-size: 22px; }
  .wk__ev { padding: 7px 10px; border-radius: 11px; }
  .wk__ev-name { font-size: 13px; }

  .cal__grid { gap: 8px; }
  .cal__day { min-height: 116px; padding: 12px; border-radius: 16px; }
  .cal__num { font-size: 17px; }
  .cal__chips { flex-direction: column; gap: 4px; }
  .cal__chip {
    /* room for the real label at this width */
    width: 100%; height: auto; font-size: 12px; line-height: 1.35;
    padding: 3px 7px; border-radius: 6px; overflow: hidden;
    white-space: nowrap; text-overflow: ellipsis;
    background: rgba(158, 109, 78, .12); color: var(--espresso);
  }
  .cal__day--on .cal__chip { background: rgba(244, 233, 216, .18); color: var(--cream); }
}

/* --- Current section in the nav ------------------------------------------ */

.nav a.navlink { position: relative; padding-bottom: 3px; }
.nav a.navlink::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor;
  transform: scaleX(0); transform-origin: left;
  transition: transform .4s var(--ease), background-color .4s ease;
}
.nav a.navlink.is-current::after { transform: scaleX(1); background: var(--cream); }
.nav.is-solid a.navlink.is-current { color: var(--espresso); }
.nav.is-solid a.navlink.is-current::after { background: var(--terracotta); }

.menu__item.is-current { color: var(--tan); }
.menu__item.is-current span { color: var(--tan); }

@media (prefers-reduced-motion: reduce) {
  .nav a.navlink::after { transition: none; }
}

/* --- Shadow band (MyTeachers opening) ------------------------------------
   Modelled on innsaei: a single branch of leaf shadow hanging in the top-left
   corner, small and complete, drifting. Not a full-bleed background — scaled up
   to cover a wide band the leaves become huge and crop off at the edges.

   mix-blend-mode: multiply lets the clip's own near-white backdrop disappear so
   only the shadow lands on the page. The clip is levels-corrected on encode so
   that backdrop is neutral white; without that it would tint the whole area. */

#myteachers { padding-top: 0; }

.shadowband {
  position: relative;
  overflow: hidden;
  padding: 88px 0 20px;
}
.shadowband__inner { position: relative; }

.shadowband__video {
  position: absolute;
  top: 0;
  left: 0;
  width: clamp(475px, 75vw, 1075px);   /* 2.5x */
  height: auto;
  mix-blend-mode: multiply;
  opacity: .92;
  pointer-events: none;
  /* Multiply cannot fully erase a backdrop that is a hair under pure white, and
     the residue would show as a hard-edged rectangle. Fading the clip outward
     from the corner it hangs from dissolves that edge whatever is left. */
  -webkit-mask-image: radial-gradient(125% 125% at 0% 0%, #000 42%, transparent 82%);
          mask-image: radial-gradient(125% 125% at 0% 0%, #000 42%, transparent 82%);
}

.shadowband__copy {
  position: relative;
  text-align: center;
  max-width: 700px;
  margin: 0 auto;
}
.shadowband__copy .muted { color: rgba(51, 39, 28, .82); }

@media (min-width: 900px) {
  .shadowband { padding: 120px 0 24px; }
}

/* Under reduced motion site.js pauses the clip, which leaves its poster frame
   in place — same shadow, no drift. */

/* --- Teachers, four across ------------------------------------------------
   Eight teachers land as two clean rows of four rather than 3 + 3 + 2 with a
   gap where the last row stops. It waits for 1200px because below that the
   columns fall under about 250px, which is not enough to carry a portrait, a
   name, a discipline and three lines of lede. */
@media (min-width: 1200px) {
  .teachers { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 44px 28px; }
}

/* --- Section rail ---------------------------------------------------------
   A column of ticks down the left margin marking where you are. It only exists
   where there is genuinely spare margin to put it — below 1240px the page has
   none, and a floating widget over the content would be worse than no widget.

   Each tick is a short rule that lengthens and darkens when its section is the
   one being read; the label appears on hover or focus, so at rest the whole
   thing is seven quiet dashes rather than a menu competing with the nav. */
.rail { display: none; }

@media (min-width: 1240px) {
  .rail {
    display: flex; flex-direction: column; gap: 15px;
    position: fixed; left: 30px; top: 50%; transform: translateY(-50%);
    z-index: 50;
    /* out of the way until you have left the hero, where it would sit on the
       photograph and read as debris */
    opacity: 0; visibility: hidden;
    transition: opacity .5s var(--ease), visibility .5s var(--ease);
  }
  .rail.is-on { opacity: 1; visibility: visible; }

  .rail__item {
    position: relative; display: flex; align-items: center;
    text-decoration: none; padding: 3px 0;
  }
  .rail__tick {
    display: block; width: 16px; height: 1px; flex-shrink: 0;
    background: rgba(51, 39, 28, .3);
    transition: width .45s var(--ease), background-color .45s var(--ease);
  }
  /* Absolute, so a label that is merely invisible cannot still widen the link
     and swallow clicks meant for the copy beside it — in flow the rail's hit
     area reached 184px into an 80px gutter. */
  .rail__label {
    position: absolute; left: calc(100% + 12px); top: 50%;
    font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
    color: rgba(51, 39, 28, .5); white-space: nowrap; pointer-events: none;
    opacity: 0; transform: translateY(-50%) translateX(-4px);
    transition: opacity .4s var(--ease), transform .4s var(--ease);
  }
  .rail__item:hover .rail__tick,
  .rail__item:focus-visible .rail__tick { width: 26px; background: var(--moss); }
  .rail__item:hover .rail__label,
  .rail__item:focus-visible .rail__label { opacity: 1; transform: translateY(-50%); }

  /* the section being read keeps its tick long and dark */
  .rail__item.is-current .rail__tick { width: 32px; background: var(--moss); }
  .rail__item.is-current .rail__label { color: var(--moss); }

  /* The label only ever appears on hover at this width. The gutter is 80px and
     a name is about 90 — a permanently visible label would sit on the copy. It
     carries its own paper chip so it stays readable for the moment it does
     overlap something. */
  .rail__label {
    background: var(--paper); padding: 3px 9px; border-radius: 4px;
  }
}

@media (min-width: 1240px) {
  /* over the dark MyTea section the ink version would disappear */
  .rail.is-dark .rail__tick { background: rgba(244, 233, 216, .34); }
  .rail.is-dark .rail__label { color: rgba(244, 233, 216, .72); background: var(--espresso); }
  .rail.is-dark .rail__item:hover .rail__tick { background: var(--cream); }
  .rail.is-dark .rail__item.is-current .rail__tick { background: var(--cream); }
  .rail.is-dark .rail__item.is-current .rail__label { color: var(--cream); }
}

/* Past 1600 the page is centred with real margin either side, so the section
   being read can keep its name showing without landing on anything. */
@media (min-width: 1600px) {
  .rail__item.is-current .rail__label { opacity: 1; transform: translateY(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .rail, .rail__tick, .rail__label { transition: none; }
}

/* --- Legal and info pages -------------------------------------------------
   Imprint, privacy and studio guidelines. They share the site's type and
   colour but not its nav: the homepage nav is all in-page anchors, which do
   nothing here, so these carry a mark and a way back instead. */
.pagehead {
  border-bottom: 1px solid rgba(103, 102, 76, .2);
  padding: 26px 0;
}
.pagehead__inner { display: flex; align-items: center; justify-content: space-between; gap: 20px; }
.pagehead img { width: 46px; height: auto; }
.pagehead a.back {
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  color: rgba(51, 39, 28, .6);
}
.pagehead a.back:hover { color: var(--espresso); }

.doc { max-width: 720px; margin: 0 auto; padding: 60px 0 90px; }
.doc h1 { margin-bottom: 10px; }
.doc__meta {
  font-size: 14px; color: rgba(51, 39, 28, .5);
  padding-bottom: 34px; margin-bottom: 40px;
  border-bottom: 1px solid rgba(103, 102, 76, .2);
}
.doc h2 {
  font-size: clamp(21px, 2.6vw, 27px); letter-spacing: .1em;
  margin: 52px 0 18px;
}
.doc h3 {
  font-size: 15px; letter-spacing: .16em; margin: 32px 0 12px;
  color: var(--moss);
}
.doc p, .doc li { color: rgba(51, 39, 28, .82); }
.doc p + p { margin-top: 16px; }
.doc ul { margin: 16px 0 0; padding-left: 22px; }
.doc li + li { margin-top: 10px; }
.doc a { color: var(--terracotta-ink); text-decoration: underline; text-underline-offset: 3px; }
.doc dl { margin: 18px 0 0; }
.doc dt {
  font-size: 12px; letter-spacing: .16em; text-transform: uppercase;
  color: rgba(51, 39, 28, .5); margin-top: 18px;
}
.doc dd { margin: 5px 0 0; color: rgba(51, 39, 28, .82); }
/* an unfilled detail, marked so it cannot be mistaken for a real one */
.doc .ph { font-style: normal; }

@media (min-width: 900px) {
  .doc { padding: 84px 0 120px; }
  .doc h2 { margin-top: 66px; }
}

/* --- MyWorkshops: what a gathering is -------------------------------------
   The section is named after a key message but the calendar behind it is
   often empty, so it cannot lean on the workshop cards to carry it. These
   three rows say what a gathering actually is, which is true whether or not
   one is booked, and they give the left column enough weight to stand beside
   a 420px photograph.

   Hairline rules rather than a filled panel — the same vocabulary as the
   schedule rows, the pricing tiles and the newsletter. Ink rather than moss
   because moss on the sage ground all but disappears. */
.gatherings {
  list-style: none; margin: 30px 0 0; padding: 0;
  border-top: 1px solid rgba(244, 233, 216, .18);
}
.gatherings li {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 4px 18px; padding: 15px 2px;
  border-bottom: 1px solid rgba(244, 233, 216, .18);
}
.gatherings__name {
  font-family: var(--serif); font-size: 19px; color: var(--cream);
}
/* pushed right on a roomy row, dropped under the name when it will not fit,
   so a long note never crushes the name into two lines */
.gatherings__note {
  margin-left: auto; font-size: 14.5px; letter-spacing: .01em;
  color: rgba(244, 233, 216, .72);
}
.gatherings__why {
  margin-top: 20px; max-width: 54ch;
  color: rgba(244, 233, 216, .72);
}

@media (max-width: 619px) {
  .gatherings__note { margin-left: 0; flex-basis: 100%; }
}

/* The empty state, which on this section is the common case rather than the
   exception. A bordered invitation with somewhere to go, instead of a line of
   grey text apologising for an empty calendar. */
.nextup {
  border: 1px solid rgba(244, 233, 216, .22);
  border-radius: 3px;
  padding: 30px 32px;
  max-width: 560px;
  margin: 0 auto;
  text-align: center;
}
/* Tan is the accent on the espresso ground — the same choice .sec--dark makes
   for its eyebrows, and the only one of the warm tokens that clears AA here
   (4.9:1; terracotta manages 3.3:1). */
.nextup .label { color: var(--tan); margin-bottom: 12px; }
.nextup__body {
  color: rgba(244, 233, 216, .82); font-size: 16.5px; line-height: 1.62;
  margin-bottom: 22px;
}

/* The workshop cards and their loading skeleton were drawn for a light
   ground. Now that the section is espresso, both hairlines and the date
   accent have to invert with it. */
.sec--dark .card { border-top-color: rgba(244, 233, 216, .24); }
.sec--dark .card__date { color: var(--tan); }
.sec--dark .skel__bar,
.sec--dark .skel__pill,
.sec--dark .skel__thumb { background: rgba(244, 233, 216, .14); }

/* The "Quiet Luxury" USP, closing MyStudio. A hairline above it rather than a
   fourth fact: it is the reason behind the three facts, not another one of
   them, and it earns a moment of italic serif for that. */
.studio__close {
  margin-top: 30px; padding-top: 24px;
  border-top: 1px solid rgba(103, 102, 76, .22);
  font-family: var(--serif); font-style: italic;
  font-size: 18px; line-height: 1.66;
  color: rgba(51, 39, 28, .82);
  max-width: 54ch;
}

/* The "we are nature" key message, opening the hero. Italic serif so it reads
   as the headline's own voice rather than a second deck line, and sized
   between the h1 and the lead so the eye goes h1 → this → the practical line
   underneath. */
.hero__nature {
  margin-top: 14px;
  font-family: var(--serif); font-style: italic;
  font-size: clamp(17px, 1.6vw, 22px); line-height: 1.5;
  color: rgba(250, 246, 239, .92);
  text-shadow: 0 2px 24px rgba(27, 21, 14, .4);
  /* wide enough to hold the sentence on one line from about 720px up; it
     wraps below that, which is the only place it should */
  max-width: 640px;
  text-wrap: balance;
}

/* ==========================================================================
   The booking sheet — a bottom sheet on a phone, a dialog on a desk.
   Uses the same tokens and .btn as the rest of the page; nothing new to learn.
   ========================================================================== */

.sheet {
  border: 0; padding: 0; margin: auto 0 0; width: 100%; max-width: 100%;
  max-height: 92vh; overflow: auto; overscroll-behavior: contain;
  background: var(--paper); color: var(--ink);
  border-radius: 22px 22px 0 0; box-shadow: 0 -12px 40px rgba(27, 21, 14, .18);
}
.sheet::backdrop { background: rgba(27, 21, 14, .55); }
.sheet[open] { animation: sheet-up .28s ease-out; }
@keyframes sheet-up { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
.sheet__form { position: relative; padding: 26px 22px calc(22px + env(safe-area-inset-bottom)); }
.sheet__close {
  position: absolute; top: 12px; right: 12px; width: 40px; height: 40px;
  border: 0; border-radius: 50%; background: transparent; color: var(--espresso); font-size: 26px; line-height: 1; cursor: pointer;
}
.sheet__close:hover { background: rgba(51, 39, 28, .06); }
.sheet__title { font-family: var(--display); font-size: 30px; line-height: 1.1; margin: 8px 0 6px; padding-right: 44px; }
.sheet__meta { color: rgba(51, 39, 28, .74); font-size: 15px; margin: 0 0 18px; }
.sheet__line { font-size: 17px; line-height: 1.5; margin: 0 0 12px; }
.sheet__line--alert { color: var(--terracotta-ink); }
.sheet__offers { display: grid; gap: 10px; margin: 6px 0 18px; }
.offer {
  display: grid; grid-template-columns: auto 1fr auto; gap: 12px; align-items: center;
  padding: 14px 16px; border: 1px solid rgba(51, 39, 28, .18); border-radius: 14px; cursor: pointer;
}
.offer:has(input:checked) { border-color: var(--moss); background: rgba(103, 102, 76, .06); }
.offer--off { opacity: .55; cursor: default; }
.offer input { accent-color: var(--moss); width: 18px; height: 18px; margin: 0; }
.offer__body { display: grid; }
.offer__name { font-size: 16px; }
.offer__note { font-size: 13px; color: rgba(51, 39, 28, .62); }
.offer__price { font-family: var(--serif); font-size: 16px; white-space: nowrap; }
.sheet__fields { display: grid; gap: 14px; margin: 0 0 18px; }
.sheet__field { display: grid; gap: 6px; }
.sheet__label { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: rgba(51, 39, 28, .74); }
.sheet__field input {
  font: inherit; font-size: 18px; padding: 12px 14px; border: 1px solid rgba(51, 39, 28, .28); border-radius: 12px;
  background: #fff; color: var(--ink); min-height: 50px;
}
.sheet__field input:focus { outline: 2px solid var(--terracotta); outline-offset: 2px; }
.sheet__field input[name="code"] { letter-spacing: .3em; font-size: 24px; text-align: center; }
.sheet__check { display: flex; gap: 10px; align-items: flex-start; font-size: 15px; line-height: 1.45; }
.sheet__check input { accent-color: var(--moss); width: 18px; height: 18px; margin-top: 3px; flex: none; }
/* announced, not shown: every sentence it carries is already on screen as a line */
.srow__price--free { color: var(--moss); letter-spacing: .06em; }

.sheet__live { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.sheet__actions { position: sticky; bottom: 0; display: grid; gap: 12px; padding-top: 12px; background: var(--paper); }
.sheet__secondary {
  justify-self: center; background: none; border: 0; padding: 6px; cursor: pointer;
  font-family: var(--serif); font-size: 11px; letter-spacing: .24em; text-transform: uppercase; color: var(--espresso); text-decoration: underline;
}
.sheet.is-busy .btn { opacity: .6; pointer-events: none; }
.sheet.is-loading .sheet__form { min-height: 220px; }
.sheet.is-loading .sheet__form::after {
  content: ''; position: absolute; inset: 40px 22px auto; height: 14px; border-radius: 7px;
  background: rgba(51, 39, 28, .08); animation: sheet-pulse 1.2s ease-in-out infinite;
}
@keyframes sheet-pulse { 50% { opacity: .4; } }
[hidden] { display: none !important; }

@media (min-width: 900px) {
  .sheet { margin: auto; max-width: 480px; border-radius: 22px; box-shadow: 0 24px 60px rgba(27, 21, 14, .28); }
  .sheet__form { padding: 30px 30px 26px; }
}
@media (prefers-reduced-motion: reduce) {
  .sheet[open] { animation: none; }
  .sheet.is-loading .sheet__form::after { animation: none; }
}
