/* New Head Spa — direction A: Sandstone landing page, Clay everything else.
   Light warm ground, olive accent for the quiet marks, warm brown for anything
   you are meant to press. Nothing bounces. */

:root {
  --ground:        #E4D6C3;
  --ground-alt:    #D8C7AF;
  --surface:       #EFE5D6;
  --ground-invert: #33261C;

  --ink:   #33261C;   /* 10.3:1 on --ground */
  --ink-2: #5A4838;   /* secondary prose */
  --muted: #6B5745;   /* labels */
  --ink-on-invert: #F2ECE2;

  --accent: #566040;  /* olive — eyebrows, hairlines, quiet marks (4.68:1) */
  --cta:    #7E4E2A;  /* warm brown — anything you press (white on it 6.98:1,
                         4.89:1 when used as a link on the ground) */
  --cta-deep: #5F3A1E;
  --hair:  rgba(86, 96, 64, .34);
  --rule:  rgba(51, 38, 28, .14);

  --serif: Lora, Georgia, serif;
  --sans:  Karla, system-ui, -apple-system, "Segoe UI", sans-serif;

  --measure: 62ch;
  --pad: clamp(1.25rem, 5vw, 4.5rem);
  --gap: clamp(2.75rem, 7vw, 6rem);
  --ease: cubic-bezier(.22, .61, .36, 1);

  /* The home page's menu box, and — the same width minus that box's own side
     padding — a package row anywhere else. Derived rather than typed twice so
     the three packages are the SAME LENGTH on the home page and on the
     packages page; they were 787px and 928px before 2026-08-12, which is what
     made the two pages look unrelated. Tune --menu-w only; --pkg-row-w
     follows. Both are caps: below them the box and the table simply fill, so
     a phone is unaffected.
     One residue that CSS cannot remove: the menu box scrolls, so where the
     browser draws a classic scrollbar (Windows, Linux) it eats ~15px and the
     home page's row lands that much narrower than the packages page's. On
     macOS overlay scrollbars they match within 2px. Scrollbar width is not
     knowable in CSS, so this is stated rather than fixed — at ~920px wide it
     is under 2% and nobody will see it across two separate pages. */
  --menu-w: 66rem;
  --pkg-row-w: calc(var(--menu-w) - 3.8rem - 2px);  /* .menu-scroll's 1.9rem sides + the box's 1px borders */
}

/* Chinese: Latin family FIRST so digits and Latin words keep the brand face;
   the browser falls through to the CJK family only for Han characters. */
[data-cjk="tc"] {
  --serif: Lora, "Noto Serif TC", "Songti TC", "LiSong Pro", PMingLiU, serif;
  --sans:  Karla, "Noto Sans TC", "PingFang TC", "Heiti TC", "Microsoft JhengHei", sans-serif;
  --measure: 34em;
}
[data-cjk="sc"] {
  --serif: Lora, "Noto Serif SC", "Songti SC", STSong, SimSun, serif;
  --sans:  Karla, "Noto Sans SC", "PingFang SC", "Heiti SC", "Microsoft YaHei", sans-serif;
  --measure: 34em;
}
/* Han characters have no italic or bold tradition — synthesising either
   shears or blobs the strokes. Load a real weight or do not use one. */
[data-cjk] { font-synthesis: none; }
[data-cjk] em, [data-cjk] i { font-style: normal; }
[data-cjk] body, [data-cjk] p, [data-cjk] li { line-height: 1.75; }
[data-cjk] h1 { font-size: clamp(1.85rem, 1.3rem + 2.9vw, 3.35rem); line-height: 1.24; }
[data-cjk] h2 { font-size: clamp(1.4rem, 1.15rem + 1vw, 1.9rem); line-height: 1.32; }
[data-cjk] h3 { font-size: clamp(1.05rem, 1rem + .4vw, 1.25rem); }
[data-cjk] h1, [data-cjk] h2, [data-cjk] h3 { line-break: strict; overflow-wrap: anywhere; }
[data-cjk] .eyebrow, [data-cjk] .card-eyebrow { letter-spacing: .12em; }

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: clamp(1rem, .96rem + .2vw, 1.0625rem);
  font-weight: 400;
  line-height: 1.65;
  overflow-x: hidden;
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--cta); outline-offset: 3px; }

h1, h2, h3 { font-family: var(--serif); font-weight: 400; line-height: 1.16; margin: 0; }
h1 { font-size: clamp(2rem, 1.35rem + 3.1vw, 3.6rem); }
h2 { font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.1rem); }
h3 { font-size: clamp(1.15rem, 1.05rem + .5vw, 1.4rem); }
p  { margin: 0 0 1.1em; max-width: var(--measure); }

.eyebrow {
  font-family: var(--sans); font-size: .74rem; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--accent); margin: 0 0 1.1rem;
}
.section-title { margin-bottom: 1.6rem; }
.section-title::after {
  content: ""; display: block; width: 3.25rem; height: 1px;
  background: var(--accent); opacity: .7; margin-top: .9rem;
}
.lede { font-size: 1.09em; color: var(--ink-2); }
.note { color: var(--ink-2); font-size: .94em; }

.skip { position: absolute; left: -9999px; min-height: 44px; }
.skip:focus { left: 1rem; top: 1rem; z-index: 99; background: var(--cta); color: #fff; padding: .85rem 1.2rem; min-height: 44px; }

/* ── header ─────────────────────────────────────────────────────────────── */
.site {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding: .9rem var(--pad);
  border-bottom: 1px solid var(--rule);
  background: var(--surface);
  position: sticky; top: 0; z-index: 40;
}
.brand { display: flex; align-items: center; gap: .6rem; text-decoration: none; min-height: 44px; }
.brand-mark { width: 1px; height: 1.15rem; flex: none; background: var(--accent); opacity: .8; }
.brand-name {
  font-family: var(--serif); font-size: 1rem;
  letter-spacing: .19em; text-transform: uppercase; white-space: nowrap;
}
.nav { display: flex; align-items: center; gap: clamp(.9rem, 2.2vw, 1.8rem); }
.nav-links { display: flex; align-items: center; gap: clamp(.9rem, 2vw, 1.7rem); }
.nav-links > a, .mm-top {
  text-decoration: none; font-size: .93rem; color: var(--ink-2);
  padding: .55rem 0; min-height: 44px; display: inline-flex; align-items: center;
  transition: color .35s var(--ease);
}
.nav-links > a:hover, .mm-top:hover,
.nav-links > a[aria-current="page"] { color: var(--ink); }
.burger { display: none; }

/* ── the Treatments mega-menu ───────────────────────────────────────────── */
.has-mm { position: relative; }
.mm-top { gap: .35rem; }
.mm-top i { font-style: normal; font-size: .68em; transition: transform .35s var(--ease); }
.has-mm:hover .mm-top i, .has-mm:focus-within .mm-top i { transform: rotate(180deg); }
.mm {
  position: absolute; top: 100%; left: 50%; z-index: 45;
  display: grid; grid-template-columns: repeat(2, minmax(11.5rem, 1fr)); gap: .1rem;
  min-width: 26rem; padding: .7rem;
  background: var(--surface); border: 1px solid var(--rule);
  box-shadow: 0 22px 60px rgba(51, 38, 28, .22);
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translate(-50%, 8px);
  transition: opacity .35s var(--ease), transform .35s var(--ease), visibility .35s;
}
.has-mm:hover .mm, .has-mm:focus-within .mm {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translate(-50%, 0);
}
.mm-sub {
  display: flex; align-items: center; gap: .75rem; padding: .5rem;
  text-decoration: none; color: var(--ink); min-height: 44px;
  transition: background .3s var(--ease);
}
.mm-sub:hover { background: var(--ground); }
.mm-sub img { width: 3rem; height: 3rem; object-fit: cover; flex: none; }
.mm-sub b { font-family: var(--serif); font-weight: 400; font-size: .98rem; }
.mm-all {
  grid-column: 1 / -1; padding: .8rem .5rem .35rem; min-height: 44px;
  color: var(--cta); text-decoration: none; font-size: .86rem;
  border-top: 1px solid var(--rule); margin-top: .35rem;
}

/* ── language dropdown ──────────────────────────────────────────────────── */
.langs { position: relative; }
.lang-top {
  display: inline-flex; align-items: center; gap: .4rem; min-height: 44px;
  padding: .45rem .75rem; background: none; cursor: pointer;
  border: 1px solid var(--rule); color: var(--ink-2);
  font: inherit; font-size: .85rem;
  transition: border-color .35s var(--ease), color .35s var(--ease);
}
.lang-top:hover { border-color: var(--hair); color: var(--ink); }
.lang-top i { font-style: normal; font-size: .68em; transition: transform .35s var(--ease); }
.lang-top[aria-expanded="true"] i { transform: rotate(180deg); }
.lang-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 46;
  min-width: 10.5rem; padding: .35rem;
  background: var(--surface); border: 1px solid var(--rule);
  box-shadow: 0 18px 44px rgba(51, 38, 28, .2);
  display: grid; opacity: 0; visibility: hidden; transform: translateY(6px);
  transition: opacity .3s var(--ease), transform .3s var(--ease), visibility .3s;
}
.lang-menu.open { opacity: 1; visibility: visible; transform: none; }
.lang-menu a {
  padding: .6rem .75rem; min-height: 44px; display: flex; align-items: center;
  text-decoration: none; color: var(--ink-2); font-size: .9rem;
  transition: background .25s var(--ease), color .25s var(--ease);
}
.lang-menu a:hover { background: var(--ground); color: var(--ink); }
.lang-menu a[aria-current="true"] { color: var(--cta); }

/* ── buttons ────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: .78rem 1.5rem;
  font-family: var(--sans); font-size: .92rem; font-weight: 500;
  letter-spacing: .02em; text-decoration: none; white-space: nowrap;
  border-radius: 0; transition: all .4s var(--ease);
}
.btn-book { color: var(--cta); border: 1px solid var(--hair); background: transparent; font-weight: 600; }
.btn-book:hover { border-color: var(--cta); background: rgba(126, 78, 42, .07); }
.btn-metal {
  position: relative; overflow: hidden;
  background: var(--cta); color: #fff; border: 1px solid var(--cta-deep);
  font-weight: 600; letter-spacing: .03em;
  box-shadow: 0 6px 18px rgba(95, 58, 30, .26), inset 0 1px 0 rgba(255, 255, 255, .16);
}
.btn-metal:hover { background: #8C5730; box-shadow: 0 10px 26px rgba(95, 58, 30, .32), inset 0 1px 0 rgba(255,255,255,.2); }
/* the header booking button — solid, so it is never mistaken for a nav link */
.btn-nav { padding: .72rem 1.3rem; font-size: .89rem; }
/* the hero ask carries the page, so it is the biggest thing you can press */
.hero-actions .btn-metal { padding: 1.05rem 2.1rem; font-size: 1rem; }
.btn-metal::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(105deg, transparent 38%, rgba(255,255,255,.3) 50%, transparent 62%);
  transform: translateX(-120%); transition: transform .85s var(--ease);
}
.btn-metal:hover::after { transform: translateX(120%); }

/* ── hero: Sandstone's landing page, kept ───────────────────────────────── */
/* `overflow: hidden` is load-bearing, not tidiness. The `settle` animation at
   the foot of this file starts the hero photograph at `scale(1.04)`, and this
   is the ONE image on the site that runs full-bleed — every other hero sits
   inside `.page-hero`'s padding, where 4% has room to grow. Scaling about the
   centre pushed it 25px past the viewport at 1280 (1265 × 1.04, centred) and
   7px at 375, so for the 1.8s the animation runs the whole page could be
   panned sideways. `body { overflow-x: hidden }` did NOT stop it: with
   `overflow-y` left visible the pair computes to hidden/auto, the viewport
   keeps its own scroll, and `documentElement.scrollLeft` still moved 25px.
   Clipping at the hero fixes it at the source and costs nothing — the zoom-out
   reads exactly the same, it just stops bleeding past the page.
   ⚠️ Safe only because the sticky element (`.site`, the header) is a SIBLING
   of `<main>`, not a descendant of the hero — an `overflow: hidden` ancestor
   would silently kill `position: sticky`. Check that again if the header moves.
   Measured, not guessed: the pane freezes CSS animations at their `from` state
   when the tab is hidden (see the handoff), which is why this looked permanent
   rather than transient. Finishing the animations by hand took overflow to 0. */
.hero { position: relative; display: grid; overflow: hidden; }
.hero-img {
  grid-area: 1/1; width: 100%; height: clamp(30rem, 84vh, 48rem);
  object-fit: cover; object-position: 50% 55%;
}
.hero-copy {
  grid-area: 1/1; align-self: end; padding: var(--pad);
  position: relative; z-index: 1;   /* .hero-img is its own paint layer; without
                                       this the photograph covers the words.
                                       Found by measuring, not by reading. */
  padding-bottom: clamp(2.5rem, 6vw, 4.5rem);
  /* The last stop MUST stay `transparent 100%`. Giving it any opacity puts a
     visible horizontal band across the photograph, because the scrim then jumps
     from nothing to something at the copy block's own top edge. Tried on
     2026-08-08, and it looked like a bug.
     The middle stops are a different matter, and they were raised (.62 -> .78,
     .15 -> .40) because the h1 measured 2.14:1 where "warm" crosses the dark
     bokeh at the top right — the largest text on the site, under the 3:1 floor.
     Raising the middle fixes that without touching the top edge. */
  background: linear-gradient(to top, var(--ground) 2%, rgba(228,214,195,.95) 30%, rgba(228,214,195,.78) 62%, rgba(228,214,195,.40) 88%, transparent 100%);
}
/* THE HERO HAS NO EYEBROW, and that is a decision, not an omission.
   A 12px letterspaced "OTTAWA" sat at the very top of the copy block, where the
   scrim is thinnest and the background is therefore the PHOTOGRAPH rather than
   any colour we control. Every candidate was measured off the rendered pixels,
   with the hero text hidden so the readings were of real background:
     olive 1.4:1 · --ink-2 1.3:1 · --ink 3.6:1 · cream 3.5:1
   None reach the 4.5:1 an 11.8px label needs, because this photograph lands in
   the mid-tones under that label, where light text and dark text both lose.
   Strengthening the scrim enough to rescue it washes out the photograph;
   putting a solid chip behind it adds an element nobody asked for.
   It has been illegible on the live demo since launch, at 1.3:1, and the
   locator line directly beneath it reads "New Head Spa · 2702 Alta Vista
   Drive, Ottawa" — so removing it loses no word and no search term.
   ⚠️ If it comes back, it needs its own background, not a colour. */
.hero h1 { max-width: 17ch; }
[data-cjk] .hero h1 { max-width: 14em; }
.locator { color: var(--ink-2); font-size: .95rem; margin: 1.1rem 0 0; }
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem; margin-top: 1.9rem; }
.proof {
  font-size: .88rem; color: var(--ink-2); text-decoration: none;
  border-bottom: 1px solid var(--hair);
  display: inline-flex; align-items: center; min-height: 44px; padding-bottom: .18rem;
  transition: color .35s var(--ease);
}
.proof:hover { color: var(--cta); }

/* ── bands ──────────────────────────────────────────────────────────────── */
.band { padding: var(--gap) var(--pad); }
.band + .band { border-top: 1px solid var(--rule); }
/* The welcome paragraph, on its own: one block, no picture, running the full
   width of the band. Two things are kept from the earlier passes because they
   were asked for and they hold up: the italic, and the lighter ground.
   --ground-alt sat darker than the scrim the hero fades into, so sand → mud →
   sand read as a mistake; --surface lifts off it instead and matches the header.
   The 120ch cap is what keeps this to three lines on a laptop — the paragraph
   is 418 characters and needs about 1130px of line before it folds to three.
   Measured, not guessed. */
.intro { background: var(--surface); padding-block: clamp(2.5rem, 5.5vw, 4.25rem); }
.intro .lede {
  font-size: clamp(1.06rem, 1rem + .3vw, 1.2rem); max-width: 120ch;
  margin-bottom: 0; font-style: italic;
}
/* Han characters have no italic tradition — synthesising one shears the
   strokes. Chinese keeps the upright, the same rule the rest of the sheet uses. */
[data-cjk] .intro .lede { max-width: 52em; font-style: normal; }

/* ── Clay's staggered mosaic of treatments ──────────────────────────────── */
.cards { display: grid; gap: clamp(1rem, 2.4vw, 2rem); }
@media (min-width: 52rem) {
  .cards { grid-template-columns: repeat(2, 1fr); }
  .card:nth-child(even) { margin-top: 3.2rem; }
}
.card { display: block; text-decoration: none; color: inherit; }
.card-shot { display: block; overflow: hidden; }
.card-shot img { width: 100%; display: block; object-fit: cover; transition: transform .9s var(--ease); }
.card:nth-child(3n+1) .card-shot img { height: 20rem; }
.card:nth-child(3n+2) .card-shot img { height: 15rem; }
.card:nth-child(3n)   .card-shot img { height: 24rem; }
.card:hover .card-shot img { transform: scale(1.045); }

/* ── the sliding head card ───────────────────────────────────────────────────
   Several photographs on one card, moving right one frame at a time. The
   height moves onto .card-shot here because the frames have to share it; the
   images then fill it, so the staggered card heights above still hold.
   Without JavaScript this is simply the first frame: the track never moves and
   the others stay outside the clip. */
.card:nth-child(3n+1) .card-shot.rolling { height: 20rem; }
.card:nth-child(3n+2) .card-shot.rolling { height: 15rem; }
.card:nth-child(3n)   .card-shot.rolling { height: 24rem; }
.shot-roll { display: flex; height: 100%; will-change: transform; }
.shot-roll img { flex: 0 0 100%; width: 100%; height: 100%; }
.card-shot.rolling.animating .shot-roll { transition: transform 1.15s var(--ease); }
.card-words { background: var(--surface); padding: 1.1rem 1.35rem; margin: -2.6rem 1.4rem 0; position: relative; z-index: 1; }
.card-eyebrow { font-size: .72rem; letter-spacing: .2em; color: var(--accent); display: block; margin-bottom: .4rem; }
.card h3 { margin-bottom: .25rem; }
.card-desc { color: var(--ink-2); font-size: .95rem; padding: .9rem 1.4rem 0; margin: 0; max-width: none; }
.card-price { color: var(--ink); font-size: .93rem; margin: .4rem 0 0; }
/* Home page only: the cards carry the duration and no price, so the line is a
   quiet caption rather than a figure. It matches the italic intro above it.
   The treatments index keeps its prices upright — a price is not an aside. */
.cards-quiet .card-price { font-style: italic; color: var(--ink-2); }
[data-cjk] .cards-quiet .card-price { font-style: normal; }
.card-cta { font-size: .85rem; color: var(--cta); }
.card-cta::after { content: " →"; }

.saje-grid { display: grid; gap: clamp(1.6rem, 4vw, 3.5rem); align-items: center; }
@media (min-width: 54rem) { .saje-grid { grid-template-columns: minmax(0, 22rem) 1fr; } }
.saje-grid img { border: 1px solid var(--rule); }

.visit-strip { background: var(--ground-alt); }
.visit-strip address, .visit-page address { font-style: normal; color: var(--ink-2); margin-bottom: 1.8rem; }
.visit-strip address span { display: block; }
.visit-page address p { margin-bottom: .55em; }

/* ── treatment pages ────────────────────────────────────────────────────── */
.page-hero { display: grid; gap: clamp(1.5rem, 4vw, 3rem); padding: var(--gap) var(--pad); align-items: center; }
@media (min-width: 58rem) { .page-hero:not(.slim) { grid-template-columns: 1fr minmax(0, 26rem); } }
.page-hero.slim { padding-bottom: clamp(1.5rem, 3vw, 2.5rem); }
.page-hero.slim + .band { padding-top: clamp(1.75rem, 3.5vw, 3rem); }
.page-hero img { border: 1px solid var(--rule); max-height: 30rem; object-fit: cover; width: 100%; }
.page-hero h1 { margin-bottom: 1.3rem; }

.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.7rem; max-width: 46rem; }
.steps li { display: grid; grid-template-columns: 2.6rem 1fr; gap: 1rem; align-items: start; }
.step-n { font-family: var(--serif); color: var(--accent); font-size: .95rem; padding-top: .22rem; }
.steps h3 { font-size: 1.06rem; margin-bottom: .35rem; }
.steps p { color: var(--ink-2); margin: 0; }

.price-band { background: var(--ground-alt); }
.prices { border-collapse: collapse; width: 100%; max-width: 40rem; }
.prices th, .prices td { text-align: left; padding: 1.05rem .6rem; border-bottom: 1px solid var(--rule); font-weight: 400; }
.prices tr:first-child th, .prices tr:first-child td { border-top: 1px solid var(--rule); }
.prices th { color: var(--ink-2); }
.prices .price { font-family: var(--serif); font-size: 1.22rem; color: var(--ink); white-space: nowrap; }
.prices .row-cta { text-align: right; }
.prices .row-cta a { color: var(--cta); text-decoration: none; font-size: .85rem; display: inline-block; padding: .55rem 0; min-height: 44px; line-height: 2; }
.prices .row-cta a:hover { text-decoration: underline; text-underline-offset: 3px; }
.packages-table th { font-family: var(--serif); color: var(--accent); font-size: 1.1rem; }
/* Wider than the 40rem the treatment tables use: since 2026-08-12 each package
   row carries its combination line underneath, and at 40rem that squeezed the
   duration onto two lines while half the page sat empty beside it.
   The width is DERIVED from the home page's menu box (see --pkg-row-w) so a
   package is the same length wherever it is shown — owner, 2026-08-12: "make
   the packages page match". Applies on the packages page and on the packages
   band of the treatments index, both of which use this class. */
.packages-table { max-width: var(--pkg-row-w); }

/* ── who it suits ───────────────────────────────────────────────────────────
   A list of situations, not of features. The olive dash is the same quiet mark
   the eyebrows use; it sits on the first line's optical centre rather than its
   top, so it reads as punctuation instead of a bullet. */
.forwho { list-style: none; margin: 0; padding: 0; display: grid; gap: .85rem; max-width: 44rem; }
.forwho li { position: relative; padding-left: 1.6rem; color: var(--ink-2); }
.forwho li::before {
  content: ""; position: absolute; left: 0; top: .72em;
  width: .7rem; height: 1px; background: var(--accent);
}
[data-cjk] .forwho li::before { top: .85em; }

/* ── common questions ───────────────────────────────────────────────────────
   A description list, so a screen reader announces each answer as belonging to
   its question. The same pairs are emitted as FAQPage JSON-LD from the one
   source, which is why the two can never disagree. */
.faq-band { background: var(--surface); }
.faq { margin: 0; max-width: 46rem; }
.faq dt {
  font-family: var(--serif); font-size: 1.1rem; color: var(--ink);
  margin-top: 1.9rem; padding-top: 1.9rem; border-top: 1px solid var(--rule);
}
.faq dt:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }
.faq dd { margin: .55rem 0 0; color: var(--ink-2); }
.faq-band .note { margin-top: 2.4rem; }

.siblings { padding: 0 var(--pad) var(--gap); }
.siblings a { color: var(--ink-2); text-decoration: none; font-size: .92rem; display: inline-block; min-height: 44px; line-height: 2.6; }
.siblings a:hover { color: var(--cta); }

.prose { max-width: 46rem; }
.prose p { color: var(--ink-2); }
.packages-link { margin-top: 2rem; }
.packages-link a { color: var(--cta); text-decoration: none; display: inline-block; min-height: 44px; line-height: 2.6; }

/* ── the home menu: every price in one scrollable window ─────────────────
   The owner asked for "a rectangular area window where it's scrollable"
   (2026-08-12). The wrapper owns the border and a bottom fade that signals
   there is more below the fold of the box; the inner element scrolls. The
   fade sits on the WRAPPER so it does not scroll away with the content.
   tabindex + role="region" in the markup keep it keyboard-scrollable. */
.menu-lede { max-width: var(--measure); color: var(--ink-2); }
/* The width is --menu-w, and it took four passes to land, so the history lives
   here rather than only in git: 46rem (too narrow — most of a laptop sat empty
   beside a three-column table) → the full band, 1137px (too wide — a gulf
   opened between a package's name and its duration) → 53rem, 25% off the band
   → 62rem, halfway back → 66rem, where the owner settled it on 2026-08-12.
   66rem is 1056px at a 1280 window, still 81px short of filling the band.
   A rem cap rather than a percentage on purpose: 75% of a phone's band would
   be a 250px-wide price table, so below this width the box simply fills. The
   band's own --pad keeps it off the page edge either way. */
.menu-wrap { position: relative; margin-top: 1.9rem; border: 1px solid var(--rule); background: var(--ground-alt); max-width: var(--menu-w); }
.menu-wrap::after {
  content: ''; position: absolute; left: 1px; right: 1px; bottom: 1px; height: 3.2rem;
  background: linear-gradient(to bottom, transparent, var(--ground-alt)); pointer-events: none;
}
/* Tall enough that the next group's heading always peeks above the fold — that
   peek, not the fade alone, is what tells a reader the box scrolls. Raised from
   27rem when the package rows gained their combination line and grew ~28px
   each, which had pushed Head Massage out of sight entirely. */
.menu-scroll { max-height: 33rem; overflow-y: auto; padding: 1.7rem 1.9rem 3.2rem; }
.menu-scroll:focus-visible { outline: 2px solid var(--cta); outline-offset: -2px; }
.menu-group + .menu-group { margin-top: 2.1rem; padding-top: 1.9rem; border-top: 1px solid var(--rule); }
.menu-group h3 { font-family: var(--serif); font-weight: 500; font-size: 1.16rem; margin: 0 0 .55rem; }
.menu-group h3 a { color: var(--ink); text-decoration: none; }
.menu-group h3 a:hover { color: var(--cta); }
.menu-note { color: var(--ink-2); font-size: .92rem; margin: 0 0 .9rem; max-width: none; }
.menu-prices { max-width: none; }

/* The combination under each package row. It repeats on all three rows on
   purpose — that is how the client's own booking page reads, and it means a
   reader looking only at package C still learns what is in it. Italic because
   the owner asked for it, and it happens to be the right weight: it is a
   qualifier of the row above, not a second heading. */
.pkg-combo {
  display: block; font-family: var(--sans); font-weight: 400; font-style: italic;
  font-size: .84rem; line-height: 1.45; color: var(--ink-2);
  margin-top: .3rem; max-width: 34rem; white-space: normal;
}
/* The combination line makes its cell two lines tall, so the duration and the
   price must ride at the top with the package name rather than floating to the
   middle of the taller row. Scoped with :has so the one-line treatment tables
   keep their centred alignment; where :has is unsupported the rows simply stay
   centred, which is the old behaviour and not a break. */
.prices tr:has(.pkg-combo) th, .prices tr:has(.pkg-combo) td { vertical-align: top; }
.menu-actions { margin-top: 1.1rem; display: flex; flex-wrap: wrap; gap: 0 1.7rem; }
.menu-actions a { color: var(--cta); text-decoration: none; font-size: .95rem; display: inline-block; min-height: 44px; line-height: 2.6; }
.menu-actions a:hover { text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 40rem) { .menu-scroll { max-height: 23rem; padding: 1.2rem 1.15rem 2.8rem; } }

/* ── the booking form ───────────────────────────────────────────────────
   Booking is calling or email (owner, 2026-08-12). The phone button sits
   above the form; the form is the email path. The .hp field is the bot
   honeypot: parked off-screen, never display:none, so simple bots still
   fill it and people never meet it. */
.book-alt { display: inline-block; margin-left: 1.5rem; color: var(--cta); text-decoration: none; font-size: .95rem; min-height: 44px; line-height: 2.6; }
.book-alt:hover { text-decoration: underline; text-underline-offset: 3px; }
.book-form { margin-top: 2.3rem; max-width: 30rem; }
.book-form .field { margin: 0 0 1.2rem; max-width: none; }
.book-form label { display: block; font-size: .9rem; color: var(--ink-2); letter-spacing: .02em; margin-bottom: .4rem; }
.book-form .opt { color: var(--muted); }
.book-form input:not([type="hidden"]), .book-form select, .book-form textarea {
  width: 100%; padding: .72rem .85rem; font: inherit; font-size: 1rem; color: var(--ink);
  background: var(--ground-alt); border: 1px solid var(--rule); border-radius: 0;
}
.book-form input:focus-visible, .book-form select:focus-visible, .book-form textarea:focus-visible {
  outline: 2px solid var(--cta); outline-offset: -1px;
}
.book-form textarea { resize: vertical; }
.book-form button { margin-top: .3rem; }
.book-form button:disabled { opacity: .55; }
.form-status { min-height: 1.5em; color: var(--ink); max-width: none; }
.hp { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }

/* ── the map ──────────────────────────────────────────────────────────────
   The height is written as the old ratio with its second number multiplied by
   0.65, so the "35% shorter" the owner asked for on 2026-08-08 stays legible
   in the source: 16/9 → 16/5.85 desktop, 4/3 → 4/1.95 on a phone. Width is
   unchanged, so shortening the height is all this does. Keep the two numbers
   derived that way if it is ever re-tuned. */
.map-frame {
  margin-top: 2rem; border: 1px solid var(--rule); background: var(--ground-alt);
  position: relative; aspect-ratio: 16 / 5.85; overflow: hidden;
}
@media (max-width: 40rem) { .map-frame { aspect-ratio: 4 / 1.95; } }
.map-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; filter: saturate(.84) contrast(.97); }
.map-actions { margin-top: 1rem; display: flex; flex-wrap: wrap; gap: 1rem 1.5rem; align-items: center; }
.map-actions a { color: var(--cta); text-decoration: none; font-size: .9rem; display: inline-block; min-height: 44px; line-height: 2.6; }
.map-actions a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ── mobile call bar ────────────────────────────────────────────────────
   The spa books by telephone, so on a phone the number is a permanent,
   thumb-height target. Desktop never sees it. Body gains matching padding so
   the bar can never sit on top of the last line of a page. */
.callbar { display: none; }

/* ── footer ─────────────────────────────────────────────────────────────── */
.site-foot {
  padding: var(--gap) var(--pad) clamp(2rem, 4vw, 3rem);
  border-top: 1px solid var(--rule); background: var(--surface);
}
.foot-line { color: var(--muted); font-size: .86rem; max-width: none; }
.foot-links { font-size: .86rem; color: var(--muted); margin: 0; }
.foot-links a { color: var(--ink-2); text-decoration: none; padding: .7rem 0; display: inline-block; min-height: 44px; line-height: 1.8; }
.foot-links a:hover { color: var(--cta); }
.foot-links span { margin: 0 .5rem; }

/* ── mobile ─────────────────────────────────────────────────────────────── */
@media (max-width: 62rem) {
  .site { padding: .7rem 1.1rem; }
  .burger {
    display: flex; flex-direction: column; justify-content: center; gap: 5px;
    width: 44px; height: 44px; padding: 0; margin-right: -.4rem;
    background: none; border: 0; cursor: pointer;
  }
  .burger span { display: block; height: 1px; width: 21px; background: var(--ink); transition: transform .35s var(--ease); }
  .burger[aria-expanded="true"] span:first-child { transform: translateY(3px) rotate(45deg); }
  .burger[aria-expanded="true"] span:last-child { transform: translateY(-3px) rotate(-45deg); }

  .nav {
    position: fixed; inset: 0; z-index: 45;
    flex-direction: column; align-items: flex-start; justify-content: flex-start;
    gap: 1.3rem; padding: 5.5rem 1.6rem 2rem;
    background: var(--ground);
    transform: translateY(-100%); transition: transform .45s var(--ease);
    overflow-y: auto;
  }
  .nav.open { transform: none; }
  .nav-links { flex-direction: column; align-items: flex-start; gap: .3rem; width: 100%; }
  .nav-links > a, .mm-top { font-family: var(--serif); font-size: 1.5rem; color: var(--ink); padding: .45rem 0; }
  /* a hover menu is a trap on a touchscreen — list the treatments inline instead */
  .has-mm { width: 100%; }
  .mm {
    position: static; transform: none; opacity: 1; visibility: visible; pointer-events: auto;
    grid-template-columns: 1fr; min-width: 0; box-shadow: none; border: 0;
    background: none; padding: .2rem 0 .6rem;
  }
  .mm-sub { padding: .45rem 0; }
  .mm-sub img { width: 2.4rem; height: 2.4rem; }
  .mm-sub b { font-size: 1rem; }
  .mm-top i { display: none; }
  .langs { width: 100%; border-top: 1px solid var(--rule); padding-top: 1rem; }
  .lang-top { width: 100%; justify-content: space-between; }
  .lang-menu { position: static; opacity: 1; visibility: visible; transform: none; box-shadow: none; border: 0; background: none; padding: .2rem 0 0; display: none; }
  .lang-menu.open { display: grid; }
  .btn-book, .btn-nav { width: 100%; }
  .nav .btn-nav { margin-top: .4rem; }
  .hero-img { height: clamp(26rem, 74vh, 34rem); }
  .hero-actions .btn-metal { width: 100%; padding: 1rem 1.4rem; }
  .hero-actions { gap: .9rem; }

  /* the call bar */
  body { padding-bottom: 4.25rem; }
  .callbar {
    display: flex; align-items: center; justify-content: center; gap: .55rem;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 42;
    min-height: 3.85rem; padding: .7rem 1rem;
    padding-bottom: calc(.7rem + env(safe-area-inset-bottom, 0px));
    background: var(--cta); color: #fff; text-decoration: none;
    box-shadow: 0 -8px 26px rgba(51, 38, 28, .22);
    transform: translateY(100%);
    transition: transform .5s var(--ease);
  }
  .callbar.show { transform: none; }
  .callbar-label { font-weight: 600; font-size: .95rem; letter-spacing: .02em; }
  .callbar-num { font-size: .95rem; opacity: .92; }
  .callbar-num::before { content: "· "; opacity: .6; }
  /* the open menu covers the screen; the bar must not float over it */
  body:has(.nav.open) .callbar { display: none; }
}

/* ── motion ─────────────────────────────────────────────────────────────
   The hidden state is applied by site.js, never here, so a blocked or failed
   script leaves the page fully visible. Opacity and translate only. */
.reveal-init { opacity: 0; transform: translateY(16px); will-change: opacity, transform; }
.reveal-in {
  opacity: 1; transform: none; will-change: auto;
  transition: opacity .95s var(--ease) var(--reveal-delay, 0ms),
              transform .95s var(--ease) var(--reveal-delay, 0ms);
}
tr.reveal-init { transform: none; }

.hero-copy > *, .page-hero > div > * { animation: rise 1s var(--ease) both; }
.hero-copy > :nth-child(1), .page-hero > div > :nth-child(1) { animation-delay: .06s; }
.hero-copy > :nth-child(2), .page-hero > div > :nth-child(2) { animation-delay: .18s; }
.hero-copy > :nth-child(3), .page-hero > div > :nth-child(3) { animation-delay: .30s; }
.hero-copy > :nth-child(4), .page-hero > div > :nth-child(4) { animation-delay: .42s; }
.hero-img, .page-hero > img { animation: settle 1.8s var(--ease) both; }
@keyframes rise   { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }
@keyframes settle { from { opacity: 0; transform: scale(1.04); }     to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important;
      animation-delay: 0ms !important; transition-delay: 0ms !important; }
  .reveal-init { opacity: 1; transform: none; }
}

/* ── what it is good for ────────────────────────────────────────────────────
   The page's explanation of the treatment, in prose, because prose is what a
   search engine reads and what a first-time visitor actually wants before a
   price. Kept to one measure so it does not run the full width of a laptop. */
.benefits p { max-width: var(--measure); color: var(--ink-2); }
.benefits p + p { margin-top: 1.1rem; }

/* The packages, on the treatments index. They were one small link at the foot
   of the page; the client's own site shows them as three priced options, which
   is how people actually compare them. */
.packages-band .note { max-width: var(--measure); }
.packages-band .prices { margin-top: 1.6rem; }
.packages-band .packages-link { margin-top: 1.8rem; }
.mm-packages { border-top: 0; margin-top: 0; padding-top: 0; }
