/* ==========================================================================
   Advanced Health Chiropractic - shared site styles
   Extracted from homepage/index.html on 6 October 2026 for the service pages.
   Holds everything the pages share: tokens, type, layout, buttons and links,
   header, nav, sheet, spine, motion, reviews, team, booking band, FAQ, footer
   and the dock. The homepage still carries its own inline copy of these rules
   plus its homepage-only sections (hero, statement, conditions, whole-body
   strip, journal). When it moves onto this file, those go to home.css.
   ========================================================================== */
/* Self-hosted so text doesn't wait on a second server. */
@font-face{font-family:"Hanken Grotesk";font-style:normal;font-weight:100 900;font-display:swap;src:url("fonts/hanken-grotesk-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+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Hanken Grotesk";font-style:normal;font-weight:100 900;font-display:swap;src:url("fonts/hanken-grotesk-latin-ext.woff2") format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}

/* ==========================================================================
   Advanced Health Chiropractic - homepage
   Tokens from tokens.json. Layout patterns from brand-book.md.
   ========================================================================== */
:root{
  --koru:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHIAAAAxCAQAAACsGDU0AAABg0lEQVR42u2aPy8EYRCHn5ctFAqFP7EKnVziK/gEPsQlIqGS6CQSopGgE4X6RCGiUWkUaLQiF9EJsg5HROISOeFVbC5U67h9z7yz9/u1m9l9MrOzM7tr8EUT5AjpZ4CQN0pE3HDNLEo0xy02wUXG/QZcS8T78h0zfgIuUa0TMXaZvG+IF78CrHnfH8DVPwHGrviBuNkAosXyLh9xo0HE2KK1kwqixTIm94loU7RQ2VR9XgvbLgjxlL5U43XzwZGsLE6nnEeRJVt2ArkuCXHSCaLlVdI9WaDXSdyAF4519tXvPpGCuOgQ0kop12VCh9HvjZBidantNvQrJwHS9T4/JAGyx3H8DgmQzq8hYOHfIUdcn8BI36K9KJUWZAsyNT1lAbKYBciDLHRXoz+TURYaTyELw4DRn8mtLIx1Rv8wsKJ/QD9jWDvkM136Vy2jf0A32reQCkb7qnVFp/Z9co9B3UvzA3lGafL3pGY6YoqEV5K+65Hdn/6SDDj0FK5KiUvm6zn0E4MgmJfbR6UEAAAAAElFTkSuQmCC");
  /* Neutrals. These used to scatter across hue 26-51 and three of them were
     within dE2000 2.5 of the reference site's own greys and cream, which is
     below the threshold the eye can tell apart. They now share one hue, ~37deg,
     which is where the original cream already sat - a warm stone, not a yellow.
     An earlier pass pushed this family to 50deg to buy distance from that
     reference palette and the result was sour: at this lightness you cannot win
     much separation anyway, and cream is the most convergent colour in editorial
     design, so it is weak evidence either way. The differentiation that matters
     is carried by sky, blush, the chassis and the link marker instead. The creams
     are a touch deeper and a touch less saturated than they were, so the bands
     read as a ground rather than as not-quite-white. surface stays pure white on
     purpose: it is the one neutral that should carry no tint, which is what lets
     the tinted ones read as a decision. */
  --surface:#ffffff; --surface-cream:#f6f3ee; --surface-warm:#efece7; --surface-ink:#32352c;
  --ink:#32352c; --ink-muted:#5f6357; --ink-inverse:#f7f5ef;
  --lime:#cbd300; --lime-press:#b6bd00; --lime-text:#4e5300;
  /* Sky sits at 191deg rather than a straight 205deg blue and blush at 14deg
     rather than 22deg: both were close enough to the reference palette to be
     indistinguishable by eye (dE2000 2.4 on the blue). Teal and dusty rose
     also sit better against a green ink and lime than a sky blue and apricot. */
  --sky:#b9d7de; --blush:#eec5b8; --on-field:#26291f;
  --line:#ded8cf; --line-strong:#7e7a6b; --focus:#2b6d92;

  --font-sans:"Hanken Grotesk",system-ui,-apple-system,"Segoe UI",sans-serif;

  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;
  --s7:48px; --s8:64px; --s9:96px; --s10:128px;
  /* viewport-fit=cover lets the page run under a phone's notch and rounded
     corners, so the gutter is never narrower than the safe area beside it */
  --gutter:max(24px,env(safe-area-inset-left,0px),env(safe-area-inset-right,0px));

  /* Chassis. These were 38 / 70 / 55, which were the reference site's own
     announcement, nav and gutter values and sat on no scale of ours. They now
     come off the 8px grid the rest of the system uses. */
  --promo-h:40px; --nav-h:64px;
  --ease:cubic-bezier(.22,.61,.36,1);
  --t:.5s var(--ease);
}
@media (min-width:768px){ :root{ --gutter:max(48px,env(safe-area-inset-left,0px),env(safe-area-inset-right,0px)); --nav-h:72px; } }
/* The spine rail starts at 744px (an iPad mini held upright), so the wider
   gutter starts there too: the rail sits in it and needs it clear. */
@media (min-width:744px) and (min-height:500px){ :root{ --gutter:max(48px,env(safe-area-inset-left,0px),env(safe-area-inset-right,0px)); } }
/* On a touch screen the band is 44px so its close button meets the target
   size; with a mouse it keeps its 40px. Dismissing it still zeroes this. */
@media (pointer:coarse){ :root{ --promo-h:44px; } }

*,*::before,*::after{box-sizing:border-box}
/* In-page jumps - the nav, the spine rail, every Book Now - land below the
   fixed promo band and header rather than under them. */
html{-webkit-text-size-adjust:100%;
  scroll-padding-top:calc(var(--promo-h) + var(--nav-h) + env(safe-area-inset-top,0px))}
body{
  margin:0; background:var(--surface); color:var(--ink);
  font-family:var(--font-sans); font-size:17px; line-height:26px; letter-spacing:-.005em;
  font-weight:400; -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img{display:block;max-width:100%}
a{color:inherit}
h1,h2,h3,h4,p,figure,blockquote{margin:0}
ul,ol{margin:0;padding:0;list-style:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}

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

/* ---------- feature switches ------------------------------------------
   Birthcare is a satellite arrangement that may be short- or long-term, so
   every piece of it on the page - the nav item in the header, sheet and
   footer, the banner item and the location block - carries
   data-feature="birthcare", and data-birthcare="on" on <html> shows them.
   Delete that attribute (or set it to anything else) and all of it goes at
   once; rename it in those places and the slot can carry something else, such
   as talks. */
html:not([data-birthcare="on"]) [data-feature="birthcare"]{display:none!important}

/* The promo band is off by default. Its two strongest facts (reviews, no
   referral) moved into the hero, and the rest repeated the proof band under
   it. It stays built for short announcements - such as "Now also at
   Birthcare" when that page launches: add data-promo="on" to <html> to bring
   it back, and the header and offsets follow --promo-h automatically. */
html:not([data-promo="on"]){--promo-h:0px}
html:not([data-promo="on"]) .promo{display:none}

/* ---------- type ------------------------------------------------------- */
.display-xl{font-family:var(--font-sans);font-weight:300;font-size:40px;line-height:42px;letter-spacing:-.03em}
.statement{font-family:var(--font-sans);font-weight:300;font-size:34px;line-height:36px;letter-spacing:-.03em}
.h2{font-family:var(--font-sans);font-weight:300;font-size:30px;line-height:34px;letter-spacing:-.025em}
.h3{font-family:var(--font-sans);font-weight:400;font-size:20px;line-height:25px;letter-spacing:-.02em}
.body-lg{font-size:18px;line-height:27px;letter-spacing:-.01em}
.body-sm{font-size:15px;line-height:23px}
.caption{font-size:13px;line-height:18px}
.overline{font-size:12px;line-height:16px;letter-spacing:.12em;font-weight:500;text-transform:uppercase}
.muted{color:var(--ink-muted)}
@media (min-width:768px){
  .display-xl{font-size:72px;line-height:70px}
  .statement{font-size:60px;line-height:60px}
  .h2{font-size:42px;line-height:46px}
  .h3{font-size:24px;line-height:28px}
  .body-lg{font-size:19px;line-height:28px}
}

/* ---------- layout ----------------------------------------------------- */
.wrap{max-width:1160px;margin:0 auto;padding-inline:var(--gutter)}
.section{padding-block:var(--s7)}
@media (min-width:768px){ .section{padding-block:var(--s9)} }
.rule{height:1px;background:var(--line);border:0;margin:0}

/* section head: heading left, hairline beneath, optional link right */
.sec-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s5);flex-wrap:wrap}
.sec-head .rule-anim{width:100%}
.rule-anim{height:1px;background:var(--line);transform-origin:0 50%;
  transition:transform 1s var(--ease);margin-top:var(--s4)}
.anim .rule-anim{transform:scaleX(0)}
.rule-anim.in{transform:scaleX(1)}
.rule-anim--strong{background:var(--line-strong)}

/* ---------- dot link / buttons ----------------------------------------- */
/* The marker is a single koru bar, the same masked artwork the spine rail draws,
   at the size the rail uses it. The artwork is drawn with its bulb on the right,
   so it needs no flip here: the heavy end faces the label and the tail runs away
   from it. It replaces a 9px dot that matched the reference site's own link
   component in every measurable respect - 9px dot, 10px gap, 16px label, -.02em -
   which is why the type around it moved to body-sm and a spacing token too.
   7px tall against an 11px cap height, so it sits inside the text's band. */
.dot-link{display:inline-flex;align-items:center;gap:var(--s3);font-size:15px;
  text-decoration:none;padding-block:6px;--dotc:var(--lime-text);--mark-w:14px;position:relative}
/* The link sets at 38px; this transparent margin takes the touch area to 44px
   without moving anything it sits beside. */
.dot-link::after{content:"";position:absolute;left:0;right:0;top:50%;height:max(100% + 6px,44px);transform:translateY(-50%)}
/* 14x6 rather than the rail's 16x7: the bar is solid across its whole width, so
   at rail size it put noticeably more ink on a page carrying eight of these.
   The form survives the reduction - the shape is a bar and a bulb, with no fine
   detail to lose. translateY(-1px) is an optical correction, not a layout one:
   the ink sits 0.72px below the middle of its own box, so centring the box
   leaves the mark reading low against the text. */
.dot-link::before{content:"";width:var(--mark-w);height:6px;flex:none;background:var(--dotc);
  transform:translateY(-1px);
  -webkit-mask:var(--koru) center/contain no-repeat;mask:var(--koru) center/contain no-repeat}
/* The label needed a move of its own. Its hover colour shift is a hue change at
   a near-identical lightness - 1.52:1 between the two - and small dark text is
   read by lightness, so the change was invisible and only the mark looked live.
   A rule wiping in from the left is the page's own gesture: every hairline here
   draws the same way, from transform-origin 0. It is deliberately not the label
   sliding sideways, which is the reference site's hover and the one motion
   signature worth staying away from. */
.dot-link span{position:relative}
.dot-link span::after{content:"";position:absolute;left:0;right:0;bottom:-3px;height:1px;
  background:currentColor;transform:scaleX(0);transform-origin:0 50%;
  transition:transform .45s var(--ease)}
.dot-link:hover span::after,.dot-link:focus-visible span::after{transform:scaleX(1)}

.btn{display:inline-flex;align-items:center;justify-content:center;gap:10px;
  border-radius:0;border:1px solid transparent;text-decoration:none;
  font-size:16px;line-height:16px;font-weight:500;letter-spacing:-.01em;
  padding:16px 34px;min-height:48px;
  transition:background-color var(--t),color var(--t),border-color var(--t)}
.btn--primary{background:var(--lime);color:var(--on-field)}

.btn--onDark{background:var(--surface);color:var(--ink)}

.btn--solid{background:var(--surface-ink);color:var(--ink-inverse)}
.btn--solid::after{background:var(--ink-muted)}
.btn--ghost{border-color:var(--line-strong);color:var(--ink)}

.btn--full{width:100%}

/* ---------- promo band -------------------------------------------------- */
.promo{position:fixed;inset:0 0 auto 0;z-index:60;height:var(--promo-h);padding-top:env(safe-area-inset-top,0px);box-sizing:content-box;
  background:var(--lime);color:var(--on-field);overflow:hidden;display:flex;align-items:center}
.promo__track{display:flex;flex:none}
.promo__viewport{display:flex;overflow:hidden;user-select:none;flex:1 1 auto;min-width:0;
  margin-right:calc(44px + env(safe-area-inset-right,0px))}
.promo__track{animation:marquee 44s linear infinite}
@keyframes marquee{from{transform:translateX(0)}to{transform:translateX(-100%)}}
.promo__items{display:flex;flex:none}
.promo__items li{white-space:nowrap}
.promo__items li::after{content:"";display:inline-block;vertical-align:middle;
  width:5px;height:5px;border-radius:50%;background:var(--on-field);opacity:.5;
  margin:0 28px 1px}
/* The marquee is clipped short of the close button rather than sliding under
   a lime patch painted over it. A second lime box could round a pixel off the
   band's own edge on some screens and show as a step in the corner; with the
   button transparent the band is the only thing drawing the edge. */
/* On desktop the band holds still. Across a wide screen the marquee kept five
   items moving in the corner of the eye and the practice found it busy; on a
   phone only one item shows at a time, so it stays there. Five items do not
   fit a 1024px row, so the static band carries the three that answer the
   questions people arrive with: when, whether they need a referral, and
   whether anyone rates it. */
.promo__static{display:none}
@media (min-width:1024px){
  .promo__viewport{display:none}
  .promo__static{display:flex;flex:1 1 auto;justify-content:center;
    margin-right:calc(44px + env(safe-area-inset-right,0px));padding-left:44px}
  .promo__static li:last-child::after{display:none}
}
.promo__close{position:absolute;right:env(safe-area-inset-right,0px);top:0;height:100%;min-width:44px;padding-inline:14px;
  display:grid;place-items:center;z-index:2}
.promo__close svg{width:12px;height:12px}

/* ---------- header ------------------------------------------------------ */
.header{position:fixed;left:0;right:0;top:calc(var(--promo-h) + env(safe-area-inset-top,0px));z-index:50;height:var(--nav-h);
  transition:background-color var(--t),color var(--t)}
/* backdrop under the transparent state so the nav clears 4.5:1 over any crop */
.header::after{content:"";position:absolute;inset:0 0 -60px 0;z-index:-1;pointer-events:none;
  background:linear-gradient(to bottom,rgba(38,41,31,.54) 0%,rgba(38,41,31,.36) 62%,transparent 100%);
  transition:opacity var(--t)}
.header.solid::after{opacity:0}
.header__grid{display:grid;grid-template-columns:auto 1fr;height:100%;align-items:stretch}
.header__brand{display:flex;align-items:center;padding-inline:var(--gutter);position:relative;text-decoration:none}
/* The supplied lockup at every width. Reversed artwork over the hero, full
   colour once solid. On a phone the header carries only the lockup and the
   menu button - Book Now is in the dock at the foot of the screen - so the
   wordmark has the room it needs at the same 152px the desktop uses. */
.brand-logo{display:block;background-repeat:no-repeat;background-position:left center;background-size:contain;
  width:152px;height:44px;background-image:url("logo-lockup-reversed.webp");transition:opacity var(--t)}
.header.solid .brand-logo{background-image:url("logo-lockup.webp")}
.header__right{display:flex;align-items:center;gap:30px;padding-inline:var(--gutter);position:relative}
.nav{display:none;gap:28px;align-items:center}
@media (min-width:1024px) and (max-width:1149px){ .nav{gap:20px} }
.nav a,.nav button{white-space:nowrap;font-size:16px;letter-spacing:-.02em;text-decoration:none;padding-block:9px;
  position:relative}
/* A hairline that draws in from the left, the same motif as the header edge and
   every section rule. It replaces the opacity fade: it reads as a clearer target,
   and because it persists while a panel is open it also says which menu is open. */
.nav a::after,.nav__parent::before{content:"";position:absolute;left:0;right:0;bottom:2px;
  height:1px;background:currentColor;transform:scaleX(0);transform-origin:0 50%;
  transition:transform .4s var(--ease)}
.nav a:hover::after,
.nav a[aria-current="page"]::after,
.nav__parent:hover::before,
.nav__parent[aria-expanded="true"]::before{transform:scaleX(1)}
.header__actions{margin-left:auto;display:flex;align-items:center;gap:var(--s5)}
/* Below bp-md Book Now leaves the header: the fixed dock at the foot of the
   screen and the foot of the menu sheet both carry it, and the hero has its
   own. From bp-md, where there is no dock, it is back in the bar. */
.header__actions .btn{display:none}
@media (min-width:768px){ .header__actions .btn{display:inline-flex} }
.header__tel{display:none;position:relative;font-size:16px;letter-spacing:-.02em;text-decoration:none;transition:opacity var(--t)}
.header__tel::after{content:"";position:absolute;inset:-9px 0}
.header__tel:hover{opacity:.62}

/* the two hairlines that draw themselves on load */
.header__edge{position:absolute;left:0;right:0;bottom:0;height:1px;background:currentColor;opacity:.3;z-index:2;
  transform-origin:0 50%;transition:transform 1.1s var(--ease) .25s}
.anim .header__edge{transform:scaleX(0)}
.header__wall{position:absolute;right:0;top:0;bottom:0;width:1px;background:currentColor;opacity:.3;
  transform-origin:50% 100%;transition:transform .8s var(--ease) .5s}
.anim .header__wall{transform:scaleY(0)}
.loaded .header__edge{transform:scaleX(1)}
.loaded .header__wall{transform:scaleY(1)}

/* over the hero: transparent, white. scrolled: solid, ink. */
.header{color:var(--ink-inverse);background:transparent}
.header.solid{color:var(--ink);background:var(--surface)}
.header.solid .header__edge,.header.solid .header__wall{opacity:1;background:var(--line)}

/* 44px square target; the negative margin keeps the three lines exactly
   where they sat when the button was only as wide as they are. */
.burger{display:grid;gap:5px;align-content:center;width:44px;height:44px;padding-inline:9px;margin-right:-9px}
.burger i{display:block;height:1px;background:currentColor;transition:transform var(--t),opacity var(--t)}
/* Open, the three lines fold into a cross where they stood, so the menu closes
   from the same spot it opened. The lines sit 6px apart centre to centre. */
.burger[aria-expanded="true"] i:nth-child(1){transform:translateY(6px) rotate(45deg)}
.burger[aria-expanded="true"] i:nth-child(2){opacity:0}
.burger[aria-expanded="true"] i:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
/* Four links and Book Now fit beside the lockup from 1024px, with about 80px
   to spare, so the nav takes over from the menu button there. Between 768 and
   1023 it once pushed Book Now off the screen. The phone number joins at
   1150px, where it sits clear of Resources on one row; below that it is in
   the dock, the booking band and the footer. Measured 8 October 2026, after
   Birthcare left the nav (it was 1100 and 1220 with five links). */
@media (min-width:1024px){
  .nav{display:flex}
  .burger{display:none}
}
@media (min-width:1150px){ .header__tel{display:inline} }

/* mobile sheet */
/* Shut, the sheet is hidden as well as moved off screen, so its links are
   out of the tab order and the accessibility tree. Visibility flips after the
   slide on the way out and at once on the way in. */
/* The sheet slides in under the header rather than over it: the lockup stays
   put, the menu button becomes its close, and the booking dock (z-index 55)
   rides over the foot of the sheet. Its bottom padding clears that dock. */
.sheet{position:fixed;inset:0;z-index:47;background:var(--surface);color:var(--ink);
  padding:calc(var(--promo-h) + var(--nav-h) + var(--s6)) var(--gutter)
          calc(56px + env(safe-area-inset-bottom,0px) + var(--s7));
  transform:translateY(-100%);visibility:hidden;overflow-y:auto;
  transition:transform .55s var(--ease),visibility 0s linear .55s}
.sheet[data-open="true"]{transform:translateY(0);visibility:visible;
  transition:transform .55s var(--ease),visibility 0s}
.sheet a{display:block;text-decoration:none;padding-block:var(--s4);border-bottom:1px solid var(--line);
  font-size:26px;font-weight:300;letter-spacing:-.025em}
/* Tablets have no dock, so the phone number sits under the last row there
   instead. The .sheet a rules above are for the list and are reset here. */
.sheet .sheet__call{display:none;margin-top:var(--s6);padding-block:6px;border-bottom:0;
  font-size:15px;font-weight:400;letter-spacing:normal}
@media (min-width:768px){ .sheet .sheet__call{display:inline-flex} }


/* ---------- nav dropdowns ------------------------------------------------
   Full-width panels dropping from under the header rather than small floating
   boxes. Parents are buttons: they have no page of their own. */
.nav__item{position:static;display:flex}
.nav__parent{display:inline-flex;align-items:center;gap:8px;position:relative;font-size:16px;letter-spacing:-.02em;padding-block:9px}
.nav__parent::after{content:"";width:6px;height:6px;flex:none;
  border-right:1px solid currentColor;border-bottom:1px solid currentColor;
  transform:rotate(45deg) translateY(-2px);transition:transform var(--t)}
.nav__parent[aria-expanded="true"]::after{transform:rotate(225deg) translateY(1px)}


.menu{position:fixed;left:0;right:0;
  top:calc(var(--promo-h) + env(safe-area-inset-top,0px) + var(--nav-h));
  background:var(--surface);color:var(--ink);
  box-shadow:0 8px 24px rgba(50,53,44,.16);padding-block:var(--s8);z-index:49;
  opacity:0;visibility:hidden;transform:translateY(-10px);pointer-events:none;
  transition:opacity .42s cubic-bezier(.33,1,.68,1),
             transform .52s cubic-bezier(.33,1,.68,1),
             visibility .52s}
/* The mega menus are desktop only; hidden here so phones skip their lazy-loaded photos. */
@media (max-width:1023px){ .menu{display:none} }
.menu.open{opacity:1;visibility:visible;transform:none;pointer-events:auto;
  transition:opacity .34s cubic-bezier(.33,1,.68,1),
             transform .46s cubic-bezier(.22,.61,.36,1),
             visibility .46s}
/* panel, then an aside that fills the dead right-hand space and gives the menu
   somewhere to put a CTA at a high-intent moment */
.menu__grid{display:grid;gap:var(--s7)}
@media (min-width:1024px){ .menu__grid{grid-template-columns:1fr 290px;gap:var(--s8)} }
.menu__row{display:grid;gap:var(--s5)}
@media (min-width:600px){ .menu__row{grid-template-columns:repeat(3,1fr)} }
@media (min-width:600px){ .menu__row--4{grid-template-columns:repeat(4,1fr)} }
@media (min-width:600px){ .menu__row--cards4{grid-template-columns:repeat(4,1fr)} }
/* The whole card responds, not just the title. On a card this dominated by a
   photograph, recolouring the smallest element is feedback you have to hunt for.
   The image is clipped by the link so the scale never escapes its box. */
.menu__row a{display:block;text-decoration:none;overflow:hidden}
.menu__row a:hover .h3{color:var(--lime-text)}
.menu__row a:hover img{transform:scale(1.05)}
/* transform-origin keeps the bar growing without shifting the text below it */
.menu__row a:hover .mm-field{transform:scaleY(1.9)}
/* the text-only Resources items lean on their rule instead of an image */
.menu__row--4 a:hover{border-top-color:var(--lime-text)}
.menu__row .h3{display:block;transition:color var(--t)}
.menu__row img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;
  transition:transform .7s var(--ease);
  margin-bottom:var(--s3)}
.menu__row .mm-field{display:block;height:5px;margin-bottom:var(--s3);
  transform-origin:50% 0;transition:transform .35s var(--ease)}
.menu__row--4 a{border-top:1px solid var(--line-strong);padding-top:var(--s3);
  transition:border-color var(--t)}
.menu__row p{margin-top:var(--s2)}
.menu__aside{padding-top:var(--s2)}
@media (min-width:1024px){
  .menu__aside{border-left:1px solid var(--line);padding-left:var(--s7);padding-top:0}
}
.menu__aside p{margin-top:var(--s3)}
.menu__aside .btn{margin-top:var(--s5)}
.menu__aside .dot-link{display:flex;margin-top:var(--s4)}
/* the Resources menu: the hub leads as one large card, with the blog, the
   podcast and the FAQs stacked beside it */
.menu__res{display:grid;gap:var(--s6)}
@media (min-width:1024px){ .menu__res{grid-template-columns:7fr 5fr;gap:var(--s8)} }
.menu__hub{display:grid;gap:var(--s5);text-decoration:none;color:inherit}
@media (min-width:600px){ .menu__hub{grid-template-columns:5fr 6fr;gap:var(--s6);align-items:start} }
.menu__hub-img{display:block;overflow:hidden}
.menu__hub img{display:block;width:100%;height:auto;aspect-ratio:4/5;object-fit:cover;object-position:50% 40%;transition:transform .7s var(--ease)}
.menu__hub:hover img{transform:scale(1.04)}
.menu__hub-text{display:flex;flex-direction:column;align-items:flex-start}
.menu__hub .h2{transition:color var(--t)}
.menu__hub:hover .h2{color:var(--lime-text)}
.menu__hub-lede{display:block;margin-top:var(--s3);max-width:40ch;font-size:17px;line-height:27px;color:var(--ink-muted)}
.menu__hub .dot-link{margin-top:var(--s5)}
.menu__hub:hover .dot-link span::after{transform:scaleX(1)}
.menu__res-list{display:grid;border-bottom:1px solid var(--line-strong)}
@media (min-width:1024px){ .menu__res-list{grid-template-rows:repeat(3,1fr)} }
.menu__res-list a{position:relative;display:block;padding-block:var(--s4);border-top:1px solid var(--line-strong);text-decoration:none}
/* hover: a lime rule draws across the top, and the title and its line slide in after it */
.menu__res-list a::before{content:"";position:absolute;left:0;right:0;top:-1px;height:2px;background:var(--lime-text);
  transform:scaleX(0);transform-origin:0 50%;transition:transform .55s var(--ease)}
.menu__res-list a:hover::before,.menu__res-list a:focus-visible::before{transform:scaleX(1)}
.menu__res-list .h3{display:block;transition:color var(--t),transform .45s var(--ease)}
.menu__res-list p{margin-top:var(--s2);transition:transform .45s var(--ease) 40ms}
.menu__res-list a:hover .h3,.menu__res-list a:focus-visible .h3{color:var(--lime-text);transform:translateX(8px)}
.menu__res-list a:hover p,.menu__res-list a:focus-visible p{transform:translateX(8px)}
@media (prefers-reduced-motion:reduce){
  .menu__res-list a::before{transition:none}
  .menu__res-list .h3,.menu__res-list p{transition:color var(--t);transform:none!important}
}
.nav-overlay{position:fixed;inset:0;z-index:48;background:rgba(38,41,31,.5);
  opacity:0;visibility:hidden;transition:opacity var(--t),visibility var(--t)}
.nav-overlay.open{opacity:1;visibility:visible}

/* mobile sheet groups */
/* padding-inline:0 clears the browser's own button padding, which set these
   two rows 6px in from the links between them */
.sheet__parent{display:flex;width:100%;align-items:center;justify-content:space-between;gap:var(--s5);
  padding-block:var(--s4);padding-inline:0;border-bottom:1px solid var(--line);font-size:26px;font-weight:300;letter-spacing:-.025em}
.sheet__parent .plus{position:relative;width:14px;height:14px;flex:none}
.sheet__parent .plus::before,.sheet__parent .plus::after{content:"";position:absolute;inset:50% 0 auto 0;height:1px;background:currentColor}
.sheet__parent .plus::after{transform:rotate(90deg);transition:transform .45s var(--ease)}
.sheet__parent[aria-expanded="true"] .plus::after{transform:rotate(0)}
.sheet__children{display:grid;grid-template-rows:0fr;transition:grid-template-rows .45s var(--ease)}
.sheet__parent[aria-expanded="true"]+.sheet__children{grid-template-rows:1fr}
.sheet__children>div{overflow:hidden;visibility:hidden;transition:visibility 0s linear .45s}
/* a collapsed group's links stay out of the tab order until it opens */
.sheet__parent[aria-expanded="true"]+.sheet__children>div{visibility:visible;transition:visibility 0s}
.sheet__children a{font-size:19px;padding-block:var(--s3);padding-left:var(--s5);border-bottom:1px solid var(--line)}


/* ---------- the spine ----------------------------------------------------
   The mark is a column of paired rounded bars with dots through it: vertebrae
   seen from behind. So the page gets a spine. One vertebra per section, fixed
   to the right edge. At rest it is a quiet dotted column; the section you are
   in opens its two bars, and the connector fills as you travel down.
   Inactive dots are line-strong and the active dot is ink, because lime at 8px
   is 1.6:1 - the green is a fill shape here, never the thing carrying meaning.

   It shows on every laptop and desktop, and not on phones, where there is no
   room for it beside the text, or on touch tablets (see below). The test is
   744px wide (an iPad mini upright) and 500px tall: the rail is about 250px
   tall and clears the header in a 500px window, which takes in the short
   viewports of scaled-up Windows laptops, and a phone on its side is never
   500px tall. Below 1240px the content's right margin is only the 48px gutter,
   so the rail drops to three-quarter size and tucks into the edge, where it
   clears the content by about 7px; from 1240px the margin has room for it at
   full size. */
.spine{display:none}
/* Mouse and trackpad only (decided 9 October 2026): the vertebrae sit 15px apart,
   too close to give each a 44px touch target without overlapping, so touch
   tablets go without the rail and scroll the page as phones do. */
@media (min-width:744px) and (min-height:500px) and (hover:hover) and (pointer:fine){
  .spine{display:block;position:fixed;right:2px;top:50%;transform:translateY(-50%) scale(.75);
    transform-origin:100% 50%;z-index:45}
  /* Touch tablets get the whole pitch between vertebrae as the target, not
     just the 18px glyph. */
  .spine__v::after{content:"";position:absolute;inset:-7px -4px}
  .spine__track{position:absolute;left:50%;top:6px;bottom:6px;width:1px;background:var(--line);
    transform:translateX(-50%)}
  .spine__fill{position:absolute;left:0;top:0;width:100%;height:0;background:var(--lime-text);
    transition:height .25s linear}
  .spine__list{position:relative;display:grid;gap:15px}
  .spine__v{display:flex;align-items:center;justify-content:center;gap:5px;height:18px;width:56px;
    position:relative}
  .spine__bar{display:block;width:16px;height:7px;flex:none;background:var(--ink);opacity:.3;
    -webkit-mask:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHIAAAAxCAQAAACsGDU0AAABg0lEQVR42u2aPy8EYRCHn5ctFAqFP7EKnVziK/gEPsQlIqGS6CQSopGgE4X6RCGiUWkUaLQiF9EJsg5HROISOeFVbC5U67h9z7yz9/u1m9l9MrOzM7tr8EUT5AjpZ4CQN0pE3HDNLEo0xy02wUXG/QZcS8T78h0zfgIuUa0TMXaZvG+IF78CrHnfH8DVPwHGrviBuNkAosXyLh9xo0HE2KK1kwqixTIm94loU7RQ2VR9XgvbLgjxlL5U43XzwZGsLE6nnEeRJVt2ArkuCXHSCaLlVdI9WaDXSdyAF4519tXvPpGCuOgQ0kop12VCh9HvjZBidantNvQrJwHS9T4/JAGyx3H8DgmQzq8hYOHfIUdcn8BI36K9KJUWZAsyNT1lAbKYBciDLHRXoz+TURYaTyELw4DRn8mtLIx1Rv8wsKJ/QD9jWDvkM136Vy2jf0A32reQCkb7qnVFp/Z9co9B3UvzA3lGafL3pGY6YoqEV5K+65Hdn/6SDDj0FK5KiUvm6zn0E4MgmJfbR6UEAAAAAElFTkSuQmCC") center/contain no-repeat;
    mask:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHIAAAAxCAQAAACsGDU0AAABg0lEQVR42u2aPy8EYRCHn5ctFAqFP7EKnVziK/gEPsQlIqGS6CQSopGgE4X6RCGiUWkUaLQiF9EJsg5HROISOeFVbC5U67h9z7yz9/u1m9l9MrOzM7tr8EUT5AjpZ4CQN0pE3HDNLEo0xy02wUXG/QZcS8T78h0zfgIuUa0TMXaZvG+IF78CrHnfH8DVPwHGrviBuNkAosXyLh9xo0HE2KK1kwqixTIm94loU7RQ2VR9XgvbLgjxlL5U43XzwZGsLE6nnEeRJVt2ArkuCXHSCaLlVdI9WaDXSdyAF4519tXvPpGCuOgQ0kop12VCh9HvjZBidantNvQrJwHS9T4/JAGyx3H8DgmQzq8hYOHfIUdcn8BI36K9KJUWZAsyNT1lAbKYBciDLHRXoz+TURYaTyELw4DRn8mtLIx1Rv8wsKJ/QD9jWDvkM136Vy2jf0A32reQCkb7qnVFp/Z9co9B3UvzA3lGafL3pGY6YoqEV5K+65Hdn/6SDDj0FK5KiUvm6zn0E4MgmJfbR6UEAAAAAElFTkSuQmCC") center/contain no-repeat;
    transition:opacity var(--t),transform var(--t)}
  .spine__v .spine__bar:last-child{transform:scaleX(-1)}
  .spine__dot{display:block;width:6px;height:6px;border-radius:50%;background:var(--line-strong);
    flex:none;transition:background-color var(--t),transform var(--t)}
  .spine__v:hover .spine__bar,
  .spine__v[aria-current="true"] .spine__bar{opacity:1}
  .spine__v[aria-current="true"] .spine__dot{background:var(--ink);transform:scale(1.25)}
  .spine__v:hover .spine__dot{background:var(--ink)}
  .spine__label{position:absolute;right:calc(100% + 6px);white-space:nowrap;font-size:12px;
    letter-spacing:.08em;text-transform:uppercase;color:var(--ink-muted);
    opacity:0;transform:translateX(4px);transition:opacity var(--t),transform var(--t);pointer-events:none}
  .spine__v:hover .spine__label,.spine__v:focus-visible .spine__label{opacity:1;transform:none}
  /* The rail inverts over any dark ground, not just the hero: the photograph,
     the ink band and now the footer. It crossfades on the shared timing rather
     than switching, so travelling past a boundary reads as the rail adjusting
     rather than as a repaint. lime-text is 1.6:1 on surface-ink, so the travel
     fill takes full lime there - it is a shape, and it has to stay visible. */
  .spine__track,.spine__fill,.spine__bar{transition:background-color var(--t)}
  .spine__bar{transition:opacity var(--t),transform var(--t),background-color var(--t)}
  .spine[data-on-dark="true"] .spine__track{background:rgba(247,246,240,.34)}
  .spine[data-on-dark="true"] .spine__fill{background:var(--lime)}
  .spine[data-on-dark="true"] .spine__dot{background:rgba(247,246,240,.72)}
  .spine[data-on-dark="true"] .spine__bar{background:var(--ink-inverse)}
  .spine[data-on-dark="true"] .spine__v[aria-current="true"] .spine__dot,
  .spine[data-on-dark="true"] .spine__v:hover .spine__dot{background:var(--ink-inverse)}
  .spine[data-on-dark="true"] .spine__label{color:var(--ink-inverse)}
}
@media (min-width:1240px) and (min-height:500px){ .spine{right:22px;transform:translateY(-50%)} }

/* Images carry width and height for layout stability; the CSS width and
   aspect-ratio win, so the height attribute must not pin the box. */
img[height]{height:auto}

/* ---------- hero -------------------------------------------------------- */
/* The homepage hero, shared from 8 October 2026 so the team page can use it.
   The homepage still carries its own inline copy. */
/* The top padding is the fixed promo band and header plus a step of air. On a
   tall screen it is empty space the type never reaches; on a landscape phone,
   390px tall, it makes the hero grow instead of sliding the headline up under
   the header. */
.hero{position:relative;min-height:100svh;display:flex;align-items:flex-end;isolation:isolate;overflow:hidden;
  padding-top:calc(var(--promo-h) + var(--nav-h) + var(--s5) + env(safe-area-inset-top,0px))}
.hero__bg{position:absolute;inset:0;z-index:-2}
.hero__bg img{width:100%;height:100%;object-fit:cover;object-position:46% 50%}
/* A portrait frame - a phone, or a tablet held upright - shows well under the
   photograph's full width, so it centres on the practitioner and the toddler.
   In a landscape frame almost the whole width is visible and the family sits
   right of the type. */
@media (orientation:landscape){ .hero__bg img{object-position:0% 50%} }
.hero__scrim{position:absolute;inset:0;z-index:-1;
  background:linear-gradient(to top,rgba(38,41,31,.82) 0%,rgba(38,41,31,.62) 22%,rgba(38,41,31,.46) 42%,rgba(38,41,31,.16) 62%,transparent 82%),
              linear-gradient(to bottom,rgba(38,41,31,.66) 0%,rgba(38,41,31,.40) 12%,rgba(38,41,31,.12) 26%,transparent 38%)}
/* grain - hides the upscale and reads as film, not noise */
.hero__grain{position:absolute;inset:0;z-index:-1;opacity:.22;pointer-events:none;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E")}
.hero__inner{position:relative;width:100%;padding:0 var(--gutter) var(--s8);color:var(--ink-inverse)}
@media (min-width:768px){ .hero__inner{padding-bottom:80px;max-width:76ch} }
.hero h1{margin-bottom:11px}
.hero p{max-width:46ch;font-weight:300;letter-spacing:-.01em;margin-bottom:var(--s6)}
.hero__actions{display:flex;align-items:center;gap:var(--s6);flex-wrap:wrap}
/* The two facts most likely to tip a booking, set quietly under the button
   they back up. Stars in lime, the only colour in the hero besides the photo. */
.hero p.hero__trust{max-width:none;margin:var(--s5) 0 0;font-size:14px;line-height:20px;letter-spacing:-.005em;
  color:rgba(247,246,240,.88);display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px}
.hero__trust .stars{color:var(--lime);letter-spacing:2px;font-size:13px}
.hero__trust i{font-style:normal;opacity:.6}
@media (max-width:479px){ .hero__trust i{display:none} .hero__trust span:last-child{flex-basis:100%} }
.hero__anchor{color:var(--ink-inverse);text-decoration:none;font-size:16px;letter-spacing:-.02em;position:relative;
  border-bottom:1px solid rgba(247,246,240,.5);padding-bottom:3px;transition:border-color var(--t)}
.hero__anchor::after{content:"";position:absolute;inset:-8px 0}
.hero__anchor:hover{border-color:var(--ink-inverse)}

/* ---------- page-load intro ----------------------------------------------
   Promo band drops in, then the header cascades left to right, with the hero
   line-masks running across the top of it. Every piece is gated on .anim, so
   under prefers-reduced-motion none of it is ever applied. */
.promo{transition:transform .75s var(--ease)}
.anim .promo{transform:translateY(-100%)}
.loaded .promo{transform:translateY(0)}

.header__brand,.nav>*,.header__tel,.header__actions .btn{
  transition:opacity .55s var(--ease),transform .55s var(--ease)}
.anim .header__brand,.anim .nav>*,.anim .header__tel,.anim .header__actions .btn{
  opacity:0;transform:translateY(-7px)}
.loaded .header__brand,.loaded .nav>*,.loaded .header__tel,
.loaded .header__actions .btn{opacity:1;transform:none}
.loaded .header__brand{transition-delay:.14s}
.loaded .nav>*:nth-child(1){transition-delay:.22s}
.loaded .nav>*:nth-child(2){transition-delay:.28s}
.loaded .nav>*:nth-child(3){transition-delay:.34s}
.loaded .nav>*:nth-child(4){transition-delay:.40s}
.loaded .header__tel{transition-delay:.46s}
.loaded .header__actions .btn{transition-delay:.52s}

/* line-mask reveal */
.mask{display:block;overflow:hidden}
.anim .mask>span{transform:translateY(105%);transition:transform 1.1s var(--ease)}
.mask>span{display:block}
.loaded .mask>span{transform:translateY(0)}
.loaded .mask:nth-of-type(1)>span{transition-delay:.30s}
.loaded .mask:nth-of-type(2)>span{transition-delay:.40s}
.anim .fade{opacity:0;transform:translateY(14px);transition:opacity .9s var(--ease),transform .9s var(--ease)}
.loaded .fade{opacity:1;transform:none}
.loaded .fade--1{transition-delay:.60s} .loaded .fade--2{transition-delay:.70s} .loaded .fade--3{transition-delay:.80s}

/* ---------- motion --------------------------------------------------------
   Four rules, all off under prefers-reduced-motion:
   1. siblings reveal in sequence, not all at once  2. images wipe rather than fade
   3. section headings rise out of a mask, echoing the hero  4. buttons fill by wipe */

/* 1. staggered reveal - --i is set per sibling group in JS */
.anim .rv{opacity:0;transform:translateY(16px);
  transition:opacity .7s var(--ease),transform .7s var(--ease);
  transition-delay:calc(var(--i,0) * 70ms)}
.rv.in{opacity:1;transform:none}

/* 2. images wipe up and settle out of a slight overscale */
.rv-img{overflow:hidden}
.anim .rv-img{clip-path:inset(0 0 100% 0);transition:clip-path 1s var(--ease);
  transition-delay:calc(var(--i,0) * 70ms)}
.anim .rv-img img{transform:scale(1.07);transition:transform 1.4s var(--ease);
  transition-delay:calc(var(--i,0) * 70ms)}
.rv-img.in{clip-path:inset(0 0 0 0)}
.rv-img.in img{transform:none}

/* 3. section headings rise out of a mask, the hero's move repeated quietly */
.anim .rv-h{clip-path:inset(-20% 0 100% 0);transform:translateY(.28em);
  transition:clip-path .9s var(--ease),transform .9s var(--ease)}
.rv-h.in{clip-path:inset(-20% 0 -20% 0);transform:none}

/* 3b. the statement rises a word at a time. This is one of the four named
   signature moments and the only place it is used; everything else that rises
   does so as a whole block (.rv-h). The words carry their own stagger through
   --w rather than the sibling --i, because they are one sentence arriving in
   order, not a group of elements cascading. */
.rv-words .w{display:inline-block;overflow:hidden;vertical-align:bottom;
  padding-bottom:.16em;margin-bottom:-.16em}
.anim .rv-words .w>span{display:inline-block;transform:translateY(110%);
  transition:transform .85s var(--ease);transition-delay:calc(var(--w,0) * 55ms)}
.rv-words.in .w>span{transform:none}

/* 4. buttons fill by wipe instead of cross-fade; the dot settles rather than blinks */
.btn{position:relative;isolation:isolate;overflow:hidden}
.btn::after{content:"";position:absolute;inset:0;z-index:-1;transform:scaleY(0);
  transform-origin:50% 100%;transition:transform .45s var(--ease)}
.btn:hover::after{transform:scaleY(1)}
.btn--primary::after{background:var(--lime-press)}
.btn--onDark::after{background:var(--surface-cream)}
.btn--ghost::after{background:var(--ink)}
.btn--ghost:hover{color:var(--ink-inverse);border-color:var(--ink)}
/* Rest is ink so the page stays calm; the green arrives on reach. lime-text is
   the token's documented job (links and eyebrows) and clears 4.5:1 on all three
   light grounds: 8.20 on surface, 7.67 on cream, 6.92 on warm. */
.dot-link{transition:color var(--t)}
.dot-link::before{transition:transform .45s var(--ease)}
.dot-link:hover{color:var(--lime-text)}
/* the dot's old hover, kept: the mark swells rather than sliding. The nudge
   rides along with it - transform is one property, so dropping it here would
   let the mark fall back a pixel on hover. */
.dot-link:hover::before{transform:translateY(-1px) scale(1.35)}

/* ---------- split ------------------------------------------------------- */
.split{display:grid;gap:var(--s7)}
@media (min-width:1024px){ .split{grid-template-columns:1fr 1fr;gap:var(--s8);align-items:start} }
.split__media img{width:100%;aspect-ratio:4/5;object-fit:cover;object-position:50% 30%}
/* Side by side, the photo runs the height of the text column so the two start
   and end together, but never taller than the screen below the fixed header
   (client review, October 2026). Square is its minimum: beside a short column
   the photo sets the height instead. With .pin it holds still while the text
   scrolls past; one photo per page at most, so scrolling never feels pinned. */
@media (min-width:1024px){
  .split__media.pin{position:sticky;top:calc(var(--promo-h) + var(--nav-h) + env(safe-area-inset-top,0px) + var(--s6))}
  .split__media{flex:1 0 auto;position:relative;aspect-ratio:1/1;
    max-height:calc(100vh - var(--promo-h) - var(--nav-h) - env(safe-area-inset-top,0px) - 2 * var(--s6))}
  /* min-height as well: with width/height attributes Chrome sizes the photo
     from its own ratio and ignores height:100% here */
  .split__media img{position:absolute;inset:0;height:100%;min-height:100%;aspect-ratio:auto}
}

/* numbered hairline list */
.steps{margin-top:var(--s6)}
.steps li{display:grid;grid-template-columns:auto 1fr;gap:var(--s5);padding-block:var(--s5);
  border-top:1px solid var(--line-strong)}
.steps li:last-child{border-bottom:1px solid var(--line-strong)}
.steps .n{font-size:13px;color:var(--ink-muted);padding-top:5px;font-variant-numeric:tabular-nums}

/* Book Now at its natural width with the phone beside it: two routes in, the
   button still the heavier of the two. Wraps under on a narrow phone. */
/* What happens after the first visit, set as a quiet note under the steps
   rather than a fifth step: the first visit is understanding and assessment
   only, and care begins at the second, the Report of Findings. */
.fv-next{margin-top:var(--s6);max-width:56ch}
.fv-cta{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s4) var(--s6);margin-top:var(--s6)}
/* Side by side, the two columns stretch to one height: the photo fills the
   left and the booking row drops to the foot of the right. */
@media (min-width:1024px){
  .split{align-items:stretch}
  .split>div{display:flex;flex-direction:column}
  .split .fv-cta{margin-top:auto;padding-top:var(--s6)}
  /* the UA's auto inline margins on <hr> stop it stretching in a flex column */
  .split .rule-anim{width:100%}
}


/* footer social + legal */
.footer__social{display:flex;flex-wrap:wrap;gap:var(--s5);margin-top:var(--s5)}
.footer__social a{font-size:15px;border-bottom:1px solid rgba(247,246,240,.4);padding-bottom:2px}
.footer__legal{display:flex;flex-wrap:wrap;gap:var(--s5)}
.footer .footer__legal a{font-size:13px}

/* ---------- service cards ----------------------------------------------- */
.cards{display:grid;gap:var(--s7);margin-top:var(--s7)}
@media (min-width:768px){ .cards{grid-template-columns:repeat(2,1fr);gap:var(--s7) var(--s5)} }
@media (min-width:1100px){ .cards{grid-template-columns:repeat(4,1fr);gap:var(--s5)} }
/* Each card is the link to its service page, and responds as the Keep
   exploring cards on the inner pages do. */
.card{display:block;text-decoration:none}
.card figure{overflow:hidden}
.card img{width:100%;aspect-ratio:4/3;object-fit:cover;transition:transform .7s var(--ease)}
.card:hover img{transform:scale(1.03)}
.card h3{transition:color var(--t)}
.card:hover h3,.card:focus-visible h3{color:var(--lime-text)}
/* Category fields. Colour does navigational work in this system: blush is
   pregnancy, sky is child and family, lime is the practice and adult care. A
   listing item declares its category with data-cat and the 6px field under the
   image picks it up, so a category reads the same on a blog listing as it does
   on a service card, here or on any later page. Anything outside the three
   service areas stays neutral rather than borrowing a loaded colour. */
[data-cat]{--cat:var(--line-strong)}
[data-cat="pregnancy"],[data-cat="postnatal"]{--cat:var(--blush)}
[data-cat="children"]{--cat:var(--sky)}
[data-cat="adults"],[data-cat="practice"],[data-cat="nervous-system"]{--cat:var(--lime)}
.card__field{height:6px;background:var(--cat,var(--line-strong))}
.card h3{margin-top:var(--s4)}
.card p{margin-top:var(--s2)}

/* ---------- field band --------------------------------------------------- */
.band{background:var(--surface-warm)}
.band--lime{background:var(--lime);color:var(--on-field)}
/* One dark band. The page is otherwise relentlessly light, and surface-ink is
   documented for exactly this - a quiet full-width statement - but was never used.
   "Our approach" is the only section that is pure argument rather than service or
   proof, so it is the one that earns the tonal anchor. */
.band--ink{background:var(--surface-ink);color:var(--ink-inverse)}
.band--ink .overline{color:var(--lime)}
.band--ink .rule-anim{background:rgba(247,246,240,.34)}
.band--ink .figure-cap figcaption{color:rgba(247,246,240,.66)}
.band--ink .dot-link{color:var(--ink-inverse)}
.band--ink .dot-link{--dotc:var(--lime)}
.band--ink .dot-link:hover{color:var(--lime)}

.band--sky{background:var(--sky);color:var(--on-field)}
.band__grid{display:grid;gap:var(--s7)}
@media (min-width:1024px){ .band__grid{grid-template-columns:5fr 7fr;gap:var(--s8)} }
.band__figs{display:grid;grid-template-columns:1fr;gap:var(--s5)}
/* Stacked on a phone the pair ran to two screens, so phones keep the scan alone. */
@media (max-width:599px){ .band__figs .figure-cap:nth-child(2){display:none} }
/* Caption under the image in plain sentence case at body-sm. Not turned on its
   side and not in uppercase micro-type - both were borrowed signatures. */
.figure-cap{display:flex;flex-direction:column;gap:var(--s3);min-width:0}
.figure-cap img{flex:1 1 auto;min-width:0;aspect-ratio:4/5;object-fit:cover}
@media (min-width:600px){
  /* The pair share the row and trade width on hover: the one you point at grows,
     the other yields. A fixed row height keeps the band from jumping as the
     widths animate - object-fit crops instead of the images changing height.
     The caption sits outside that height so the images stay the same size as
     each other however long the words are. */
  .band__figs{display:flex;align-items:stretch}
  .figure-cap{flex:1 1 0;transition:flex-grow .7s var(--ease)}
  .figure-cap img{height:clamp(320px,38vw,500px);width:100%;aspect-ratio:auto}
  /* The pair sits uneven at rest: the scan leads, because that is what the copy
     beside it is about, and the adjustment is held back until you point at it.
     Whichever one is not being pointed at yields to that same held-back width,
     so the two states use one value and the row never settles anywhere it has
     not already been. */
  .band__figs .figure-cap:nth-child(2){flex-grow:.55}
  .band__figs:hover .figure-cap{flex-grow:.55}
  .band__figs .figure-cap:hover,
  .band__figs .figure-cap:focus-within{flex-grow:1.6}
}
.figure-cap figcaption{font-size:15px;line-height:23px;color:var(--ink-muted)}
/* The practice's longer copy (October 2026) runs well past the pair. Left to
   stretch with the text column the photos became thin strips, so on a desktop
   the pair keeps its own height at the top of the column. */
@media (min-width:1024px){ .band__figs{align-self:start} }

/* ---------- proof -------------------------------------------------------- */
.proof{display:grid;grid-template-columns:1fr 1fr;gap:0}
@media (min-width:1024px){ .proof{grid-template-columns:repeat(4,1fr)} }
.proof li{min-width:0;padding:var(--s6) var(--s4);border-top:1px solid var(--line)}
@media (min-width:600px){ .proof li{padding-inline:var(--s5)} }
.proof li+li{border-left:1px solid var(--line)}
@media (max-width:1023px){ .proof li:nth-child(odd){border-left:0} }
.proof .fig{font-weight:300;font-size:clamp(30px,9.4vw,38px);line-height:1;letter-spacing:-.025em;display:flex;align-items:baseline;gap:6px}
.proof .fig small{font-size:15px;letter-spacing:-.01em}
.proof .lab{margin-top:var(--s3);color:var(--ink-muted)}
@media (min-width:768px){ .proof .fig{font-size:42px} }

/* ---------- reviews ------------------------------------------------------ */
.reviews{display:grid;gap:var(--s7);margin-top:var(--s7)}
@media (min-width:1024px){ .reviews{grid-template-columns:repeat(3,1fr);gap:var(--s5)} }
.review{border-top:1px solid var(--line-strong);padding-top:var(--s5)}
.review blockquote{font-family:var(--font-sans);font-weight:300;font-size:24px;line-height:31px;letter-spacing:-.015em}
@media (min-width:768px){ .review blockquote{font-size:28px;line-height:35px} }
.review figcaption{margin-top:var(--s5);color:var(--ink-muted)}
.stars{color:var(--lime-text);letter-spacing:.18em;font-size:13px}
.rating{display:flex;align-items:center;gap:var(--s3);text-decoration:none;position:relative;
  transition:opacity var(--t)}
a.rating::after{content:"";position:absolute;inset:-9px 0}
a.rating:hover{opacity:.62}
a.rating .body-sm{border-bottom:1px solid var(--line-strong);padding-bottom:2px}
.review blockquote{text-wrap:pretty}


/* reviews run as a horizontal rail, same mechanic as the koru strip: native
   scroll so it works without JS, arrows as an enhancement */
/* The rail runs off the right edge so a card is always part-visible, and the
   trailing edge fades while there is more to scroll. Both are affordances, not
   decoration: they are what tells someone the row continues. */
.revwrap{position:relative}
.revrail{overflow-x:auto;overflow-y:hidden;scrollbar-width:none;scroll-snap-type:x proximity;
  margin-top:var(--s7);margin-right:calc(-1 * var(--gutter));
  -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 96px),transparent 100%);
  mask-image:linear-gradient(to right,#000 calc(100% - 96px),transparent 100%);
  transition:-webkit-mask-image var(--t),mask-image var(--t)}
.revrail.is-end{-webkit-mask-image:none;mask-image:none}
.revrail::-webkit-scrollbar{display:none}
.revtrack{display:flex;gap:var(--s5);width:max-content;padding-right:var(--s8)}
.revtrack .review{flex:none;width:280px;scroll-snap-align:start;padding-top:var(--s5);
  border-top:1px solid var(--line-strong)}
@media (min-width:768px){ .revtrack .review{width:330px} }
.revtrack .review blockquote{font-size:20px;line-height:27px}
@media (min-width:768px){ .revtrack .review blockquote{font-size:22px;line-height:30px} }
/* Arrows sit on the rail edge rather than in the section head, so the control is
   where the motion is. Square and hairline rather than a floating pill, and no
   shadow: shadow-overlay is reserved for menus and the sticky bar. */
/* Native scrollbars are inconsistent across platforms and clumsy under a flat
   card row, but hiding one removes the only cue for *position*. This replaces it:
   a hairline track with a segment whose width is the proportion visible and whose
   offset is how far through you are. Same track-and-fill idea as the spine rail. */
.revprog{position:relative;height:2px;background:var(--line);margin-top:var(--s5);
  margin-right:calc(-1 * var(--gutter))}
.revprog span{position:absolute;left:0;top:0;height:100%;background:var(--ink);
  transition:transform .12s linear,width var(--t)}
/* One arrow, and no box on top of the copy. It sits inside the fade, so a bare
   chevron on a soft veil reads without a hard edge cutting through a quote.
   The 46px hit area stays for touch even though only the glyph is visible. */
.revarrow--prev{display:none}
.revarrow{position:absolute;top:50%;right:0;transform:translateY(-50%);z-index:3;
  width:46px;height:46px;display:none;place-items:center;border:0;color:var(--ink);
  background:radial-gradient(closest-side,var(--surface) 62%,rgba(255,255,255,0) 100%);
  transition:opacity var(--t),transform var(--t),visibility var(--t)}
.revarrow:hover{transform:translateY(-50%) translateX(3px)}
.revarrow svg{width:17px;height:17px}
.revarrow[disabled]{opacity:0;visibility:hidden;pointer-events:none}
@media (min-width:768px){ .revarrow--next{display:grid} }

/* The section ground stays white; the cards carry the colour instead. Alternating
   blush and sky - the two field colours that hold the same value in both themes,
   so on-field is legal on every card and the run reads as one system. */
.revband{background:var(--surface)}
/* A rule, not a box. The brand book separates with hairlines and colour rather
   than containers, and this is the same device the service cards use: a band of
   the field colour sitting above the content. Keeps the lift, drops the box. */
.revtrack .review{border-top:0;padding-top:var(--s5);color:var(--ink);position:relative}
.revtrack .review::before{content:"";position:absolute;inset:0 0 auto 0;height:5px;
  background:var(--blush)}
.revtrack .review figcaption{color:var(--ink-muted);margin-top:var(--s5)}
.revtrack .review .stars{display:block;margin-bottom:var(--s3);color:var(--lime-text);
  font-size:13px;letter-spacing:.2em}

/* ---------- team --------------------------------------------------------- */
.team{display:grid;grid-template-columns:1fr 1fr;gap:var(--s5);margin-top:var(--s7)}
@media (min-width:1024px){ .team{grid-template-columns:repeat(4,1fr)} }
.team img{width:100%;aspect-ratio:4/5;object-fit:cover;object-position:50% 22%;
  transition:transform .7s var(--ease)}
.team li{overflow:hidden}
.team li:hover img{transform:scale(1.03)}
.team figure{overflow:hidden}
.team h3{margin-top:var(--s4)}
/* each chiropractor is one link through to their profile on /meet-our-team/ */
.team__card{display:block;text-decoration:none;color:inherit}
.team__card .h3{transition:color var(--t)}
.team__card:hover .h3,.team__card:focus-visible .h3{color:var(--lime-text)}

/* ---------- booking and find us -----------------------------------------
   One band for "book" and "where". The booking panel takes the wider left
   column and comes first on phones, so the form is never pushed down by the
   map. The right column is reference: a map tile, the two places, then the
   hours set small - they are looked up, not read. */
.book__grid{display:grid;gap:var(--s8)}
.book__panel{background:var(--surface);color:var(--ink);padding:var(--s6)}
@media (min-width:768px){ .book__panel{padding:var(--s7)} }
/* The booking form takes the band's full width (9 October 2026): PracticeHub's form picks one or two
   columns from the window's width, not its own, so beside the map it was squeezed into two thin
   columns. The heading and form come first; the map, places and hours sit in a row beneath. The
   fallback panel (no form) keeps a readable measure. */
.book__panel{max-width:620px}
.book__panel.is-embed{max-width:none}
@media (min-width:1024px){
  .book__find{display:grid;grid-template-columns:7fr 5fr;column-gap:var(--s8);align-items:start}
  .book__find>.book__map{grid-row:1/span 3}
  .book__find>:not(.book__map){grid-column:2}
  .book__find .book__places{margin-top:0}
}
/* The form's slot holds just under its first-step height while it loads, so nothing below jumps,
   then lets go once the form is in so no gap is left under it (two options, measured 12 November
   2026: 523px at 390, 477 at 800, 449 at 1100, 404 at 1440; one column at 768px and below). */
.book__panel.is-embed>:first-child{min-height:520px}
@media (min-width:769px){ .book__panel.is-embed>:first-child{min-height:460px} }
@media (min-width:1024px){ .book__panel.is-embed>:first-child{min-height:400px} }
.book__panel.is-embed>:first-child:has(.phob--container){min-height:0}

/* PracticeHub's form, set in the site's palette: our one face, ink type, square corners, hairline
   borders instead of shadows, lime actions with ink text, and ink step dots. Its CSS is scoped
   under .phob--container and loads after ours, so these lead with .book__panel to win. */
.book__panel .phob--container,.book__panel .phob--container *:not(i):not(svg):not([class*="fa-"]){font-family:var(--font-sans)!important}
.book__panel .phob--container{color:var(--ink)}
.book__panel #phob__header_title h1,.book__panel #phob__header_page_title h2{font-weight:300;font-size:32px;letter-spacing:-.025em;color:var(--ink)}
.book__panel .phob--container h2,.book__panel .phob--practitioner-name,.book__panel .phob--cal-slots-day-title,
.book__panel #phob__booking-summary-title,.book__panel .phob--modality-header-text{font-weight:400;color:var(--ink)}
.book__panel .phob--sub-text,.book__panel #phob__progress,.book__panel .phob--step-indicator{color:var(--ink-muted)}
.book__panel .phob--card,.book__panel .phob--appt-type-card,.book__panel .phob--location-card,.book__panel .phob--practitioner-card,
.book__panel #phob__booking_summary,.book__panel .phob--cal-slots-wrapper,.book__panel .phob--modality-header{
  border-radius:0!important;box-shadow:none!important;border:1px solid var(--line)!important}
/* The cards you choose from get the strong hairline at rest (the light one is about 1.4:1 on
   white, too faint to read as a control) and darken to ink on hover. */
.book__panel .phob--appt-type-card,.book__panel .phob--location-card,.book__panel .phob--practitioner-card{border-color:var(--line-strong)!important}
.book__panel .phob--appt-type-card:hover,.book__panel .phob--location-card:hover,.book__panel .phob--practitioner-card:hover{border-color:var(--ink)!important}
.book__panel .phob--appt-type-card:focus-within,.book__panel .phob--location-card:focus-within,.book__panel .phob--practitioner-card:focus-within{outline:2px solid var(--focus);outline-offset:2px}
.book__panel .phob--btn,.book__panel .phob--btn-select-app-type,.book__panel .phob--btn-slot,.book__panel .phob--book-appointment-button{
  border-radius:0!important;box-shadow:none!important;background-color:var(--lime)!important;color:var(--on-field)!important;font-weight:500}
.book__panel .phob--btn:hover,.book__panel .phob--btn-select-app-type:hover,.book__panel .phob--btn-slot:hover{background-color:#b8bf00!important;opacity:1}
.book__panel .phob--btn:disabled{background-color:var(--line)!important;color:var(--ink-muted)!important}
.book__panel .phob--btn-choose-option,.book__panel .phob--summary-icon{border-radius:0!important;background-color:var(--surface-cream)!important;color:var(--ink)!important}
.book__panel .phob--step-dot,.book__panel .phob--progress-step{background-color:var(--line)}
.book__panel .phob--step-dot.phob--active,.book__panel .phob--progress-step.phob--active{background-color:var(--ink)}
.book__panel .phob--cal-has-availability{background-color:var(--lime)!important;color:var(--on-field)!important}
.book__panel .phob--cal-is-selected a{color:var(--ink)!important;border-color:var(--ink)!important}
.book__panel .phob--cal-is-today a{background:var(--surface-cream)!important;color:var(--ink)!important}
.book__panel .phob--input,.book__panel .phob--textarea,.book__panel .phob--sel-modality-id{border-radius:0!important;box-shadow:none!important;
  border:1px solid var(--line-strong)!important;font-size:16px!important;color:var(--ink)}
.book__panel .phob--input:focus,.book__panel .phob--textarea:focus,.book__panel .phob--sel-modality-id:focus{outline:2px solid var(--focus)!important;outline-offset:2px;border-color:var(--line-strong)!important}
.book__panel .phob--read-more-btn,.book__panel .phob--read-less-btn{border-radius:0!important;border-color:var(--ink)!important;color:var(--ink)!important}
.book__panel .phob--back-button{border-radius:0!important;border:1px solid var(--ink)!important;color:var(--ink)!important;background:none!important;box-shadow:none!important}
.book__panel .phob--modality-icon,.book__panel .phob--toggle-modality-icon,.book__panel .phob--modal-inner h2{color:var(--lime-text)!important}
.book__panel .phob--link,.book__panel .phob--terms-link{color:var(--ink)}
.book__panel .phob--customer-remember-me-input,.book__panel .phob--customer-terms-and-conditions-input{accent-color:var(--ink)}

/* "Prefer to ask a question first?" under the booking form: a cream row with its own label, so it
   reads as a second option without competing with booking. On the homepage it opens on click;
   on the contact page (.ask--open) it is shown open under its own heading. A line above the
   booking form (in its intro, "Ask us a question") opens and moves to it. Labels sit above their fields,
   inputs are 16px so phones don't zoom, and the send button spans the column below bp-md. */
/* the booking intro carries the other two routes: "Ask us a question" opens the row below the
   form, and the phone number calls */
.book__intro a{color:inherit;text-decoration:underline;text-decoration-color:var(--line-strong);text-underline-offset:4px;
  transition:text-decoration-color var(--t);position:relative}
.book__intro a:hover{text-decoration-color:currentColor}
.book__intro a::after{content:"";position:absolute;left:0;right:0;top:50%;height:44px;transform:translateY(-50%)}
/* On phones, step 1's booking summary only repeats the practice address (about 300px under the
   service cards), so it waits until a visit type is chosen. */
@media (max-width:768px){ .book__panel .phob--container:has(.phob--appt-type-card) #phob__booking_summary{display:none} }
.ask{margin-top:var(--s5);background:var(--surface-cream);scroll-margin-top:calc(var(--promo-h) + var(--nav-h) + var(--s4))}
.ask__toggle{display:flex;align-items:center;justify-content:space-between;gap:var(--s4);min-height:44px;
  padding:var(--s4) var(--s5);cursor:pointer;list-style:none}
.ask__toggle::-webkit-details-marker{display:none}
.ask__title{display:block;font-size:20px;line-height:26px;letter-spacing:-.015em;color:var(--ink);transition:color var(--t)}
.ask__toggle .body-sm,.ask__head .body-sm{display:block;margin-top:4px}
.ask__toggle:hover .ask__title{color:var(--lime-text)}
.ask__cta{display:inline-flex;align-items:center;gap:var(--s3);flex:none;font-size:15px;color:var(--ink)}
.ask__cta-text{display:none}
@media (min-width:600px){ .ask__cta-text{display:inline;text-decoration:underline;text-decoration-color:var(--line-strong);text-underline-offset:4px} }
.ask[open] .ask__cta-text{visibility:hidden}
.ask .plus{position:relative;width:14px;height:14px;flex:none}
.ask .plus::before,.ask .plus::after{content:"";position:absolute;inset:50% 0 auto 0;height:1px;background:currentColor}
.ask .plus::after{transform:rotate(90deg);transition:transform .45s var(--ease)}
.ask[open] .plus::after{transform:rotate(0)}
.ask__head{padding:var(--s5) var(--s5) var(--s4)}
.ask__form{padding:0 var(--s5) var(--s5)}
.ask__grid{display:grid;gap:var(--s4)}
@media (min-width:600px){ .ask__grid{grid-template-columns:1fr 1fr} .ask__field--wide{grid-column:1/-1} }
.ask__field>span{display:block;margin-bottom:6px;font-size:14px;line-height:20px;color:var(--ink)}
.ask__field input,.ask__field textarea{display:block;width:100%;min-height:48px;padding:12px 14px;border:1px solid var(--line-strong);
  border-radius:0;background:var(--surface);color:var(--ink);font:inherit;font-size:16px;line-height:22px}
.ask__field textarea{min-height:112px;resize:vertical}
.ask__field input:focus,.ask__field textarea:focus{outline:2px solid var(--focus);outline-offset:2px}
.ask__note{margin-top:var(--s3);max-width:62ch}
.ask__hp{position:absolute;left:-9999px;width:1px;height:1px;opacity:0}
.ask__error{margin-top:var(--s4);padding:10px 14px;background:#f7efdc;color:#6f4e00;font-size:15px;line-height:22px}
.ask__send{margin-top:var(--s4);width:100%}
@media (min-width:768px){ .ask__send{width:auto;min-width:220px} }
.ask__done{padding:var(--s4) var(--s5) var(--s5);font-size:17px;line-height:26px;color:var(--ink)}
.ask__done:focus{outline:none}

/* The map: West Auckland around the practice - streets, the Western Line and its
   stations, parks and the harbours - drawn from OpenStreetMap data in the palette
   (assets/map-glen-eden.svg). Labels are HTML over it in the site's own type, at
   percentages of the fixed 16:10 tile, so they hold their place at any width; the
   minor ones drop out when the tile is small. The practice is a plain ink dot with
   its name. The whole tile opens the practice's Google listing; the credit is the
   OpenStreetMap licence's. */
.book__map{display:block;position:relative;overflow:hidden;aspect-ratio:16/10;color:var(--ink);container-type:inline-size}
.book__map img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .7s var(--ease)}
.book__map:hover img{transform:scale(1.02)}
.map__labels{position:absolute;inset:0;pointer-events:none}
.map__sub,.map__road,.map__water{position:absolute;white-space:nowrap;line-height:1;transform:translate(-50%,-50%);
  text-shadow:0 0 3px #f4f5ee,0 0 3px #f4f5ee,0 0 2px #f4f5ee}
.map__sub{font-size:10px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:#5d6152}
.map__road{font-size:10px;color:var(--ink-muted);transform:translate(-50%,-50%) rotate(var(--r,0deg));text-shadow:0 0 3px #fff,0 0 3px #fff,0 0 2px #fff}
.map__water{font-size:11px;font-style:italic;letter-spacing:.02em;color:#557587;text-shadow:none}
.map__shield{position:absolute;transform:translate(-50%,-50%);padding:2px 5px;border:1px solid #8d917f;border-radius:3px;
  background:#fff;font-size:10px;line-height:12px;font-weight:500;color:var(--ink)}
@container (max-width:520px){ .map__minor{display:none} .book__flag{padding:5px 8px;font-size:10px} }
@container (min-width:760px){ .map__sub,.map__road{font-size:11px} .map__water{font-size:12px} }
.map__pin{position:absolute;display:flex;align-items:center;gap:8px;transform:translate(-7px,-50%)}
.map__pin b{flex:none;width:14px;height:14px;border-radius:50%;background:var(--ink);
  box-shadow:0 0 0 3px #fff,0 0 0 9px rgba(50,53,44,.14),0 2px 6px rgba(50,53,44,.3)}
.map__pin span{font-size:12px;line-height:14px;font-weight:500;color:var(--ink);white-space:nowrap;
  text-shadow:0 0 3px #fff,0 0 3px #fff,0 0 3px #fff,0 0 2px #fff}
.book__flag{position:absolute;left:var(--s3);bottom:var(--s3);z-index:1;isolation:isolate;overflow:hidden;
  display:inline-flex;align-items:center;gap:6px;background:var(--surface);
  padding:6px 10px;font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-muted);
  transition:color .45s var(--ease)}
/* hover: ink wipes in from the left, as on the site's buttons, and an arrow slides up to say
   it opens Google Maps in a new tab */
.book__flag::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--surface-ink);
  transform:scaleX(0);transform-origin:0 50%;transition:transform .45s var(--ease)}
.book__flag::after{content:"\2197";font-size:12px;line-height:1;letter-spacing:0;opacity:0;transform:translate(-3px,3px);
  transition:opacity .3s var(--ease),transform .45s var(--ease)}
.book__map:hover .book__flag,.book__map:focus-visible .book__flag{color:var(--ink-inverse)}
.book__map:hover .book__flag::before,.book__map:focus-visible .book__flag::before{transform:none}
.book__map:hover .book__flag::after,.book__map:focus-visible .book__flag::after{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){ .book__flag::before,.book__flag::after{transition:none} }
/* The data licence (ODbL) needs the credit on the map; this is the short form it allows, kept faint. */
.book__credit{position:absolute;right:6px;bottom:4px;font-size:9px;line-height:12px;color:var(--ink-muted);opacity:.75;
  text-shadow:0 0 3px #f4f5ee,0 0 3px #f4f5ee}

/* Glen Eden and Birthcare side by side under the map. Birthcare carries the
   feature switch, so turning it off leaves Glen Eden alone in the row. */
.book__places{display:grid;grid-template-columns:1fr 1fr;gap:var(--s5);margin-top:var(--s6)}
.book__place{border-top:1px solid var(--line-strong);padding-top:var(--s4)}
.book__place .addr{font-family:var(--font-sans);font-weight:300;font-size:19px;
  line-height:25px;letter-spacing:-.01em;margin-top:var(--s3)}

/* Directions and hours share one row under both places. The hours fold open
   beneath it at the column's full width, on the FAQ's grid-rows transition. */
.book__links{display:flex;flex-wrap:wrap;gap:var(--s3) var(--s6);margin-top:var(--s5)}
.book__hours-btn{background:none;border:0;padding:0;font:inherit;font-size:15px;color:inherit;cursor:pointer}
.book__hours-btn .plus{position:relative;width:10px;height:10px;flex:none;margin-left:var(--s1)}
.book__hours-btn .plus::before,.book__hours-btn .plus::after{content:"";position:absolute;inset:50% 0 auto 0;height:1px;background:currentColor}
.book__hours-btn .plus::after{transform:rotate(90deg);transition:transform .45s var(--ease)}
.book__hours-btn[aria-expanded="true"] .plus::after{transform:rotate(0)}
.book__hours{display:grid;grid-template-rows:0fr;transition:grid-template-rows .45s var(--ease)}
.book__hours[data-open="true"]{grid-template-rows:1fr}
.book__hours>div{overflow:hidden}
.hours{width:100%;border-collapse:collapse;margin-top:var(--s4)}
.hours th,.hours td{text-align:left;padding-block:6px;border-bottom:1px solid rgba(38,41,31,.18);
  font-size:13px;line-height:18px;font-weight:400}
.hours th{width:5.5ch}
.hours td{text-align:right;font-variant-numeric:tabular-nums}

/* ---------- faq ---------------------------------------------------------- */
.faq{margin-top:var(--s7)}
.faq li{border-top:1px solid var(--line-strong)}
.faq li:last-child{border-bottom:1px solid var(--line-strong)}
.faq button{display:flex;width:100%;gap:var(--s5);align-items:center;justify-content:space-between;
  text-align:left;padding-block:var(--s5)}
.faq .plus{position:relative;width:14px;height:14px;flex:none}
.faq .plus::before,.faq .plus::after{content:"";position:absolute;inset:50% 0 auto 0;height:1px;background:currentColor}
.faq .plus::after{transform:rotate(90deg);transition:transform .45s var(--ease)}
.faq [aria-expanded="true"] .plus::after{transform:rotate(0)}
.faq .a{display:grid;grid-template-rows:0fr;transition:grid-template-rows .45s var(--ease)}
.faq [aria-expanded="true"]+.a{grid-template-rows:1fr}
.faq .a>div{overflow:hidden;visibility:hidden;transition:visibility 0s .45s}
/* hidden once closed, so a collapsed answer's links leave the tab order and screen readers skip it */
.faq [aria-expanded="true"]+.a>div{visibility:visible;transition-delay:0s}
/* a heading's rule is the list's top edge, not a second line above it */
.sec-head:has(+.faq) .rule-anim{background:var(--line-strong)}
.sec-head+.faq{margin-top:0}
.sec-head+.faq>li:first-child{border-top:0}
.faq .a p{padding-bottom:var(--s5);max-width:68ch;color:var(--ink-muted)}
/* a list inside an answer reads as part of the answer, not as more question rows */
.faq .a ul{max-width:68ch;padding:0 0 var(--s5) 1.2em;list-style:disc;color:var(--ink-muted)}
.faq .a ul li{border:0;margin-top:var(--s2)}
.faq .a ul li:first-child{margin-top:0}
.faq .a ul strong{font-weight:500;color:var(--ink)}

/* ---------- footer ----------------------------------------------------- */
/* The footer takes surface-ink rather than a wash of sky. Sky is a category
   colour - it means child and family care on a card, a listing and a condition
   row - and spending it on the largest block of the page blunted that. The dark
   ground also gives the page a terminal edge it did not have. */
.footer{background:var(--surface-ink);color:var(--ink-inverse)}
.footer__grid{display:grid;gap:var(--s7)}
@media (min-width:768px){ .footer__grid{grid-template-columns:2fr 1fr 1fr 1fr} }
.footer h2{font-size:15px;font-weight:500;margin-bottom:var(--s4)}
.footer a{text-decoration:none;display:inline-block;padding-block:5px;font-size:15px;transition:opacity var(--t);position:relative}
/* footer links set at 33-37px; the touch area reaches 44px without opening up
   the columns */
.footer a::after{content:"";position:absolute;inset:-6px 0}
.footer a:hover{opacity:.6}
.footer__logo{width:208px;height:auto;margin-bottom:var(--s5)}
.footer__base{display:flex;flex-wrap:wrap;gap:var(--s5);justify-content:space-between;
  margin-top:var(--s8);padding-top:var(--s5);border-top:1px solid rgba(247,246,240,.34);font-size:13px}
.footer__credit a{display:inline;padding-block:0;font-size:inherit;text-decoration:underline;text-underline-offset:2px}
.footer__credit a::after{content:none}

/* ---------- sticky mobile booking bar (CRO) ------------------------------ */
.dock{position:fixed;left:0;right:0;bottom:0;z-index:55;display:grid;grid-template-columns:1fr 1fr;
  background:var(--surface);box-shadow:0 -8px 24px rgba(50,53,44,.16);
  transform:translateY(110%);transition:transform .45s var(--ease)}
.dock.up{transform:translateY(0)}
/* Each half carries the home-indicator inset itself, so Call stays white and
   Book Now stays lime right to the bottom edge instead of sitting on a strip
   of page background. The label stays centred in the 56px above it. */
.dock a{display:flex;align-items:center;justify-content:center;gap:8px;
  min-height:calc(56px + env(safe-area-inset-bottom,0px));padding-bottom:env(safe-area-inset-bottom,0px);
  text-decoration:none;font-size:16px;font-weight:500;letter-spacing:-.01em}
.dock a:first-child{color:var(--ink);border-right:1px solid var(--line)}
.dock a:last-child{background:var(--lime);color:var(--on-field)}
@media (min-width:768px){ .dock{display:none} }
/* The dock is fixed over the bottom of the screen on phones, so the footer
   carries its height: scrolled to the end, the last line sits above the dock,
   and what runs underneath it is the footer's own dark ground rather than a
   band of white page. */
.footer{padding-bottom:calc(56px + env(safe-area-inset-bottom,0px))}
@media (min-width:768px){ .footer{padding-bottom:0} }

.skip{position:absolute;left:-9999px;top:0;z-index:100;background:var(--ink);color:var(--ink-inverse);padding:12px 18px}
.skip:focus{left:0}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important}
  .mask>span,.fade,.rv,.rv-h,.rv-img,.rv-img img,.rv-words .w>span{transform:none!important;opacity:1!important;
    clip-path:none!important;transition-delay:0s!important}
  .btn::after{display:none}
  .rule-anim,.header__edge,.header__wall{transform:none!important}
}
