/* ===========================================================================
   DESIGN TOKENS
   Palette: Forest. Deep green accent + cool bone paper, drawn from the
   practice photography. Deliberately NOT the warm cream / brass / terracotta
   wellness default.
   Radius: single 8px scale everywhere, controls included. No pills.
   Type: Plus Jakarta Sans variable (200-800), embedded. One family, hierarchy
   carried by scale + weight + colour.
   =========================================================================== */
@font-face{
  font-family:'Plus Jakarta Sans';
  font-style:normal;
  font-weight:200 800;
  font-display:swap;
  src:url(fonts/pjs-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

:root{
  --ink:#16211C;
  --ink-soft:#47554E;
  --paper:#F5F6F3;
  --paper-alt:#ECEFE8;
  --surface:#FFFFFF;
  --green:#1E4034;
  --green-mid:#2C5B49;
  --green-wash:#E4EBE4;
  --line:#D7DCD4;

  --r:8px;
  --pad:clamp(1.25rem,1rem + 2.2vw,3rem);
  --gap-section:clamp(4.5rem,3.2rem + 5.5vw,8.5rem);
  --measure:63ch;
  --head-h:100px;

  --t-fast:160ms;
  --t-mid:340ms;
  --ease:cubic-bezier(.16,1,.3,1);

  --shadow-soft:0 1px 2px rgba(22,33,28,.05),0 8px 24px -12px rgba(22,33,28,.14);
  --shadow-lift:0 2px 4px rgba(22,33,28,.06),0 16px 34px -14px rgba(22,33,28,.2);
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:'Plus Jakarta Sans',ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
  font-size:clamp(1rem,.965rem + .17vw,1.115rem);
  line-height:1.72;
  font-weight:400;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img{max-width:100%;height:auto;display:block}

/* Grid and flex children default to min-width:auto, which lets one long
   unbreakable string (a long practice name, an email
   address, a URL) force its track wider than the container and push the whole
   page into horizontal scroll. These two rules stop that for good. */
.hero-foot>*,.split>*,.bento>*,.groups>*,.foot-grid>*,.statement-body>*,.who-layout>*,.hero-split>*,.fee>*{min-width:0}
h1,h2,h3,p,li,dd,address,blockquote,summary{overflow-wrap:break-word}
h1,h2,h3{line-height:1.1;margin:0;font-weight:700;letter-spacing:-.025em;text-wrap:balance}
h1{font-size:clamp(2.3rem,1.5rem + 3.1vw,3.6rem);line-height:1.06;letter-spacing:-.035em}
h2{font-size:clamp(1.85rem,1.3rem + 2.1vw,2.9rem)}
h3{font-size:clamp(1.1rem,1.02rem + .3vw,1.3rem);letter-spacing:-.015em}
p{margin:0}
a{color:inherit}

.wrap{width:min(1240px,100% - (var(--pad) * 2));margin-inline:auto}
.prose{max-width:var(--measure)}
.muted{color:var(--ink-soft)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* focus + skip link ------------------------------------------------------ */
:focus-visible{outline:2.5px solid var(--green);outline-offset:3px;border-radius:2px}
/* Moves on transform, not top: transform is compositor-friendly and does not
   trigger layout on focus. */
.skip{
  position:absolute;left:var(--pad);top:.75rem;z-index:100;
  background:var(--green);color:#fff;padding:.75rem 1.1rem;border-radius:var(--r);
  font-weight:600;text-decoration:none;
  transform:translateY(-250%);transition:transform var(--t-fast) var(--ease);
}
.skip:focus{transform:translateY(0)}

/* ---------------------------------------------------------------- header */
.site-head{
  position:sticky;top:0;z-index:40;
  background:rgba(245,246,243,.88);
  backdrop-filter:blur(12px) saturate(140%);
  -webkit-backdrop-filter:blur(12px) saturate(140%);
  border-bottom:1px solid transparent;
  transition:border-color var(--t-mid) var(--ease),box-shadow var(--t-mid) var(--ease);
}
.site-head[data-stuck="true"]{border-bottom-color:var(--line);box-shadow:0 1px 14px rgba(22,33,28,.05)}
@supports not (backdrop-filter:blur(1px)){.site-head{background:var(--paper)}}

.head-in{display:flex;align-items:center;justify-content:space-between;gap:1.5rem;height:var(--head-h)}
.brand{flex:none;display:flex;align-items:center;gap:.6rem;text-decoration:none;font-weight:700;letter-spacing:-.02em;font-size:1.02rem;white-space:nowrap}
.foot-brand{display:inline-block;margin-bottom:clamp(2rem,1.6rem + 1.4vw,3rem)}
.site-foot a.foot-brand:hover{text-decoration:none;opacity:.9}
.brand span{color:var(--ink)}

.nav{display:flex;align-items:center;gap:clamp(1rem,.4rem + 1.3vw,1.9rem)}
/* :not(.btn) matters. Without it these rules out-specify .btn-primary and
   repaint the CTA label in muted grey on the dark green button, which fails
   contrast badly. Do not simplify to `.nav a`. */
.nav a:not(.btn){
  text-decoration:none;font-size:.935rem;font-weight:500;color:var(--ink-soft);
  white-space:nowrap;position:relative;padding-block:.3rem;transition:color var(--t-fast) var(--ease);
}
.nav a:not(.btn)::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1.5px;background:var(--green);
  transform:scaleX(0);transform-origin:left;transition:transform var(--t-mid) var(--ease);
}
.nav a:not(.btn):hover{color:var(--ink)}
.nav a:not(.btn):hover::after{transform:scaleX(1)}
/* Active page. Colour + underline only: a weight change would shift the
   nav's width between pages. */
.nav a[aria-current="page"]:not(.btn){color:var(--ink)}
.nav a[aria-current="page"]:not(.btn)::after{transform:scaleX(1)}
/* The fifth label is long. It stays on one line so the bar reads as one
   even row; the nav collapses (below) before it would run out of room. */
.nav a.nav-long:not(.btn){white-space:nowrap}

.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  font:inherit;font-weight:600;font-size:.945rem;line-height:1;
  padding:.82rem 1.35rem;border-radius:var(--r);border:1.5px solid transparent;
  text-decoration:none;cursor:pointer;white-space:nowrap;
  transition:background var(--t-fast) var(--ease),color var(--t-fast) var(--ease),
             transform var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease),
             border-color var(--t-fast) var(--ease);
}
.btn-primary{background:var(--green);color:#fff;box-shadow:var(--shadow-soft)}
.btn-primary:hover{background:var(--green-mid);box-shadow:var(--shadow-lift);transform:translateY(-1px)}
.btn-primary:active{transform:translateY(0) scale(.985);box-shadow:var(--shadow-soft)}
.btn-ghost{background:transparent;color:var(--ink);border-color:var(--line)}
.btn-ghost:hover{border-color:var(--green);color:var(--green);background:var(--surface)}
.btn-ghost:active{transform:scale(.985)}
.btn-lg{padding:1rem 1.6rem;font-size:1rem}
/* For dark bands and the footer. */
.btn-light{background:#fff;color:var(--green)}
.btn-light:hover{background:var(--green-wash);transform:translateY(-1px)}
.btn-light:active{transform:translateY(0) scale(.985)}
/* Long labels (e.g. "Book an appointment online") may wrap on narrow screens. */
.btn-wrap{white-space:normal;text-align:center;line-height:1.25}

.nav-toggle{display:none;background:transparent;border:1.5px solid var(--line);border-radius:var(--r);padding:.55rem;cursor:pointer;color:var(--ink)}
.nav-toggle:hover{border-color:var(--green);color:var(--green)}

/* ------------------------------------------------------------------ hero
   Family A2: centred stack. Headline, standfirst and booking bar sit centred
   over a wide photograph whose edges dissolve into the paper, then a
   two-column sign-off line closes the section. Adapted from the 21st.dev
   Hero09 block, rebuilt in plain CSS on the Forest tokens (no React). */
.hero{--hero-gap:clamp(2rem,1.2rem + 3vw,3.5rem);--hero-overlap:clamp(3.5rem,1rem + 11vw,10.5rem);padding-block:clamp(1.5rem,1rem + 2vw,3rem) var(--gap-section);display:flex;flex-direction:column;gap:var(--hero-gap)}
.hero-head{display:flex;flex-direction:column;align-items:center;text-align:center;gap:1.25rem;max-width:44rem;margin:calc(-1 * var(--hero-gap) - var(--hero-overlap)) auto 0;position:relative;z-index:1}
.hero h1{font-weight:500;letter-spacing:-.04em;max-width:none}
/* Soft paper haze behind the overlapping text so it stays readable where the
   photo has not fully dissolved yet. */
.hero-head::before{content:"";position:absolute;z-index:-1;inset:-2.5rem -3rem 35%;pointer-events:none;
  background:radial-gradient(closest-side,rgba(245,246,243,.9) 45%,rgba(245,246,243,0) 100%)}
.hero h1 span{display:block}
.hero-sub{font-size:clamp(1.02rem,.98rem + .25vw,1.14rem);color:var(--ink-soft);max-width:42ch;line-height:1.62;text-wrap:balance}

/* Booking bar: the Hero09 search pill, repurposed as the primary CTA. Outer
   radius is the button's radius plus the bar's padding, so the corners stay
   concentric on the house 8px scale. */
.book-bar{
  display:flex;align-items:center;gap:.75rem;width:100%;max-width:33rem;margin-top:.5rem;
  background:var(--surface);border:1px solid var(--line);border-radius:calc(var(--r) + .4rem);
  padding:.4rem .4rem .4rem 1rem;box-shadow:var(--shadow-soft);text-align:left;
  transition:border-color var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease);
}
.book-bar:hover,.book-bar:focus-within{border-color:#B9C2B8;box-shadow:var(--shadow-lift)}
.book-bar svg{flex:none;color:var(--green)}
.book-bar-text{flex:1;font-size:1rem;font-weight:500;color:var(--ink);line-height:1.35}
.book-bar .btn{flex:none}

/* Mask stack from Hero09: side fades, a top/bottom fade and a radial vignette,
   intersected, so the photo has no hard edge anywhere and melts into --paper.
   Softer than the original on purpose: the remedy bottle is the subject and
   has to stay legible. -webkit- composite is for Safari.
   Order is logo, photo, text: the photo's faded top edge starts just under
   the logo, and the heading, standfirst and booking bar (.hero-head) are
   pulled up by --hero-overlap to sit on its dissolving bottom edge. */
.hero-media{
  margin:calc(-.5rem - var(--hero-gap)) auto 0;width:100%;max-width:64rem;
  --fade-x:linear-gradient(to right,transparent 0,#000 16%,#000 84%,transparent 100%);
  --fade-y:linear-gradient(to bottom,transparent 0,#000 18%,#000 52%,transparent 92%);
  --fade-r:radial-gradient(95% 88% at 50% 50%,#000 62%,transparent 100%);
  mask-image:var(--fade-x),var(--fade-y),var(--fade-r);
  -webkit-mask-image:var(--fade-x),var(--fade-y),var(--fade-r);
  mask-composite:intersect;
  -webkit-mask-composite:source-in;
}
.hero-media img{width:100%;aspect-ratio:16/10;object-fit:cover}

.hero-foot{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));align-items:end;gap:1.5rem 3rem;position:relative}
.hero-foot h2{font-size:clamp(1.6rem,1.15rem + 1.9vw,2.6rem);font-weight:500;letter-spacing:-.035em}
.hero-foot h2 span{display:block}
.hero-foot p{color:var(--ink-soft);font-size:1rem;line-height:1.62;max-width:34ch;justify-self:end}
.hero-foot a{color:var(--green);font-weight:600;text-underline-offset:3px;white-space:nowrap}
.hero-foot a:hover{color:var(--green-mid)}

/* --------------------------------------------------- section scaffolding */
section[id]{scroll-margin-top:calc(var(--head-h) + 16px)}
.band{padding-block:var(--gap-section)}
.band-alt{background:var(--paper-alt)}
.sec-head{max-width:34ch;margin-bottom:clamp(2rem,1.4rem + 1.8vw,3.2rem)}
.sec-head p{margin-top:1.1rem;color:var(--ink-soft)}

/* Below-the-fold work is handled by loading="lazy" on imagery plus the
   IntersectionObserver reveal. content-visibility:auto was tried here and
   removed on purpose: on a DOM this small it buys nothing measurable, and it
   can skip paint on sections whose reveal observer has not fired yet, leaving
   them blank. Do not reintroduce it without re-testing a full-page render. */

/* ------------------------------------------------- statement (family: B) */
.statement{border-top:1px solid var(--line);padding-top:clamp(2.2rem,1.6rem + 2vw,3.4rem)}
.statement h2{max-width:20ch}
.statement-body{margin-top:1.6rem;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(1.4rem,1rem + 1.6vw,3rem)}
.statement-body p{color:var(--ink-soft);max-width:52ch}

/* -------------------------------------------- interlude (family: B-bleed) */
/* Pure visual pause between the editorial statement and the bento . no text,
   so it is a different job to the testimonial's full-bleed quote-cover and
   does not repeat that layout family. Edges fade into the bands either side
   (paper above, paper-alt below) rather than cutting hard. */
.interlude{position:relative;overflow:hidden;height:clamp(220px,28vw,420px)}
.interlude img{width:100%;height:100%;max-width:none;object-fit:cover;transform-origin:center}
.interlude::before,.interlude::after{content:"";position:absolute;inset:0 0 auto 0;height:22%;pointer-events:none}
.interlude::before{background:linear-gradient(var(--paper),transparent)}
.interlude::after{top:auto;bottom:0;background:linear-gradient(transparent,var(--paper-alt))}

/* ------------------------------------------------------ bento (family: C) */
.bento{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));grid-auto-rows:minmax(0,auto);gap:clamp(.9rem,.6rem + .8vw,1.4rem)}
.cell{border-radius:var(--r);padding:clamp(1.5rem,1.1rem + 1.4vw,2.4rem);display:flex;flex-direction:column;gap:.85rem;min-height:250px}
.cell h3{max-width:18ch}
.cell p{font-size:.985rem;line-height:1.66}
.cell-wide{grid-column:span 2;background:var(--surface);border:1px solid var(--line);justify-content:flex-start}
.cell-tint{background:var(--green);color:#fff;justify-content:flex-start}
.cell-tint p{color:rgba(255,255,255,.84)}
.cell-media{grid-column:span 3;position:relative;overflow:hidden;min-height:clamp(230px,18vw,320px);justify-content:flex-end;color:#fff;padding:clamp(1.6rem,1.2rem + 1.4vw,2.6rem)}
/* max-width:none is required: the global img{max-width:100%} otherwise
   constrains this absolutely-positioned cover image and object-fit crops the
   photo into a narrow box, leaving the rest of the cell empty. */
.cell-media img{position:absolute;inset:0;width:100%;height:100%;max-width:none;object-fit:cover;z-index:0}
.cell-media::after{content:"";position:absolute;inset:0;z-index:1;background:linear-gradient(190deg,rgba(9,20,15,.34) 0%,rgba(9,20,15,.78) 78%)}
.cell-media>*{position:relative;z-index:2;max-width:46ch}
.cell-media p{color:rgba(255,255,255,.88)}

/* ------------------------------------------------------ split (family: D) */
.split{display:grid;grid-template-columns:.85fr 1.15fr;gap:clamp(2rem,1.2rem + 4vw,4.5rem);align-items:center}
.split-media{border-radius:var(--r);overflow:hidden;box-shadow:var(--shadow-lift)}
.split-media img{width:100%;aspect-ratio:2/3;object-fit:cover}
/* Wrap carries the overlap: .split-media keeps its own overflow:hidden for the
   portrait's rounded corners, so the inset print has to hang off a separate,
   overflow:visible parent rather than off .split-media itself. */
.split-media-wrap{position:relative}
.split-inset{
  position:absolute;right:-6%;bottom:-9%;width:38%;aspect-ratio:2/3;
  max-width:none;object-fit:cover;border-radius:var(--r);
  border:5px solid var(--paper);box-shadow:var(--shadow-lift);
}
.split-copy>*+*{margin-top:1.35rem}
.split-copy p{color:var(--ink-soft);max-width:54ch}
.cred{margin-top:2rem;display:flex;flex-wrap:wrap;gap:.55rem}
.cred li{list-style:none;font-size:.88rem;font-weight:500;color:var(--green);background:var(--green-wash);border-radius:var(--r);padding:.45rem .8rem}
.cred{padding:0}

/* ------------------------------------------- grouped columns (family: E) */
.groups{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(1.8rem,1.2rem + 2.4vw,3.6rem) clamp(2rem,1.4rem + 3vw,5rem)}
.group{border-top:2px solid var(--green);padding-top:1.2rem}
.group h3{margin-bottom:.6rem}
.group p{color:var(--ink-soft);font-size:.985rem;line-height:1.68}

/* ------------------------------------------------ testimonial (family: F) */
.quote-band{position:relative;overflow:hidden;color:#fff;padding-block:clamp(4rem,2.8rem + 5vw,7rem)}
.quote-media{position:absolute;inset:0;z-index:0}
.quote-media img{width:100%;height:100%;max-width:none;object-fit:cover;transform-origin:center}
.quote-band::after{content:"";position:absolute;inset:0;z-index:1;background:linear-gradient(160deg,rgba(9,20,15,.7),rgba(9,20,15,.86))}
/* The wrapper carries the stacking context so the quote aligns to the page
   grid. Putting max-width on the .wrap element itself would let its auto
   margins centre the quote instead. */
.quote-wrap{position:relative;z-index:2}
.quote-in{max-width:52ch}
.quote-in blockquote{margin:0;font-size:clamp(1.3rem,1.05rem + 1.1vw,1.85rem);line-height:1.42;font-weight:500;letter-spacing:-.02em}
.quote-cite{margin-top:1.4rem;font-size:.92rem;color:rgba(255,255,255,.78);font-style:normal}
.quote-cite strong{color:#fff;font-weight:600}

/* -------------------------------------------------------- FAQ (family: G) */
.faq{max-width:74ch}
.faq details{border-bottom:1px solid var(--line)}
.faq summary{
  cursor:pointer;list-style:none;padding:1.25rem 2.5rem 1.25rem 0;position:relative;
  font-weight:600;font-size:1.05rem;letter-spacing:-.015em;
  transition:color var(--t-fast) var(--ease);
}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--green)}
.faq summary::after{
  content:"";position:absolute;right:.35rem;top:50%;width:11px;height:11px;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:translateY(-70%) rotate(45deg);transition:transform var(--t-mid) var(--ease);
}
.faq details[open] summary::after{transform:translateY(-30%) rotate(-135deg)}
.faq-a{padding:0 2.5rem 1.4rem 0;color:var(--ink-soft);max-width:60ch}
.faq-a>*+*{margin-top:.9rem}

/* ------------------------------------------------------ contact details */
.detail-list{display:grid;gap:1.35rem;margin-top:2rem;padding:0;list-style:none}
.detail-list dt{font-size:.82rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--green)}
.detail-list dd{margin:.3rem 0 0;color:var(--ink-soft)}
.detail-list a{color:var(--ink);text-decoration-color:var(--line);text-underline-offset:3px}
.detail-list a:hover{color:var(--green)}
.detail-list--cols{grid-template-columns:repeat(2,minmax(0,1fr));gap:1.6rem clamp(2rem,1.2rem + 4vw,4.5rem);max-width:60rem}

/* ---- booking rows (Appointment page): name + length, button far right -- */
.book-list{display:grid;gap:.85rem;margin:0;padding:0;list-style:none;max-width:52rem}
.book-row{
  display:flex;align-items:center;gap:.4rem 1.5rem;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:1.15rem 1.15rem 1.15rem 1.4rem;
  transition:border-color var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease);
}
.book-row:hover,.book-row:focus-within{border-color:#B9C2B8;box-shadow:var(--shadow-soft)}
.book-row-text{flex:1;display:flex;flex-wrap:wrap;align-items:baseline;gap:.2rem 1rem}
.book-row-time{font-size:.95rem;color:var(--ink-soft)}
.book-row .btn{flex:none;min-width:7.5rem;min-height:44px}

/* ---------------------------------------------------------------- footer */
.site-foot{background:var(--green);color:rgba(255,255,255,.82);padding-block:clamp(3rem,2.2rem + 2.4vw,4.5rem) 2rem;margin-top:var(--gap-section)}
.foot-grid{display:grid;grid-template-columns:1.4fr 1fr 1fr;gap:2.5rem}
.site-foot h2{font-size:1.05rem;color:#fff;margin-bottom:1rem;letter-spacing:-.01em}
.site-foot a{color:rgba(255,255,255,.82);text-decoration:none;text-underline-offset:3px}
.site-foot a:hover{color:#fff;text-decoration:underline}
.foot-nav{list-style:none;padding:0;margin:0;display:grid;gap:.6rem;font-size:.94rem}
.nap{font-style:normal;font-size:.94rem;line-height:1.75}
.nap strong{color:#fff;font-weight:600}
.socials{display:flex;gap:.7rem;margin-top:1.2rem}
.socials a{display:grid;place-items:center;width:40px;height:40px;border:1.5px solid rgba(255,255,255,.28);border-radius:var(--r);transition:background var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease)}
.socials a:hover{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.6)}
.foot-base{margin-top:clamp(2.2rem,1.8rem + 1.4vw,3.2rem);padding-top:1.5rem;border-top:1px solid rgba(255,255,255,.18);display:flex;flex-wrap:wrap;gap:.6rem 1.5rem;justify-content:space-between;font-size:.86rem}

/* --------------------------------------------------------------- privacy */
.privacy{background:var(--paper-alt);border-radius:var(--r);padding:clamp(1.6rem,1.2rem + 1.6vw,2.6rem)}
.privacy h3{margin-top:1.6rem}
.privacy h3:first-of-type{margin-top:1.2rem}
.privacy p{color:var(--ink-soft);margin-top:.6rem;max-width:68ch;font-size:.97rem}

/* ================================================================ MOTION
   MOTION_INTENSITY 4. Every animation is motivated:
   . reveal     = establishes reading order as each band enters
   . hover/press = feedback on interactive elements
   . drift      = slow parallax on the one full-bleed image, gives the quote
                  band depth without competing with the text
   All of it collapses under prefers-reduced-motion.
   ======================================================================= */
/* The hidden state is gated on .js, which is set by an inline script in the
   head. Without JavaScript, or if the script fails before the observer is
   wired up, nothing is ever hidden and the page reads as plain content. */
@media (prefers-reduced-motion:no-preference){
  .js .reveal{opacity:0;transform:translateY(18px);transition:opacity 620ms var(--ease),transform 620ms var(--ease)}
  .js .reveal[data-seen="true"]{opacity:1;transform:none}
  .js .stagger>*{opacity:0;transform:translateY(14px);transition:opacity 560ms var(--ease),transform 560ms var(--ease);transition-delay:calc(var(--i,0) * 75ms)}
  .js .stagger[data-seen="true"]>*{opacity:1;transform:none}
  /* Hero: Hero09's blur-in, staggered by --i. filter is on the house
     "sparingly" list; this is the only place on the page it animates. */
  .js .hero .reveal{filter:blur(6px);transition:opacity 560ms var(--ease),transform 560ms var(--ease),filter 560ms var(--ease);transition-delay:calc(var(--i,0) * 100ms)}
  .js .hero .hero-media.reveal{transform:translateY(24px);filter:blur(8px);transition-duration:680ms}
  .js .hero .reveal[data-seen="true"],.js .hero .hero-media.reveal[data-seen="true"]{opacity:1;transform:none;filter:none}
}

/* Scroll-driven parallax.
   NOTE: animation-timeline is kept in its own declaration block on purpose.
   Folding it into the `animation` shorthand causes minifiers to drop it and
   the effect silently dies. Do not merge these two rules. */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .quote-media img,.interlude img,.page-hero-media img{
      animation-name:drift;
      animation-duration:1ms;
      animation-timing-function:linear;
      animation-fill-mode:both;
    }
    .quote-media img,.interlude img,.page-hero-media img{
      animation-timeline:view();
      animation-range:entry 0% exit 100%;
    }
  }
}
@keyframes drift{from{transform:scale(1.12) translateY(-2.2%)}to{transform:scale(1.12) translateY(2.2%)}}

/* =========================================================== RESPONSIVE
   Explicit collapse per layout family. Nothing left to chance.
   ======================================================================= */
@media (max-width:1000px){
  .split{grid-template-columns:1fr;gap:2.2rem}
  .split-media,.split-media-wrap{max-width:420px}
  .split-media img{aspect-ratio:4/5}
  .foot-grid{grid-template-columns:1fr 1fr}
  .bento{grid-template-columns:repeat(2,minmax(0,1fr))}
  .cell-wide{grid-column:span 2}
  .cell-tint{grid-column:span 2}
  .cell-media{grid-column:span 2}
}

/* Nav collapses below 1200px: with every label on one line (including the
   long "Appointment and Contact Information"), the emblem, five links and
   the CTA need ~1200px. Measured, not guessed. */
@media (max-width:1199px){
  .nav-toggle{display:grid;place-items:center}
  .nav{
    position:fixed;inset:var(--head-h) 0 auto;flex-direction:column;align-items:stretch;gap:0;
    background:var(--paper);border-bottom:1px solid var(--line);
    padding:.5rem var(--pad) 1.25rem;
    box-shadow:0 16px 30px -18px rgba(22,33,28,.3);
    display:none;max-height:calc(100vh - var(--head-h));overflow-y:auto;
  }
  .nav[data-open="true"]{display:flex}
  .nav a.nav-long:not(.btn){white-space:normal;max-width:none;line-height:1.4}
  .nav a[aria-current="page"]:not(.btn){color:var(--green);font-weight:600}
  .nav a:not(.btn){padding:.85rem 0;font-size:1.02rem;border-bottom:1px solid var(--line);color:var(--ink)}
  .nav a:not(.btn)::after{display:none}
  .nav .btn{margin-top:1rem;width:100%}
}

@media (max-width:760px){
  .statement-body{grid-template-columns:1fr;gap:1.1rem}
  .bento{grid-template-columns:1fr}
  .cell-wide,.cell-tint,.cell-media{grid-column:span 1}
  .cell{min-height:0}
  .groups{grid-template-columns:1fr}
  .foot-grid{grid-template-columns:1fr;gap:2.2rem}
  .split-media,.split-media-wrap{max-width:none}
  /* The overlapping inset print needs room to hang off the corner without
     touching the text column; below 760px there isn't any, so it drops
     rather than crowding the portrait. */
  .split-inset{display:none}
  .foot-base{flex-direction:column}
}

@media (max-width:760px){
  .hero-foot{grid-template-columns:1fr;gap:1rem}
  .hero-foot p{justify-self:start}
  .hero-media img{aspect-ratio:4/3}
}

/* Bar content no longer fits on one line: stack it, button full width. */
@media (max-width:560px){
  .book-bar{flex-wrap:wrap;justify-content:center;padding:.9rem .6rem .6rem;gap:.5rem .6rem}
  .book-bar-text{flex:0 1 auto;text-align:center}
  .book-bar .btn{flex:1 1 100%}
}


/* =========================================================================
   MULTI-PAGE ADDITIONS
   Components introduced by the four-page restructure. Everything reuses the
   tokens above; nothing here is page-specific, so a future page can use any
   of it as-is.
   ========================================================================= */

/* ---- page hero: h1 over a faded photograph ------------------------------
   The photo is decorative (alt=""). The overlay is what guarantees contrast:
   worst case is a black pixel under the lightest part of the overlay, which
   still leaves ink text above 7:1. It fades to --paper along the bottom so
   the band melts into the page. */
.page-hero{position:relative;overflow:hidden;isolation:isolate;padding-block:clamp(3.5rem,2.4rem + 5vw,7rem) clamp(3rem,2rem + 4vw,5.5rem)}
.page-hero-media{position:absolute;inset:0;z-index:-2}
.page-hero-media img{width:100%;height:100%;max-width:none;object-fit:cover;transform-origin:center}
.page-hero::after{
  content:"";position:absolute;inset:0;z-index:-1;
  background:
    linear-gradient(to bottom,transparent 55%,var(--paper) 96%),
    linear-gradient(90deg,rgba(245,246,243,.9) 0%,rgba(245,246,243,.62) 100%);
}
.page-hero h1{max-width:20ch}
.page-hero--plain{padding-block-end:clamp(1.5rem,1rem + 2vw,3rem)}
.page-hero--plain::after{display:none}

/* Appointment page: h1 beside a strong, uncropped-feeling photograph. */
.hero-split{display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(2rem,1.2rem + 4vw,4.5rem);align-items:center}
.hero-split h1{max-width:14ch}
.hero-fig{margin:0;border-radius:var(--r);overflow:hidden;box-shadow:var(--shadow-lift)}
.hero-fig img{width:100%;aspect-ratio:4/5;object-fit:cover;object-position:60% 12%}
.hero-fig--waterfall img{object-position:50% 50%}

/* ---- fees (Services and Fees) ------------------------------------------ */
.fees{display:grid;gap:.85rem;margin:1.6rem 0 0;padding:0;list-style:none}
.fee{
  display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.15rem 1.5rem;align-items:center;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:1.15rem 1.4rem;
}
.fee h3{grid-column:1}
.fee-note{grid-column:1;font-size:.92rem;color:var(--ink-soft)}
.fee-price{grid-column:2;grid-row:1 / span 2;font-size:clamp(1.7rem,1.4rem + 1vw,2.2rem);font-weight:700;letter-spacing:-.035em;color:var(--green);line-height:1}
.fee-terms{margin-top:1.5rem;display:grid;gap:.6rem}
.fee-actions{margin-top:1.8rem;display:flex;flex-wrap:wrap;gap:.75rem}
.split-copy .fees+.fee-terms{margin-top:1.5rem}

/* ---- who-comes layout: photograph beside the four groups --------------- */
.who-layout{display:grid;grid-template-columns:.62fr 1.38fr;gap:clamp(2rem,1.2rem + 4vw,4.5rem);align-items:start}
.who-fig{margin:0;border-radius:var(--r);overflow:hidden;box-shadow:var(--shadow-lift)}
.who-fig img{width:100%;aspect-ratio:4/5;object-fit:cover}

/* ---- closing call to action on a dark photograph (reuses .quote-band) -- */
.cta-band h2{color:#fff}
.cta-band .quote-in p{margin-top:1rem;color:rgba(255,255,255,.88)}
.cta-band .btn{margin-top:1.6rem}

/* ---- footer CTA -------------------------------------------------------- */
.foot-cta{margin-top:1.4rem}
.site-foot .btn-light{color:var(--green)}
.site-foot .btn-light:hover{color:var(--green);text-decoration:none}

@media (max-width:1000px){
  .hero-split{grid-template-columns:1fr}
  .hero-split h1{max-width:none}
  .hero-fig img{aspect-ratio:16/10;object-position:70% 14%}
  .hero-fig--waterfall img{object-position:45% 55%}
  .who-layout{grid-template-columns:1fr}
  .who-fig img{aspect-ratio:16/10}
}
@media (max-width:760px){
  .detail-list--cols{grid-template-columns:1fr}
}
@media (max-width:560px){
  .book-row{flex-wrap:wrap;padding:1.05rem 1.1rem}
  .book-row .btn{flex:1 1 100%}
  .fee{padding:1rem 1.1rem}
  .fee-actions .btn{flex:1 1 100%}
}

/* When a page ends on a full-bleed band, the footer follows it directly
   instead of after the usual section gap. (:has is progressive: without it the
   gap simply stays.) */
main:has(> .cta-band:last-child)+.site-foot{margin-top:0}

@media (max-width:760px){:root{--head-h:84px}}

/* ---- phone pass ------------------------------------------------------------
   Body text at 16px minimum, tap targets at 44px minimum, and nothing wider
   than the screen (body's overflow-x:hidden is not honoured by iOS Safari). */
@media (max-width:760px){
  /* The hero text haze stays inside the column instead of bleeding past it. */
  .hero-head::before{inset:-2rem 0 35%}
  .cell p,.cred li,.group p,.quote-cite,.book-row-time,.foot-nav,.nap,.foot-base,
  .privacy p,.fee-note,.btn,.detail-list dt{font-size:1rem}
  .nav-toggle{min-width:44px;min-height:44px}
  .socials a{width:44px;height:44px}
  .foot-nav{gap:0}
  .foot-nav a,.nap a{display:inline-block;padding-block:.6rem}
  .detail-list a{display:inline-block;padding-block:.7rem;margin-block:-.7rem}
}
/* The hero photo is the largest thing on a phone's first screen (its LCP), so
   it shows straight away there rather than waiting on the scroll reveal. */
@media (max-width:760px) and (prefers-reduced-motion:no-preference){
  .js .hero .hero-media.reveal{opacity:1;transform:none;filter:none;transition:none}
}

/* ===========================================================================
   ANIMATED LOGO
   Drop-in from LOGO/Hero Logo Animation (Light/Dark).html, verbatim below the
   site overrides. Header uses .tph-light on the paper, footer .tph-dark on the
   green. Markup lives in site-src-v2/partials/header.html + footer.html.
   =========================================================================== */
/* ===== The Practical Homeopath — animated logo (drop-in) =====
   Theme: add .tph-dark or .tph-light to .tph-logo. All motion is CSS; no JS needed. */
@font-face{font-family:"TPH Crimson";font-weight:500;font-style:normal;font-display:block;src:url(data:font/woff2;base64,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) format("woff2")}
@font-face{font-family:"TPH Crimson";font-weight:400;font-style:normal;font-display:block;src:url(data:font/woff2;base64,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) format("woff2")}
@font-face{font-family:"TPH Crimson";font-weight:400;font-style:italic;font-display:block;src:url(data:font/woff2;base64,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) format("woff2")}

.tph-logo{
  --tph-arc:#9fb88b; --tph-stem:#9fb88b; --tph-leaf-a:#9fb88b; --tph-leaf-b:#88a474; --tph-vein:#3b5129;
  --tph-petal:#f4efe3; --tph-petal-line:transparent; --tph-petal-vein:rgba(59,81,41,.18); --tph-centre:#9fb88b;
  --tph-bottle-fill:rgba(190,208,172,.10); --tph-bottle-line:#b7cba5; --tph-pill:#f4efe3; --tph-pill-line:transparent;
  --tph-ink:#f1ece0; --tph-ink-soft:#dcd6c6; --tph-rule:#9fb88b;
  width:100%; max-width:520px; margin-inline:auto; line-height:0;
}
.tph-logo.tph-light{
  --tph-arc:#3f5b2b; --tph-stem:#3f5b2b; --tph-leaf-a:#3f5b2b; --tph-leaf-b:#4f6d38; --tph-vein:#8fab7a;
  --tph-petal:#ffffff; --tph-petal-line:#3f5b2b; --tph-petal-vein:rgba(63,91,43,.25); --tph-centre:#3f5b2b;
  --tph-bottle-fill:#8ea874; --tph-bottle-line:#3f5b2b; --tph-pill:#ffffff; --tph-pill-line:#3f5b2b;
  --tph-ink:#3d5629; --tph-ink-soft:#3d5629; --tph-rule:#3f5b2b;
}
.tph-svg{width:100%;height:auto;display:block;overflow:visible}
.tph-svg *{transform-box:view-box;transform-origin:0 0}

/* shapes */
.tph-arc{fill:none;stroke:var(--tph-arc);stroke-width:4.5;stroke-linecap:round}
.tph-stem{fill:none;stroke:var(--tph-stem);stroke-width:5;stroke-linecap:round}
.tph-stem-bud{stroke-width:3.5}
.tph-leaf-a{fill:var(--tph-leaf-a)} .tph-leaf-b{fill:var(--tph-leaf-b)}
.tph-vein{fill:none;stroke:var(--tph-vein);stroke-width:2.2;stroke-linecap:round;opacity:.85}
.tph-petal-fill{fill:var(--tph-petal);stroke:var(--tph-petal-line);stroke-width:3;stroke-linejoin:round}
.tph-petal-vein{stroke:var(--tph-petal-vein);stroke-width:1.6;stroke-linecap:round}
.tph-centre-dot{fill:var(--tph-centre)}
.tph-stamens line{stroke:var(--tph-centre);stroke-width:1.8} .tph-stamens circle{fill:var(--tph-centre)}
.tph-bottle-body{fill:var(--tph-bottle-fill);stroke:var(--tph-bottle-line);stroke-width:4;stroke-linejoin:round}
.tph-bottle-lip{fill:var(--tph-bottle-fill);stroke:var(--tph-bottle-line);stroke-width:3.5}
.tph-bottle-glint{stroke:var(--tph-petal);stroke-width:3;stroke-linecap:round;opacity:.45}
.tph-pill{fill:var(--tph-pill);stroke:var(--tph-pill-line);stroke-width:2.5}
.tph-word{font:500 118px/1 "TPH Crimson",Georgia,serif;fill:var(--tph-ink);text-anchor:middle;letter-spacing:-.5px}
.tph-sub{font:400 37px/1 "TPH Crimson",Georgia,serif;fill:var(--tph-ink-soft);text-anchor:middle;letter-spacing:6.5px}
.tph-tag{font:italic 400 47px/1 "TPH Crimson",Georgia,serif;fill:var(--tph-ink);text-anchor:middle}
.tph-rule{stroke:var(--tph-rule);stroke-width:3;stroke-linecap:round}

/* ===== intro (plays once, ~3.9s) ===== */
.tph-arc{stroke-dasharray:100;animation:tph-draw 1.9s cubic-bezier(.45,0,.2,1) .1s both}
.tph-stem{stroke-dasharray:100;animation:tph-draw 1s cubic-bezier(.4,0,.2,1) .25s both}
.tph-stem-bud{animation-delay:1.05s;animation-duration:.6s}
.tph-grow{animation:tph-grow 1s cubic-bezier(.3,1.35,.6,1) var(--d) both}
.tph-petal{animation:tph-bloom .9s cubic-bezier(.3,1.5,.55,1) var(--d) both}
.tph-centre{animation:tph-pop .7s cubic-bezier(.3,1.6,.5,1) 1.25s both}
.tph-bottle{animation:tph-tip 1.1s cubic-bezier(.3,1.25,.55,1) 1.45s both}
.tph-spill{transform-box:fill-box;transform-origin:50% 50%;animation:tph-roll .85s cubic-bezier(.3,1.45,.5,1) var(--d) both}
.tph-rise{animation:tph-rise 1s cubic-bezier(.2,.7,.2,1) var(--d) both}
.tph-rule{transform-box:fill-box;animation:tph-extend .9s cubic-bezier(.3,0,.2,1) var(--d) both}
.tph-rule-l{transform-origin:100% 50%} .tph-rule-r{transform-origin:0 50%}
.tph-mark{animation:tph-mark .8s cubic-bezier(.3,1.6,.5,1) 3.3s both}

@keyframes tph-draw{from{stroke-dashoffset:100}to{stroke-dashoffset:0}}
@keyframes tph-grow{from{transform:scale(0);opacity:0}30%{opacity:1}to{transform:scale(1);opacity:1}}
@keyframes tph-bloom{from{transform:scale(.1) rotate(-14deg);opacity:0}40%{opacity:1}to{transform:none;opacity:1}}
@keyframes tph-pop{from{transform:scale(0)}to{transform:scale(1)}}
@keyframes tph-tip{from{transform:translate(10px,-14px) rotate(9deg);opacity:0}35%{opacity:1}to{transform:none;opacity:1}}
@keyframes tph-roll{from{transform:translate(var(--dx),var(--dy)) scale(.55);opacity:0}25%{opacity:1}to{transform:none;opacity:1}}
@keyframes tph-rise{from{transform:translateY(16px);opacity:0}to{transform:none;opacity:1}}
@keyframes tph-extend{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@keyframes tph-mark{from{transform:translate(500px,954px) scale(0)}to{transform:translate(500px,954px) scale(1)}}

/* ===== idle (gentle, starts after intro) ===== */
.tph-sway{animation:tph-sway var(--sd) ease-in-out calc(4s + var(--so) * -0.3) infinite}
.tph-breathe{animation:tph-breathe 7s ease-in-out 4.2s infinite}
.tph-idle-roll{transform-box:fill-box;animation:tph-nudge 9s ease-in-out 6s infinite}
@keyframes tph-sway{0%,100%{transform:rotate(0)}25%{transform:rotate(-1.6deg)}75%{transform:rotate(1.6deg)}}
@keyframes tph-breathe{0%,100%{transform:scale(1) rotate(0)}50%{transform:scale(1.04) rotate(3deg)}}
@keyframes tph-nudge{0%,70%,100%{transform:translateX(0)}80%{transform:translateX(-7px)}90%{transform:translateX(1px)}}

/* pause idle loops when the hero is off-screen (class toggled by the optional script) */
.tph-logo.tph-offscreen *{animation-play-state:paused}

@media (prefers-reduced-motion:reduce){.tph-logo *{animation:none!important}}

/* ---- site overrides ---- */
/* Full lockup (wordmark included), so it takes nearly the whole bar height. */
.brand img{flex:none;height:calc(var(--head-h) - 12px);width:auto}
/* Height-aware so the logo, standfirst, booking bar and the top of the photo
   all land above the fold on laptop screens; full 560px on tall displays. */
.hero .hero-logo{width:min(560px,88vw,max(300px,54vh));margin:0 auto}
.hero-logo .tph-logo{display:block}
/* Visible keyword line under the hero logo. Shows straight away so the hero
   isn't empty while the logo draws itself in. */
.hero-kicker{display:block;font-size:1rem;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--green);line-height:1.4}
@media (prefers-reduced-motion:no-preference){
  .hero-kicker{animation:hero-kicker-in .8s var(--ease) .15s both}
  @keyframes hero-kicker-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
}
.foot-brand .tph-logo{width:clamp(180px,10vw + 110px,230px);margin:0}
/* Footer logo holds its intro until it scrolls into view (main.js removes
   .tph-wait). Gated on .js so it can never stay hidden without scripting. */
.js .tph-logo.tph-wait *{animation-play-state:paused}

/* ---- pregnancy and birth: wide framed newborn photo ----------------------
   Framed rather than a faded full-bleed interlude: a photo of people should
   not have its edges washed into the page. */
.pb-wide-sec{padding-bottom:var(--gap-section)}
.pb-wide{margin:0;border-radius:var(--r);overflow:hidden;box-shadow:var(--shadow-lift)}
.pb-wide img{width:100%;aspect-ratio:16/9;object-fit:cover}
@media (max-width:760px){
  .pb-wide img{aspect-ratio:4/3}
  /* Stages photo stays portrait on phones: a wide crop can't show both her
     face and the bump. */
  #stages .who-fig img{aspect-ratio:4/5}
}

/* Taller, lighter page hero (About, Services, Pregnancy and Birth): more of the
   background photo shows, and the fade into the page starts lower. */
.page-hero--tall{padding-block:clamp(6rem,4rem + 9vw,12rem) clamp(6rem,4rem + 8vw,11rem)}
.page-hero--tall::after{
  background:
    linear-gradient(to bottom,transparent 72%,var(--paper) 100%),
    linear-gradient(90deg,rgba(245,246,243,.78) 0%,rgba(245,246,243,.28) 70%,rgba(245,246,243,.2) 100%);
}

/* ---- kind words: infinite moving card rail (home) --------------------------
   Native port of the "infinite moving cards" component. main.js clones
   .rail-set and adds .is-moving; the track then slides by exactly one set
   (-50%) and loops. Each set carries one trailing gap so the seam is even.
   Without JS or with reduced motion it is a plain horizontal scroller. */
.words{--rail-gap:clamp(1rem,.8rem + .6vw,1.4rem);overflow:hidden}
.words-head{display:flex;align-items:flex-end;justify-content:space-between;gap:1rem 2rem;flex-wrap:wrap;margin-bottom:clamp(2rem,1.4rem + 1.8vw,3.2rem)}
.words-head .sec-head{margin-bottom:0}
.rail-toggle{min-height:44px}
.rail-viewport{
  overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:thin;
  padding:.5rem 0 1.25rem;padding-inline-start:var(--pad);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 5%,#000 95%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 5%,#000 95%,transparent);
}
.rail-viewport:focus-visible{outline:2px solid var(--green);outline-offset:4px;border-radius:var(--r)}
.rail-track{display:flex;width:max-content}
.rail-set{display:flex;gap:var(--rail-gap);margin:0;padding:0 var(--rail-gap) 0 0;list-style:none}
.rail-card{
  margin:0;height:100%;width:min(22rem,calc(100vw - 5rem));
  display:flex;flex-direction:column;gap:1.1rem;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:clamp(1.4rem,1.2rem + .6vw,1.8rem);box-shadow:var(--shadow-soft);
  transition:transform var(--t-mid) var(--ease),box-shadow var(--t-mid) var(--ease);
}
.rail-card:hover{transform:translateY(-3px);box-shadow:var(--shadow-lift)}
.rail-card blockquote{margin:0}
.rail-card blockquote p{margin:0;font-size:1rem;line-height:1.66;color:var(--ink)}
.rail-card blockquote::before{content:"\201C" / "";display:block;height:1.3rem;font-size:3rem;line-height:1;color:var(--green-mid)}
.rail-card figcaption{margin-top:auto;padding-top:1rem;border-top:1px solid var(--line);font-size:1rem;line-height:1.45;color:var(--ink-soft)}
.rail-card figcaption strong{display:block;color:var(--ink);font-weight:600}

.rail.is-moving .rail-viewport{overflow:hidden;padding-inline-start:0}
.rail.is-moving .rail-track{animation:rail-loop var(--rail-dur,60s) linear infinite}
.rail.is-moving:hover .rail-track,
.rail.is-paused .rail-track,
.rail.is-offscreen .rail-track{animation-play-state:paused}
@keyframes rail-loop{to{transform:translateX(-50%)}}

/* ---- remedy pour: scroll-scrubbed frame sequence beside "Time to be properly heard"
   Desktop: video pinned in the LEFT column (sticky) while the text on the
   right scrolls past it; main.js scrubs the pour across that scroll.
   Phones: the video sits under the text and scrubs as it crosses the screen.
   Blend: the footage's backdrop is baked to the paper colour at encode (no
   mix-blend-mode: the sticky stage isolates blending, which is what left a
   white box). The feathered mask hides the last shade of difference. */
.pour-stage{display:flex;justify-content:center;margin-top:clamp(2rem,1.4rem + 2vw,3rem)}
.pour-video{
  display:block;height:auto;width:min(260px,62vw);aspect-ratio:9/16;
  /* Final frame: what shows before the frames load, without JS, or with
     reduced motion (main.js then never draws on the canvas). */
  background:var(--paper) url(media/pour/f060.webp) center/cover no-repeat;pointer-events:none;
  --pour-feather:radial-gradient(ellipse 50% 50% at 50% 50%,#000 72%,transparent 100%);
  -webkit-mask-image:var(--pour-feather);mask-image:var(--pour-feather);
}
@media (min-width:1001px){
  .pour-row{
    display:grid;grid-template-columns:minmax(0,.62fr) minmax(0,1.38fr);
    column-gap:clamp(2.5rem,1rem + 5vw,6rem);min-height:135vh;
  }
  .pour-row .statement{grid-column:2;grid-row:1;display:flex;flex-direction:column}
  .pour-row .statement-body{flex:1;grid-template-columns:1fr;align-content:space-between}
  .pour-row .statement-body p{max-width:52ch}
  .pour-stage{
    grid-column:1;grid-row:1;
    --stage-h:min(calc(100vh - var(--head-h) - 7rem),560px);
    position:sticky;top:calc(var(--head-h) + (100vh - var(--head-h) - var(--stage-h)) / 2);
    align-self:start;justify-content:flex-start;margin-top:0;height:var(--stage-h);
    /* line the pinned video up with the statement's top rule */
    padding-top:0;
  }
  .pour-video{height:100%;width:auto}
}

/* SEO: keyword line inside inner-page h1s, styled like the home .hero-kicker */
.h1-kicker{display:block;margin-bottom:.9rem;font-size:.95rem;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--green);line-height:1.4}

/* ===========================================================================
   PHONE RESTRUCTURE (<=760px)
   Sections recomposed for a narrow screen rather than just stacked: the
   booking CTA lands in the first screen, prices come before decoration, and
   nothing is shown half cut off at the screen edge.
   =========================================================================== */
@media (max-width:760px){
  /* Home hero: the header already carries the full lockup, so the hero logo
     steps down and the booking bar reaches the first screen. */
  .hero{--hero-overlap:2.5rem;padding-top:.75rem}
  .hero .hero-logo{width:min(160px,44vw)}
  .hero-media img{aspect-ratio:16/10}
  .hero-head{gap:1rem}
  /* The standfirst above already says "in Ely or online", so the bar's label
     drops and the bar becomes one full-width button. */
  .book-bar{padding:.4rem;margin-top:.25rem}
  .book-bar svg,.book-bar-text{display:none}
  .book-bar .btn{min-height:48px}

  /* Small inline links still get a 44px tap height. */
  .hero-foot a,.foot-base a{display:inline-block;padding-block:.65rem;margin-block:-.65rem}

  /* Pour: a smaller stage so the bottle doesn't leave a screen of empty paper. */
  .pour-video{width:min(190px,50vw)}
  #approach{padding-bottom:clamp(2.5rem,2rem + 4vw,3.5rem)}

  /* Testimonials: a swipeable rail with the next card peeking in, instead of
     an auto-scrolling ticker that slices cards at both edges (main.js only
     starts the ticker above 760px). */
  .words-head{margin-bottom:1.6rem}
  .rail-toggle{display:none}
  .rail-viewport{
    scroll-snap-type:x mandatory;scroll-padding-inline:var(--pad);
    padding-inline:var(--pad);scrollbar-width:none;
    /* Right edge only: the peeking card softens out, the current one stays whole. */
    -webkit-mask-image:linear-gradient(90deg,#000 82%,transparent);
            mask-image:linear-gradient(90deg,#000 82%,transparent);
  }
  .rail-viewport::-webkit-scrollbar{display:none}
  .rail-card{width:calc(100vw - (var(--pad) * 2) - 2.5rem);scroll-snap-align:start}
  .rail-set{padding-right:var(--pad)}

  /* Services: prices first, the photograph after them as a short band. */
  #fees .split-copy{order:-1}
  #fees .split-media img,#support .split-media img{aspect-ratio:16/10}

  /* Fee card: name and price share the top line, the note gets full width. */
  .fee{grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:.35rem 1rem}
  .fee-price{grid-row:1;font-size:1.7rem}
  .fee-note{grid-column:1 / -1}

  /* Booking rows: name over length on the left, a compact button on the
     right, the same shape for every row. */
  .book-row{flex-wrap:nowrap;padding:1rem 1rem 1rem 1.15rem;gap:1rem}
  .book-row-text{flex-direction:column;align-items:flex-start;gap:.15rem}
  .book-row .btn{flex:none;min-width:6rem}

  /* iOS Safari: dvh tracks the collapsing address bar, vh does not. */
  .nav{max-height:calc(100dvh - var(--head-h))}
}

/* ===== Blog + doula (added for the Sanity build) ===== */
.doula{max-width:var(--measure)}
.doula>*+*{margin-top:1.35rem}
.post-head{max-width:var(--measure)}
.post-meta{font-size:.9rem;color:var(--ink-soft);letter-spacing:.02em}
.post-meta a{color:inherit}
.post-list{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,320px),1fr));gap:clamp(1rem,.7rem + 1vw,1.6rem)}
.post-card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);overflow:hidden;box-shadow:var(--shadow-soft);transition:box-shadow var(--t-mid) var(--ease),transform var(--t-mid) var(--ease)}
.post-card:hover,.post-card:focus-within{box-shadow:var(--shadow-lift);transform:translateY(-2px)}
.post-card-link{display:flex;flex-direction:column;height:100%;color:inherit;text-decoration:none}
.post-card-img{width:100%;aspect-ratio:3/2;object-fit:cover}
.post-card-body{padding:clamp(1.25rem,1rem + 1vw,1.8rem);display:flex;flex-direction:column;gap:.7rem;flex:1}
.post-card-body h2{font-size:clamp(1.25rem,1.1rem + .6vw,1.6rem);line-height:1.25}
.post-card-body p{margin:0}
.post-more{margin-top:auto;padding-top:.6rem;color:var(--green);font-weight:600}
.post-hero{margin:0 auto clamp(2rem,1.4rem + 2vw,3.2rem);max-width:980px}
.post-hero img{width:100%;border-radius:var(--r)}
.post-body{margin-inline:auto}
.post-body>*+*{margin-top:1.25rem}
.post-body h2{margin-top:2.4rem;font-size:clamp(1.5rem,1.3rem + .8vw,2rem)}
.post-body h3{margin-top:2rem;font-size:clamp(1.2rem,1.1rem + .5vw,1.5rem)}
.post-body ul,.post-body ol{padding-left:1.4rem}
.post-body li+li{margin-top:.4rem}
.post-body blockquote{margin-inline:0;padding:.2rem 0 .2rem 1.25rem;border-left:3px solid var(--green-mid);color:var(--ink-soft);font-style:italic}
.post-body a{color:var(--green);text-underline-offset:3px}
.post-fig{margin:2rem 0}
.post-fig img{width:100%;border-radius:var(--r)}
.post-fig figcaption{margin-top:.6rem;font-size:.9rem;color:var(--ink-soft)}
.post-back{max-width:var(--measure);margin:3rem auto 0}
