/* ==========================================================================
   FAMILY TREE DENTAL — THE DESIGN SYSTEM
   ---------------------------------------------------------------------------
   Loaded on EVERY page, immediately after style.css and before any page's own
   sheet. It holds three things and nothing else:

     1. the shared chrome — the utility bar and the services mega-menu, which
        are additions to the navigation pill that style.css already styles
     2. the shared furniture — eyebrows, headings, prose, links, chips,
        floating cards, the reveal entry states, the action dock
     3. the shared SECTIONS — the appointment band, the patient experience,
        the testimonials, the clinic panel, the closing call, the service
        cards, the treatment rail and the pager

   Anything that appears on more than one page lives here. Anything that
   appears on exactly one page lives in that page's own sheet
   (services-hub.css, service-detail.css). If you find yourself copying a rule
   from one page sheet to the other, it belonged here.

   Every token it reads — colour, family, shadow, easing, gutter, nav height,
   hero inset — is declared in style.css and is not repeated.

   Structure
   ---------------------------------------------------------------------------
   00. Page tokens
   01. Chrome: the utility bar
   02. Chrome: the services mega-menu
   03. Furniture: eyebrow, headings, prose, links, chips, floats
   04. Reveal entry states
   05. Hero (shared by the hub and every service page)
   06. The sticky section rail
   07. Service cards
   08. The treatment rail and the pager
   09. Appointment band
   10. Patient experience
   11. Testimonials
   12. Clinic location
   13. The closing call
   14. Footer additions
   15. The action dock
   16. Responsive
   17. Reduced motion / print
   ========================================================================== */


/* ==========================================================================
   00. PAGE TOKENS
   Scoped to .sv-body so nothing here can leak into a page that does not want
   it. The homepage carries the class too — it uses the same chrome.
   ========================================================================== */
:root {
  /* THE UTILITY BAR'S HEIGHT, and it is a root token rather than a local one
     because three separate things measure themselves against it: the pill's
     own top offset, the hero's top padding, and the mobile menu's anchor.
     Set to 0 and the bar disappears cleanly, taking its space with it. */
  --util-h: 40px;
}

.sv-body,
body {
  --sv-ivory:   #faf7f2;
  --sv-cream:   #f5efe6;
  --sv-ice:     #eaf3fd;
  --sv-white:   #ffffff;

  --sv-navy:    #06213a;
  --sv-navy-2:  #0b3b56;
  --sv-teal:    #0e4f5e;

  --sv-on-dark:      rgba(255, 255, 255, 0.94);
  --sv-on-dark-soft: rgba(214, 232, 251, 0.78);
  --sv-on-dark-hair: rgba(174, 207, 246, 0.24);

  /* ONE RADIUS LADDER, four rungs, sitting either side of the hero frame's
     signature 28px so a chip, a card and a photograph are visibly the same
     family at three different sizes. */
  --sv-r-xl: 34px;
  --sv-r-lg: 24px;
  --sv-r-md: 16px;
  --sv-r-sm: 12px;

  /* Narrower than style.css's 1440 on purpose: these pages are READ, and a
     1440px column of clinical copy is a column nobody finishes. */
  --sv-shell: min(1300px, 100% - 2 * var(--gutter));
  --sv-pad:   clamp(4rem, 10vh, 8rem);
  --sv-gap:   clamp(2.5rem, 5vw, 5rem);

  --sv-fs-h1: clamp(2.6rem, 1.1rem + 5vw, 5rem);
  --sv-fs-h2: clamp(1.95rem, 1.1rem + 2.9vw, 3.35rem);
  --sv-fs-h3: clamp(1.15rem, 0.95rem + 0.7vw, 1.5rem);

  --sv-card:      rgba(255, 255, 255, 0.86);
  --sv-card-brd:  rgba(120, 170, 225, 0.26);
  --sv-hair:      rgba(11, 45, 82, 0.09);
}

.sv-body { background: var(--sv-ivory); }


/* ==========================================================================
   01. CHROME — THE UTILITY BAR
   ---------------------------------------------------------------------------
   The strip above the pill. It carries the things you want ONCE, on arrival:
   the number, the forms link, the booking button.

   IT COLLAPSES THE MOMENT YOU SCROLL. `.is-scrolled` is already written to
   .nav by every page controller, so the bar rides that class rather than
   introducing a second scroll listener. A strip you have already read is a
   strip costing you 40px of a phone for the rest of the page — and once it
   is gone the pill sits at the top, exactly where it does on the homepage
   today.

   .nav BECOMES A COLUMN HERE. style.css lays it out as a centred row, which
   was right when the pill was the only thing in it. The override is confined
   to these four declarations so nothing else about the header changes.
   ========================================================================== */
.nav {
  display: block;
  padding-top: 0;
}

.util {
  height: var(--util-h);
  overflow: hidden;
  color: rgba(255, 255, 255, .92);
  background: linear-gradient(100deg, var(--c-blue-700) 0%, #1580b4 52%, var(--c-teal, #0c4a5c) 100%);
  transition: height var(--t-med) var(--ease-out),
              opacity var(--t-fast) var(--ease-out);
}
.nav.is-scrolled .util { height: 0; opacity: 0; }

.util__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: var(--util-h);
  width: min(1600px, 100% - 2 * clamp(1rem, 3vw, 2.5rem));
  margin-inline: auto;
  font-family: var(--f-ui);
  font-size: 0.79rem;
  font-weight: 500;
  letter-spacing: .02em;
}

.util__note {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: .9;
}
.util__dot {
  flex: none;
  width: 6px; height: 6px;
  background: var(--c-mint);
  border-radius: 50%;
  box-shadow: 0 0 0 3px rgba(127, 227, 212, .25);
}

.util__actions { display: flex; align-items: center; gap: clamp(.75rem, 1.8vw, 1.6rem); }

.util__link {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  white-space: nowrap;
  color: inherit;
  opacity: .92;
  transition: opacity var(--t-fast) var(--ease-out);
}
.util__link:hover { opacity: 1; }
.util__link svg { width: 14px; height: 14px; }

/* THE ONE WARM ACCENT IN THE CHROME. Small, and the only orange above the
   fold — the pill's own button is blue, so the two do not compete. */
.util__cta {
  display: inline-flex;
  align-items: center;
  height: 26px;
  padding-inline: .9rem;
  font-size: 0.73rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: #fff;
  background: var(--c-accent);
  border-radius: 100px;
  transition: background var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.util__cta:hover { background: #ff7d45; transform: translateY(-1px); }

/* The pill floats below the bar, at the hero frame's own inset. */
.nav__inner { margin-top: calc(var(--hero-inset) + var(--hero-pad)); }

/* A link that IS the page you are on. Marked, not just hoverable. */
.nav__link.is-active { color: var(--c-blue-900); }
.nav__link.is-active::after { transform: scaleX(1); }


/* ==========================================================================
   02. CHROME — THE SERVICES MEGA-MENU
   ---------------------------------------------------------------------------
   ONE PIECE OF MARKUP, TWO LAYOUTS. On a desktop it is a panel that drops
   from the pill: a feature column on the left, the two treatment families in
   columns on the right. Below 900px the same markup is an accordion inside
   the mobile menu — the category headings are real buttons in both cases, and
   chrome.js takes their tabindex away where they have nothing to toggle.

   IT IS AUTHORED OPEN. Every panel is visible in the markup and every
   aria-expanded starts "true", so with no JavaScript the mobile menu is a
   long but complete list of all fifteen treatments. chrome.js collapses it on
   arrival. Authored closed and opened by script is a menu that a script
   failure turns into a dead end.

   `visibility`, not `display`: a display change cannot transition, and
   without a transition the panel appears in one frame while the caret above
   it is still turning.
   ========================================================================== */
.nav__item--mega { position: static; }

.mega {
  position: absolute;
  top: calc(100% + 14px);
  left: 50%;
  z-index: 5;
  width: min(1080px, calc(100vw - 2 * (var(--hero-inset) + var(--hero-pad) + 12px)));
  padding: clamp(1.1rem, 1.8vw, 1.6rem);
  background: rgba(255, 255, 255, 0.96);
  border: 1px solid var(--glass-brd);
  border-radius: var(--sv-r-lg);
  box-shadow: 0 8px 24px rgba(11, 45, 82, .1), 0 40px 90px rgba(11, 45, 82, .18);
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  backdrop-filter: blur(24px) saturate(170%);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, -10px);
  transition: opacity var(--t-fast) var(--ease-out),
              transform var(--t-med) var(--ease-out),
              visibility var(--t-med);
}
/* Bridges the gap between the trigger and the panel so crossing it with the
   pointer does not drop the hover. */
.mega::before {
  content: "";
  position: absolute;
  inset: -14px 0 auto 0;
  height: 14px;
}
.nav__item--mega:hover .mega,
.nav__item--mega:focus-within .mega,
.nav__trigger[aria-expanded="true"] + .mega {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}

.mega__inner {
  display: grid;
  grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
  gap: clamp(1rem, 2vw, 1.75rem);
}

/* --- The feature column --------------------------------------------------- */
.mega__aside {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(1.1rem, 1.8vw, 1.5rem);
  overflow: hidden;
  color: #fff;
  border-radius: var(--sv-r-md);
  background:
    radial-gradient(80% 90% at 84% 8%, rgba(127, 227, 212, .22) 0%, rgba(127, 227, 212, 0) 60%),
    linear-gradient(150deg, var(--c-blue-700) 0%, var(--c-blue-900) 60%, #06213a 100%);
}
.mega__kicker {
  font-family: var(--f-ui);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--c-mint);
}
.mega__title {
  margin-top: .5rem;
  font-family: var(--f-display);
  font-size: 1.5rem;
  line-height: 1.14;
  letter-spacing: -0.012em;
}
.mega__text {
  margin-top: .5rem;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--sv-on-dark-soft);
}
.mega__all {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  align-self: flex-start;
  margin-top: 1rem;
  padding: .55rem 1rem;
  font-family: var(--f-ui);
  font-size: 0.83rem;
  font-weight: 500;
  color: #fff;
  background: rgba(255, 255, 255, .12);
  border: 1px solid rgba(255, 255, 255, .28);
  border-radius: 100px;
  transition: background var(--t-fast) var(--ease-out);
}
.mega__all svg { width: 16px; height: 16px; transition: transform var(--t-med) var(--ease-out); }
.mega__all:hover { background: rgba(255, 255, 255, .2); }
.mega__all:hover svg { transform: translateX(3px); }

.mega__media {
  margin-top: auto;
  padding-top: 1rem;
  overflow: hidden;
  border-radius: var(--sv-r-sm);
}
.mega__media img {
  width: 100%;
  aspect-ratio: 16 / 7;
  object-fit: cover;
  border-radius: var(--sv-r-sm);
  opacity: .82;
}

/* --- The two family columns ----------------------------------------------- */
.mega__cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(.75rem, 1.6vw, 1.5rem);
}

.mega__head { margin: 0 0 .4rem; }
.mega__toggle {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  padding: .45rem .6rem;
  font-family: var(--f-ui);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  text-align: left;
  color: var(--c-blue-700);
  border-bottom: 1px solid rgba(120, 170, 225, .35);
  border-radius: 0;
}
.mega__head-label { flex: 1 1 auto; min-width: 0; }
.mega__count {
  flex: none;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--c-blue-300);
  font-variant-numeric: var(--nums-tab);
}
/* The accordion's plus. Hidden on a desktop, where the panel never closes. */
.mega__sign { display: none; }

.mega__list { list-style: none; }

.mega__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .48rem .6rem;
  font-family: var(--f-ui);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--c-ink-soft);
  border-radius: 10px;
  transition: background var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out);
}
.mega__i {
  flex: none;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: .06em;
  color: var(--c-blue-300);
  font-variant-numeric: var(--nums-tab);
  transition: color var(--t-fast) var(--ease-out);
}
.mega__label { flex: 1 1 auto; min-width: 0; }
.mega__item svg {
  flex: none;
  width: 15px; height: 15px;
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity var(--t-fast) var(--ease-out),
              transform var(--t-med) var(--ease-out);
}
.mega__item:hover,
.mega__item:focus-visible {
  color: var(--c-blue-900);
  background: rgba(26, 114, 214, .08);
}
.mega__item:hover .mega__i { color: var(--c-accent); }
.mega__item:hover svg { opacity: 1; transform: translateX(0); }

/* The page you are on, marked in the menu that got you here. */
.mega__item.is-current {
  color: var(--c-blue-900);
  background: rgba(26, 114, 214, .1);
}
.mega__item.is-current .mega__i { color: var(--c-accent); }
.mega__item.is-current::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  width: 3px; height: 55%;
  background: var(--c-accent);
  border-radius: 2px;
  transform: translateY(-50%);
}


/* ==========================================================================
   02b. CHROME — THE SMALL DROPDOWNS
   ---------------------------------------------------------------------------
   About Us, and any other nav entry given a `menu` in config.php. The mega
   menu is the bespoke panel for fifteen services; this is the general case for
   two or three, and it is deliberately a different size rather than a smaller
   copy of the same composition.

   It opens on hover and on focus-within like the mega menu, and on
   aria-expanded, which is what chrome.js sets on a touch screen's first tap.
   Same three ways in, same `visibility` transition, same hover bridge.
   ========================================================================== */
.nav__item--drop { position: relative; }

.drop {
  position: absolute;
  top: calc(100% + 14px);
  left: 50%;
  z-index: 5;
  width: max(19rem, 100%);
  padding: .5rem;
  background: rgba(255, 255, 255, 0.96);
  border: 1px solid var(--glass-brd);
  border-radius: var(--sv-r-md);
  box-shadow: 0 8px 24px rgba(11, 45, 82, .1), 0 30px 70px rgba(11, 45, 82, .16);
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  backdrop-filter: blur(24px) saturate(170%);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, -10px);
  transition: opacity var(--t-fast) var(--ease-out),
              transform var(--t-med) var(--ease-out),
              visibility var(--t-med);
}
/* Bridges the gap to the trigger so crossing it does not drop the hover. */
.drop::before {
  content: "";
  position: absolute;
  inset: -14px 0 auto 0;
  height: 14px;
}
.nav__item--drop:hover .drop,
.nav__item--drop:focus-within .drop,
[data-drop-trigger][aria-expanded="true"] + .drop {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}

.drop__list { margin: 0; padding: 0; list-style: none; }

.drop__item {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0 .75rem;
  padding: .7rem .85rem;
  text-decoration: none;
  border-radius: var(--sv-r-sm);
  transition: background var(--t-fast) var(--ease-out);
}
.drop__item:hover,
.drop__item:focus-visible { background: rgba(26, 114, 214, .07); }

.drop__label {
  font-weight: 500;
  font-size: .98rem;
  color: var(--sv-navy-2);
  transition: color var(--t-fast) var(--ease-out);
}
.drop__item:hover .drop__label { color: var(--c-blue-700); }

/* The note is the reason the row is two lines tall. It says where the link
   goes, which is what a menu of two similar-sounding pages needs most. */
.drop__note {
  grid-column: 1;
  margin-top: .12rem;
  font-size: .78rem;
  line-height: 1.35;
  color: rgba(11, 45, 82, .58);
}

.drop__arrow {
  grid-row: 1 / -1;
  grid-column: 2;
  width: 18px; height: 18px;
  color: var(--c-blue-700);
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity var(--t-fast) var(--ease-out),
              transform var(--t-med) var(--ease-out);
}
.drop__item:hover .drop__arrow,
.drop__item:focus-visible .drop__arrow { opacity: 1; transform: translateX(0); }

.drop__item.is-current { background: rgba(26, 114, 214, .09); }
.drop__item.is-current .drop__label { color: var(--c-blue-700); }


/* ==========================================================================
   03. FURNITURE
   The handful of pieces that appear in five sections each, written once.
   ========================================================================== */

/* --- The eyebrow: a drawn rule, then the label ---------------------------- */
.sv-eyebrow {
  display: flex;
  align-items: center;
  gap: .75rem;
  font-family: var(--f-ui);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--c-blue-700);
}
.sv-eyebrow__rule {
  display: block;
  flex: none;
  width: clamp(28px, 4vw, 54px);
  height: 1.5px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--c-blue-500), var(--c-mint));
  transform: scaleX(0);
  transform-origin: 0 50%;
}
.sv-eyebrow--light { color: var(--c-mint); }
.sv-eyebrow--light .sv-eyebrow__rule {
  background: linear-gradient(90deg, var(--c-mint), rgba(127, 227, 212, 0));
}

/* --- Headings -------------------------------------------------------------
   The masks are the homepage's, so the reveal reads as the same gesture at a
   different size. `.line` clips; `.line__inner` rises through it.

   A LINE THAT WRAPS IS A LINE HALF SEEN — the mask is built for one visual
   row. Every heading is authored to its breaks in the component that emits
   it; re-check them at 1440, 1100 and 480 if copy changes.
   -------------------------------------------------------------------------- */
.sv-h1,
.sv-h2 {
  position: relative;
  font-family: var(--f-display);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: -0.016em;
  color: var(--c-ink);
}
.sv-h1 { font-size: var(--sv-fs-h1); }
.sv-h2 { font-size: var(--sv-fs-h2); }

/* EVERY HEADING BUILT BY heading() NEEDS THIS GROUP, whatever its own class
   is. Without it the `.line` spans stay inline: the authored breaks collapse
   into one running line, and — worse — there is no overflow to clip, so the
   reveal slides the words in over whatever sits above instead of lifting them
   out of a hidden edge. The page-specific titles are listed here rather than
   in their own stylesheets because more than one page now needs them, which
   is the rule includes/README.md sets for this file. */
.sv-h1 .line,
.sv-h2 .line,
.sv-hero__title .line,
.tm-hero__title .line,
.of-hero__title .line,
.of-intro__title .line,
.ct-hero__title .line,
.ct-consult__title .line,
.np-hero__title .line,
.rv-hero__title .line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.11em;
  margin-bottom: -0.07em;
}
.sv-h1 .line__inner,
.sv-h2 .line__inner,
.sv-hero__title .line__inner,
.tm-hero__title .line__inner,
.of-hero__title .line__inner,
.of-intro__title .line__inner,
.ct-hero__title .line__inner,
.ct-consult__title .line__inner,
.np-hero__title .line__inner,
.rv-hero__title .line__inner { display: block; }

.sv-h1 .word,
.sv-h2 .word,
.sv-hero__title .word,
.tm-hero__title .word,
.of-hero__title .word,
.of-intro__title .word,
.ct-hero__title .word,
.ct-consult__title .word,
.np-hero__title .word,
.rv-hero__title .word { display: inline-block; }

/* The one warm accent, exactly as the homepage uses it. */
.sv-h1 em,
.sv-h2 em,
.sv-hero__title em {
  position: relative;
  font-style: italic;
  color: var(--c-accent);
}
/* The nested form, used when a word carries punctuation the emphasis must
   not swallow. inline-block so the drawn rule inside it has a real box. */
.word__em { display: inline-block; }

.sv-h2--light { color: #fff; }
.sv-h2--light em { color: var(--c-mint); }

.word__rule {
  position: absolute;
  left: 0; right: 0; bottom: 0.06em;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--c-accent), rgba(255, 107, 44, 0));
  transform: scaleX(0);
  transform-origin: 0 50%;
}

/* --- Prose ---------------------------------------------------------------- */
.sv-lede {
  max-width: 46ch;
  margin-top: clamp(1.25rem, 2.4vw, 1.9rem);
  font-size: clamp(1.12rem, 1rem + 0.42vw, 1.32rem);
  line-height: 1.58;
  color: var(--c-ink);
}
.sv-p {
  max-width: 58ch;
  margin-top: 1.1rem;
  font-size: var(--fs-body);
  line-height: 1.72;
  color: var(--c-ink-soft);
}

/* --- The quiet link: the third action level ------------------------------- */
.sv-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  padding-bottom: .3rem;
  font-family: var(--f-ui);
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--c-blue-700);
  transition: color var(--t-fast) var(--ease-out);
}
.sv-link svg { width: 18px; height: 18px; transition: transform var(--t-med) var(--ease-out); }
.sv-link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1.5px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--c-blue-500), var(--c-mint));
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-med) var(--ease-out);
}
.sv-link:hover { color: var(--c-blue-900); }
.sv-link:hover::after { transform: scaleX(1); }
.sv-link:hover svg { transform: translateX(4px); }

/* --- Chips ---------------------------------------------------------------- */
.sv-chip {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .5rem .95rem;
  font-family: var(--f-ui);
  font-size: 0.79rem;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--c-blue-900);
  background: rgba(255, 255, 255, 0.82);
  border: 1px solid var(--glass-brd);
  border-radius: 100px;
  box-shadow: var(--sh-sm);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
}
.sv-chip svg { width: 15px; height: 15px; color: var(--c-accent); }
.sv-chip--solid {
  color: #fff;
  background: linear-gradient(135deg, var(--c-blue-500), var(--c-blue-700));
  border-color: transparent;
  box-shadow: 0 6px 18px rgba(26, 114, 214, .28);
}

/* --- The floating card: one component, many positions --------------------- */
.sv-float {
  position: absolute;
  z-index: 3;
  width: min(19rem, 82%);
  padding: clamp(1rem, 1.6vw, 1.35rem);
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid var(--glass-brd);
  border-radius: var(--sv-r-md);
  box-shadow: var(--sh-lg);
  -webkit-backdrop-filter: blur(20px) saturate(165%);
  backdrop-filter: blur(20px) saturate(165%);
}
.sv-float__mark {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  margin-bottom: .7rem;
  color: var(--c-blue-500);
  background: rgba(26, 114, 214, .09);
  border-radius: 11px;
}
.sv-float__mark svg { width: 22px; height: 22px; }
.sv-float__kicker {
  font-family: var(--f-ui);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--c-ink-faint);
}
.sv-float__title {
  margin-top: .1rem;
  font-family: var(--f-display);
  font-size: 1.16rem;
  line-height: 1.2;
  color: var(--c-blue-900);
}
.sv-float__title--lg { font-size: 1.6rem; }
.sv-float__text {
  margin-top: .4rem;
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--c-ink-soft);
}
.sv-float__text--tight { font-size: 0.858rem; }
.sv-float__text a { color: var(--c-blue-700); text-decoration: underline; text-underline-offset: 2px; }
.sv-float__text a:hover { color: var(--c-accent); }

/* A short list of links inside a floating card. Rows, not a run-on
   sentence — see the note where it is emitted. */
.sv-float__links { margin-top: .5rem; list-style: none; }
.sv-float__links li + li { margin-top: .3rem; }
.sv-float__links a {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-family: var(--f-ui);
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--c-blue-700);
  transition: color var(--t-fast) var(--ease-out), gap var(--t-fast) var(--ease-out);
}
.sv-float__links a::before {
  content: "";
  flex: none;
  width: 10px; height: 1.5px;
  background: currentColor;
  border-radius: 2px;
}
.sv-float__links a:hover { color: var(--c-accent); gap: .6rem; }

/* THE FLOAT IS WRITTEN ON `translate`, NOT `transform`, and that is the whole
   reason it can coexist with the reveal: site.js owns `transform` on these
   same elements. Two writers on one property trade it back and forth every
   frame; two writers on two composable properties simply stack. */
@keyframes sv-drift {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -9px; }
}
[data-float] { animation: sv-drift 7s ease-in-out infinite; }
[data-float]:nth-of-type(even) { animation-duration: 8.5s; animation-delay: -2.5s; }

/* --- The shade strip (decorative) ----------------------------------------- */
.sv-shade { display: flex; gap: 5px; }
.sv-shade i {
  display: block;
  width: 26px; height: 30px;
  background: var(--s);
  border: 1px solid rgba(11, 45, 82, .09);
  border-radius: 6px 6px 9px 9px;
  box-shadow: inset 0 -6px 10px rgba(11, 45, 82, .05);
}

/* --- Breadcrumb ----------------------------------------------------------- */
.sv-crumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  list-style: none;
  font-family: var(--f-ui);
  font-size: 0.81rem;
  font-weight: 500;
  color: var(--c-ink-faint);
}
.sv-crumbs li + li::before {
  content: "";
  display: inline-block;
  width: 4px; height: 4px;
  margin-right: .5rem;
  vertical-align: 2px;
  background: currentColor;
  border-radius: 50%;
  opacity: .45;
}
.sv-crumbs a { transition: color var(--t-fast) var(--ease-out); }
.sv-crumbs a:hover { color: var(--c-blue-700); }
.sv-crumbs [aria-current] { color: var(--c-blue-900); }


/* Present for a reader, absent for a viewer. Used where a section needs a
   heading for the document outline but the design carries its own title —
   see the doctor showcase on the Our Team page. Not `display:none`, which
   takes it out of the accessibility tree along with the layout. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}


/* ==========================================================================
   04. REVEAL ENTRY STATES
   ---------------------------------------------------------------------------
   Set here, not in JS, so there is no flash of the finished layout before the
   script runs. site.js removes `.no-js` in the same frame it writes the GSAP
   start values; if the script or GSAP never arrives, the class stays and
   everything below renders in its final state.

   THREE CHANNELS, and they never overlap:
     [data-sv]        opacity + y      the copy
     [data-sv-mask]   clip-path        the photographs
     .line__inner     yPercent + blur  the headlines (style.css already hides
                                       these globally)
   ========================================================================== */
[data-sv] { opacity: 0; }
/* Written in the four-value percentage form GSAP interpolates cleanly. */
[data-sv-mask] { clip-path: inset(0% 0% 100% 0%); }

.no-js [data-sv] { opacity: 1; }
.no-js [data-sv-mask] { clip-path: none; }
.no-js .sv-eyebrow__rule,
.no-js .sv-step__link,
.no-js .word__rule { transform: none; }
.no-js [data-float] { animation: none; }


/* ==========================================================================
   05. HERO — shared by the hub and by every service page
   ---------------------------------------------------------------------------
   NOT the homepage hero. That one is a full-bleed photograph with the type
   washed over it; this is an editorial split — ivory ground carrying the
   type on the left, a tall photograph carrying the floating cards on the
   right.
   ========================================================================== */
.sv-hero {
  position: relative;
  isolation: isolate;
  /* `clip`, not `hidden` — hidden on a section this tall would make it a
     scroll container and take the sticky rail below it with it. */
  overflow: clip;
  padding-top: calc(var(--util-h) + var(--nav-h) + var(--hero-inset) + var(--hero-pad) + clamp(1.5rem, 5vh, 3.5rem));
  padding-bottom: clamp(3.5rem, 9vh, 7rem);
  background:
    radial-gradient(90% 70% at 92% 4%, rgba(214, 232, 251, .8) 0%, rgba(214, 232, 251, 0) 58%),
    linear-gradient(168deg, var(--sv-ivory) 0%, #f6f5f2 38%, #eef5fd 100%);
}

.sv-hero__blob {
  position: absolute;
  top: -18%;
  right: -14%;
  z-index: -2;
  width: min(46vw, 640px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 40% 38%,
              rgba(127, 227, 212, .34) 0%,
              rgba(110, 178, 244, .22) 42%,
              rgba(110, 178, 244, 0) 70%);
  filter: blur(18px);
  pointer-events: none;
}

/* THE OVERSIZED WORD. Set at a size nobody is meant to read it at and an
   opacity nobody is meant to notice — it is grain, not copy. Most of it is
   under the floor of the section: what shows is the top third of the
   letterforms, which reads as texture along the seam. */
.sv-hero__word {
  position: absolute;
  left: -0.06em;
  bottom: -0.46em;
  z-index: -1;
  font-family: var(--f-display);
  font-size: clamp(6rem, 19vw, 17rem);
  font-style: italic;
  line-height: .8;
  letter-spacing: -0.03em;
  color: rgba(11, 45, 82, .038);
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
}

.sv-hero__inner {
  position: relative;
  z-index: 1;
  width: var(--sv-shell);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1.04fr) minmax(0, 0.96fr);
  align-items: center;
  gap: clamp(2rem, 4.5vw, 4.5rem);
}

.sv-hero__copy .sv-eyebrow { margin-top: clamp(1rem, 2.5vh, 1.6rem); }

.sv-hero__title {
  position: relative;
  margin-top: clamp(.9rem, 2vh, 1.4rem);
  font-family: var(--f-display);
  font-size: var(--sv-fs-h1);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.022em;
  color: var(--c-ink);
}
/* The hub's title is ONE WORD. It can afford to be much larger than a
   treatment name, and at this size it becomes the page's own graphic — so
   the accent rule is a direct child of the H1 rather than of an <em>, and
   spans the whole word. */
.sv-hero__title--hub {
  /* `width: max-content`, NOT `display: inline-block`. The box has to shrink
     to the word so the rule under it stops where the word does — but it must
     stay BLOCK level, or the strapline that follows it is inline-level too
     and the two share a line box. `max-width` keeps it inside the column on
     a narrow screen. */
  width: max-content;
  max-width: 100%;
  font-size: clamp(3.5rem, 1rem + 10vw, 9rem);
  line-height: .94;
}
.sv-hero__title--hub > .word__rule { bottom: .02em; height: 4px; }

.sv-hero__tag {
  display: inline-flex;
  align-items: center;
  gap: .7rem;
  margin-top: clamp(.9rem, 2vh, 1.35rem);
  font-family: var(--f-display);
  font-style: italic;
  font-size: clamp(1.05rem, 0.95rem + 0.45vw, 1.3rem);
  color: var(--c-blue-700);
}
.sv-hero__tag::before {
  content: "";
  width: 22px; height: 1.5px;
  background: var(--c-blue-300);
  border-radius: 2px;
}

.sv-hero__lede {
  max-width: 46ch;
  margin-top: clamp(1.1rem, 2.4vh, 1.6rem);
  font-size: var(--fs-body);
  line-height: 1.68;
  color: var(--c-ink-soft);
}

.sv-hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(.7rem, 1.4vw, 1rem);
  margin-top: clamp(1.5rem, 3.4vh, 2.25rem);
}
/* The homepage's breathing CTA, borrowed for the one primary action above
   the fold. The keyframes live in style.css. */
.sv-cta-breathe { animation: cta-breathe 5.5s ease-in-out infinite; }
.sv-cta-breathe:hover,
.sv-cta-breathe:focus-visible { animation: none; }

.sv-hero__facts {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.1rem, 2.6vw, 2.25rem);
  margin-top: clamp(1.9rem, 4vh, 2.75rem);
  padding-top: clamp(1.4rem, 3vh, 2rem);
  list-style: none;
  border-top: 1px solid var(--sv-hair);
}
.sv-hero__facts li { display: flex; flex-direction: column; gap: .3rem; }
.sv-hero__fact-n {
  font-family: var(--f-display);
  font-size: clamp(1.9rem, 1.2rem + 1.6vw, 2.7rem);
  line-height: 1;
  color: var(--c-blue-700);
  font-variant-numeric: var(--nums-tab);
}
.sv-hero__fact-n--word {
  font-style: italic;
  font-size: clamp(1.35rem, 0.9rem + 1.1vw, 1.9rem);
  color: var(--c-accent);
}
.sv-hero__fact-l {
  font-family: var(--f-ui);
  font-size: 0.79rem;
  font-weight: 500;
  letter-spacing: .04em;
  line-height: 1.45;
  color: var(--c-ink-faint);
}

.sv-hero__media { position: relative; }

.sv-hero__frame {
  position: relative;
  overflow: hidden;
  aspect-ratio: 1 / 1.12;
  border-radius: var(--sv-r-xl);
  /* A finished gradient behind the photograph, so a slow decode — or a file
     dropped by the [data-photo] guard — leaves a composed panel, not a box. */
  background:
    radial-gradient(80% 70% at 70% 30%, rgba(174, 207, 246, .9) 0%, rgba(174, 207, 246, 0) 62%),
    linear-gradient(120deg, #f4fafd 0%, #dceaf8 46%, #bcd8f2 100%);
  box-shadow: 0 30px 70px rgba(11, 45, 82, .16), 0 6px 18px rgba(11, 45, 82, .07);
}
.sv-hero__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 62% 42%;
  filter: contrast(1.04) saturate(1.05);
  transition: transform 1.4s var(--ease-soft);
}
.sv-hero__frame:hover .sv-hero__photo { transform: scale(1.03); }

.sv-hero__grade {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(6, 33, 58, .30) 0%, rgba(6, 33, 58, 0) 42%),
    linear-gradient(115deg, rgba(26, 114, 214, .12) 0%, rgba(26, 114, 214, 0) 45%);
  pointer-events: none;
}

.sv-hero .sv-chip--float {
  position: absolute;
  top: clamp(1rem, 3vw, 2rem);
  left: clamp(-1.5rem, -1.2vw, -0.5rem);
  z-index: 3;
}
.sv-float--benefit { left: clamp(-3.5rem, -4vw, -1rem); bottom: clamp(1.5rem, 4vw, 2.75rem); }
.sv-float--shade {
  right: clamp(-2.5rem, -3vw, -0.75rem);
  top: 26%;
  width: min(15rem, 68%);
}
.sv-float--shade .sv-float__text { margin-top: .65rem; }


/* ==========================================================================
   06. THE STICKY SECTION RAIL
   ---------------------------------------------------------------------------
   NAVIGATION, NOT DECORATION. It sticks UNDER the header pill: the offset is
   the pill's own height plus its inset, expressed in the pill's tokens so the
   two cannot drift. The utility bar is NOT in the sum — by the time the rail
   is stuck, the bar has collapsed.
   ========================================================================== */
.sv-jump {
  position: sticky;
  top: calc(var(--hero-inset) + var(--hero-pad) + 62px);
  z-index: 40;
  padding-block: clamp(1rem, 2vh, 1.5rem);
  background: linear-gradient(to bottom, rgba(238, 245, 253, .96) 62%, rgba(238, 245, 253, 0));
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.sv-jump__inner {
  width: var(--sv-shell);
  margin-inline: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .45rem .45rem .45rem 1.1rem;
  background: rgba(255, 255, 255, .92);
  border: 1px solid rgba(186, 214, 243, .6);
  border-radius: 100px;
  box-shadow: 0 2px 8px rgba(11, 45, 82, .05), 0 14px 34px rgba(11, 45, 82, .07);
  -webkit-backdrop-filter: blur(18px) saturate(165%);
  backdrop-filter: blur(18px) saturate(165%);
}
.sv-jump__list {
  display: flex;
  align-items: center;
  gap: clamp(.35rem, 1.4vw, 1.1rem);
  list-style: none;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.sv-jump__list::-webkit-scrollbar { display: none; }
.sv-jump__list a {
  display: block;
  padding: .55rem .85rem;
  font-family: var(--f-ui);
  font-size: 0.88rem;
  font-weight: 500;
  white-space: nowrap;
  color: var(--c-ink-soft);
  border-radius: 100px;
  transition: color var(--t-fast) var(--ease-out),
              background var(--t-fast) var(--ease-out);
}
.sv-jump__list a:hover { color: var(--c-blue-700); background: rgba(26, 114, 214, .07); }
.sv-jump__list a.is-active {
  color: var(--c-blue-900);
  background: rgba(26, 114, 214, .11);
}
.sv-jump__cta { flex: none; }


/* ==========================================================================
   07. SERVICE CARDS
   ---------------------------------------------------------------------------
   ONE COMPONENT, FOUR VARIANTS, and the difference between them is size and
   direction rather than a different set of parts. Every one is a whole-card
   <a>: the target is the size of the card on a phone, and the hover state has
   one owner instead of three competing ones.

     .svc--feature  the large card at the head of a category
     .svc--tile     the standard grid card, with a photograph
     .svc--type     the same card WITHOUT one — a typographic panel. Not a
                    fallback: eleven of the fifteen treatments have no picture
                    yet, and a grid that mixes photographic and typographic
                    cards reads as art direction, where a grid of grey
                    rectangles reads as a broken page.
     .svc--index    the full-width editorial row
     .svc--row      the horizontal rail card
   ========================================================================== */
.svc { list-style: none; }

.svc__link {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  border-radius: var(--sv-r-lg);
  background: var(--sv-white);
  border: 1px solid var(--sv-card-brd);
  box-shadow: var(--sh-sm);
  transition: transform var(--t-med) var(--ease-out),
              box-shadow var(--t-med) var(--ease-out),
              border-color var(--t-med) var(--ease-out);
}
.svc__link:hover {
  transform: translateY(-4px);
  border-color: var(--c-blue-300);
  box-shadow: var(--sh-lg);
}

.svc__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 16 / 10;
  background: linear-gradient(120deg, #dceaf8, #bcd8f2);
}
.svc__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.2s var(--ease-soft);
}
.svc__link:hover .svc__media img { transform: scale(1.06); }
.svc__tint {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(6, 33, 58, .28) 0%, rgba(6, 33, 58, 0) 55%);
  pointer-events: none;
}

.svc__body {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  padding: clamp(1.15rem, 2vw, 1.6rem);
}

/* THE NUMBER SHIFTS ON HOVER — up and out of the way, as the arrow comes in
   from the other side. It is the smallest possible acknowledgement that the
   card is a control. */
.svc__num {
  font-family: var(--f-ui);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: .16em;
  color: var(--c-blue-300);
  font-variant-numeric: var(--nums-tab);
  transition: color var(--t-med) var(--ease-out),
              transform var(--t-med) var(--ease-out);
}
.svc__link:hover .svc__num { color: var(--c-accent); transform: translateY(-2px); }

.svc__name {
  margin-top: clamp(.9rem, 2vw, 1.5rem);
  font-family: var(--f-display);
  font-size: var(--sv-fs-h3);
  font-weight: 400;
  line-height: 1.14;
  letter-spacing: -0.012em;
  color: var(--c-blue-900);
}
.svc__text {
  margin-top: .6rem;
  font-size: 0.925rem;
  line-height: 1.62;
  color: var(--c-ink-soft);
}

.svc__go {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  margin-top: auto;
  padding-top: clamp(1rem, 2vw, 1.4rem);
  font-family: var(--f-ui);
  font-size: 0.84rem;
  font-weight: 500;
  color: var(--c-blue-700);
}
.svc__go svg { width: 16px; height: 16px; transition: transform var(--t-med) var(--ease-out); }
.svc__link:hover .svc__go svg { transform: translateX(5px); }
/* The underline draws from the left rather than appearing. */
.svc__go::before {
  content: "";
  position: absolute;
  left: clamp(1.15rem, 2vw, 1.6rem);
  right: clamp(1.15rem, 2vw, 1.6rem);
  bottom: calc(clamp(1.15rem, 2vw, 1.6rem) - 6px);
  height: 1.5px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--c-blue-500), var(--c-mint));
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-med) var(--ease-out);
}
.svc__link:hover .svc__go::before { transform: scaleX(1); }

/* --- The featured card ---------------------------------------------------- */
.svc--feature .svc__link { border-color: transparent; }
.svc--feature .svc__media { aspect-ratio: 16 / 9; }
.svc--feature .svc__body {
  color: #fff;
  background:
    radial-gradient(80% 90% at 84% 8%, rgba(127, 227, 212, .2) 0%, rgba(127, 227, 212, 0) 60%),
    linear-gradient(150deg, var(--c-blue-700) 0%, var(--c-blue-900) 62%, #06213a 100%);
}
.svc--feature .svc__name {
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2.2rem);
  color: #fff;
}
.svc--feature .svc__text { color: var(--sv-on-dark-soft); max-width: 42ch; }
.svc--feature .svc__num { color: var(--c-mint); }
.svc--feature .svc__go { color: #fff; }
.svc--feature .svc__go::before { background: linear-gradient(90deg, var(--c-mint), rgba(127, 227, 212, 0)); }
.svc--feature .svc__link:hover .svc__num { color: var(--c-mint); }

/* --- The typographic card -------------------------------------------------
   No photograph, so the NAME becomes the artwork: larger, and given the room
   the picture would have taken. A quiet tint and an oversized ghost number
   keep it from reading as an empty slot.
   -------------------------------------------------------------------------- */
.svc--type .svc__link {
  background: linear-gradient(160deg, #f4f9ff 0%, var(--sv-white) 55%);
}
.svc--type .svc__body { padding-block: clamp(1.6rem, 3vw, 2.4rem); min-height: 13rem; }
.svc--type .svc__name {
  margin-top: clamp(1.6rem, 3.5vw, 3rem);
  font-size: clamp(1.35rem, 1rem + 1.1vw, 1.85rem);
}
.svc--type .svc__body::after {
  content: "";
  position: absolute;
  right: -8%;
  bottom: -22%;
  width: 58%;
  aspect-ratio: 1;
  border: 1px solid rgba(120, 170, 225, .28);
  border-radius: 50%;
  transition: transform var(--t-slow) var(--ease-out);
  pointer-events: none;
}
.svc--type .svc__link:hover .svc__body::after { transform: translate(-6px, -6px) scale(1.04); }

/* --- The editorial index row ----------------------------------------------
   A full-width row: number, name at display size, arrow. The photograph — if
   the treatment has one — is a preview that fades in on hover at the right,
   which is why it is absolutely placed and clipped to the row.
   -------------------------------------------------------------------------- */
.svc--index .svc__link {
  flex-direction: row;
  align-items: center;
  gap: clamp(1rem, 3vw, 2.5rem);
  padding: clamp(1.1rem, 2.4vw, 1.9rem) clamp(1rem, 2.4vw, 2rem);
  background: transparent;
  border: 0;
  border-top: 1px solid var(--sv-on-dark-hair);
  border-radius: 0;
  box-shadow: none;
  transition: background var(--t-med) var(--ease-out),
              padding-left var(--t-med) var(--ease-out);
}
.svc--index:last-child .svc__link { border-bottom: 1px solid var(--sv-on-dark-hair); }
.svc--index .svc__link:hover {
  transform: none;
  background: rgba(255, 255, 255, .06);
  padding-left: clamp(1.5rem, 3.4vw, 3rem);
}

.svc--index .svc__media {
  position: absolute;
  right: clamp(4rem, 9vw, 8rem);
  top: 50%;
  z-index: 1;
  width: clamp(7rem, 12vw, 11rem);
  aspect-ratio: 4 / 3;
  border-radius: var(--sv-r-sm);
  opacity: 0;
  transform: translateY(-50%) scale(.94) rotate(-2deg);
  transition: opacity var(--t-med) var(--ease-out),
              transform var(--t-med) var(--ease-out);
  pointer-events: none;
}
.svc--index .svc__link:hover .svc__media {
  opacity: 1;
  transform: translateY(-50%) scale(1) rotate(-2deg);
}
.svc--index .svc__tint { display: none; }

.svc--index .svc__body {
  flex-direction: row;
  align-items: baseline;
  gap: clamp(1rem, 3vw, 2.5rem);
  padding: 0;
}
.svc--index .svc__num { flex: none; color: rgba(174, 207, 246, .6); }
.svc--index .svc__link:hover .svc__num { color: var(--c-mint); transform: none; }
.svc--index .svc__name {
  flex: 1 1 auto;
  margin-top: 0;
  font-size: clamp(1.4rem, 0.9rem + 2vw, 2.6rem);
  line-height: 1.1;
  color: #fff;
  transition: transform var(--t-med) var(--ease-out);
}
.svc--index .svc__text { display: none; }
.svc--index .svc__go {
  flex: none;
  margin-top: 0;
  padding-top: 0;
  color: var(--sv-on-dark-soft);
}
.svc--index .svc__go span { display: none; }
.svc--index .svc__go svg { width: 22px; height: 22px; }
.svc--index .svc__go::before { display: none; }
.svc--index .svc__link:hover .svc__go { color: var(--c-mint); }

/* --- The rail card -------------------------------------------------------- */
.svc--row { flex: 0 0 clamp(14rem, 24vw, 19rem); scroll-snap-align: start; }
.svc--row .svc__media { aspect-ratio: 16 / 11; }
.svc--row .svc__body { padding: clamp(1rem, 1.6vw, 1.25rem); }
.svc--row .svc__name { margin-top: .9rem; font-size: 1.12rem; }
.svc--row .svc__go { padding-top: 1rem; font-size: 0.8rem; }
.svc--row.is-current .svc__link { border-color: var(--c-blue-300); }


/* ==========================================================================
   08. THE TREATMENT RAIL AND THE PAGER
   ---------------------------------------------------------------------------
   The rail SCROLLS SIDEWAYS rather than wrapping. Nine cards wrapped into
   three rows is a second services page at the bottom of a treatment page; one
   row you push is a suggestion.
   ========================================================================== */
.svc-rail {
  position: relative;
  z-index: 1;
  padding-block: clamp(3rem, 7vh, 5rem);
  background: var(--sv-white);
}
.svc-rail__inner { width: var(--sv-shell); margin-inline: auto; }
.svc-rail__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: clamp(1.5rem, 3vh, 2.25rem);
}
.svc-rail__title {
  font-family: var(--f-display);
  font-size: clamp(1.4rem, 1.1rem + 1vw, 2rem);
  color: var(--c-blue-900);
}
.svc-rail__hint {
  font-family: var(--f-ui);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--c-ink-faint);
}
.svc-rail__track {
  display: flex;
  gap: clamp(.9rem, 1.8vw, 1.4rem);
  list-style: none;
  /* The gutter is added back as padding so the first and last card can sit
     flush with the column while the strip itself bleeds to the page edge. */
  padding-bottom: .5rem;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.svc-rail__track::-webkit-scrollbar { display: none; }

/* --- The pager ------------------------------------------------------------ */
.svc-pager {
  position: relative;
  z-index: 1;
  background: var(--sv-white);
  border-top: 1px solid rgba(120, 170, 225, .3);
}
.svc-pager__inner {
  width: var(--sv-shell);
  margin-inline: auto;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.svc-pager__side {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  padding: clamp(1.5rem, 3vw, 2.5rem) clamp(1rem, 2vw, 1.75rem);
  transition: background var(--t-med) var(--ease-out);
}
.svc-pager__side:hover { background: #f5faff; }
.svc-pager__side--next { text-align: right; align-items: flex-end; border-left: 1px solid rgba(120, 170, 225, .3); }
.svc-pager__kicker {
  font-family: var(--f-ui);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--c-ink-faint);
}
.svc-pager__name {
  font-family: var(--f-display);
  font-size: clamp(1.1rem, 0.95rem + 0.6vw, 1.5rem);
  color: var(--c-blue-900);
}
.svc-pager__side svg { width: 20px; height: 20px; color: var(--c-blue-500); transition: transform var(--t-med) var(--ease-out); }
.svc-pager__side--prev svg { transform: rotate(180deg); }
.svc-pager__side--prev:hover svg { transform: rotate(180deg) translateX(5px); }
.svc-pager__side--next:hover svg { transform: translateX(5px); }


/* ==========================================================================
   09. APPOINTMENT BAND
   The visual pause between the clinical half of a page and the practice half.
   The photograph sits in an ORGANIC container — a four-value radius rather
   than one — so it reads as composed into the band, not dropped into a box.
   ========================================================================== */
.sv-break {
  position: relative;
  z-index: 1;
  padding-block: var(--sv-pad);
  background:
    radial-gradient(60% 80% at 8% 20%, rgba(127, 227, 212, .16) 0%, rgba(127, 227, 212, 0) 60%),
    linear-gradient(120deg, #e8f2fd 0%, #eef5fd 45%, #f7f4ee 100%);
}
.sv-break__inner {
  width: var(--sv-shell);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  align-items: center;
  gap: var(--sv-gap);
}
.sv-break__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 5 / 4;
  border-radius: clamp(2.5rem, 7vw, 6rem) var(--sv-r-lg) clamp(2.5rem, 7vw, 6rem) var(--sv-r-lg);
  background: linear-gradient(120deg, #dceaf8, #bcd8f2);
  box-shadow: 0 30px 70px rgba(11, 45, 82, .16);
}
.sv-break__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 42%;
  transition: transform 1.5s var(--ease-soft);
}
.sv-break__media:hover img { transform: scale(1.04); }
.sv-break__caption {
  position: absolute;
  left: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vw, 2rem);
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  padding: .6rem 1rem;
  font-family: var(--f-ui);
  font-size: 0.79rem;
  font-weight: 500;
  color: var(--c-blue-900);
  background: rgba(255, 255, 255, .9);
  border-radius: 100px;
  box-shadow: var(--sh-sm);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}
.sv-break__caption-dot {
  width: 7px; height: 7px;
  background: var(--c-accent);
  border-radius: 50%;
  box-shadow: 0 0 0 4px rgba(255, 107, 44, .16);
}
.sv-break__copy .sv-h2 { margin-top: clamp(1rem, 2vh, 1.5rem); }
.sv-break__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(.7rem, 1.4vw, 1rem);
  margin-top: clamp(1.75rem, 3.4vh, 2.5rem);
}


/* ==========================================================================
   10. PATIENT EXPERIENCE
   Copy left, a three-photograph collage right. One tall pair over one wide
   cell rather than three equal tiles — three equal tiles is the template look
   this site is trying not to be.
   ========================================================================== */
.sv-exp {
  position: relative;
  z-index: 1;
  padding-block: var(--sv-pad);
  background: var(--sv-white);
}
.sv-exp__inner {
  width: var(--sv-shell);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  align-items: center;
  gap: var(--sv-gap);
}
.sv-exp__copy .sv-h2 { margin-top: clamp(1rem, 2vh, 1.5rem); }

.sv-exp__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.1rem, 2.4vw, 1.9rem);
  margin-top: clamp(2rem, 4vh, 2.75rem);
  list-style: none;
}
.sv-exp__list li {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  padding-left: 1.1rem;
  border-left: 2px solid rgba(120, 170, 225, .4);
}
.sv-exp__n {
  font-family: var(--f-display);
  font-size: clamp(1.6rem, 1.2rem + 1.1vw, 2.2rem);
  line-height: 1.05;
  color: var(--c-blue-700);
  font-variant-numeric: var(--nums-tab);
}
.sv-exp__n--word { font-style: italic; color: var(--c-accent); }
.sv-exp__l {
  margin-top: .3rem;
  font-family: var(--f-ui);
  font-size: 0.79rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--c-blue-900);
}
.sv-exp__t { font-size: 0.9rem; line-height: 1.55; color: var(--c-ink-faint); }
.sv-exp__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(1rem, 2vw, 1.75rem);
  margin-top: clamp(2rem, 4vh, 2.75rem);
}

.sv-exp__cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(.75rem, 1.6vw, 1.25rem);
}
.sv-exp__card {
  position: relative;
  overflow: hidden;
  border-radius: var(--sv-r-lg);
  background: linear-gradient(120deg, #dceaf8, #bcd8f2);
  box-shadow: var(--sh-md);
}
.sv-exp__card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 22%;
  transition: transform 1.4s var(--ease-soft);
}
.sv-exp__card:hover img { transform: scale(1.05); }
.sv-exp__card--a,
.sv-exp__card--b { aspect-ratio: 1 / 1.1; }
.sv-exp__card--c { grid-column: 1 / -1; aspect-ratio: 16 / 8; }
.sv-exp__card--c img { object-position: 50% 28%; }

.sv-exp__card figcaption {
  position: absolute;
  left: .75rem; right: .75rem; bottom: .75rem;
  padding: .7rem .9rem;
  font-family: var(--f-display);
  font-size: 1rem;
  line-height: 1.2;
  color: var(--c-blue-900);
  background: rgba(255, 255, 255, .9);
  border-radius: var(--sv-r-sm);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
}
.sv-exp__card figcaption span {
  display: block;
  margin-bottom: .1rem;
  font-family: var(--f-ui);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--c-blue-700);
}


/* ==========================================================================
   11. TESTIMONIALS — the split
   ---------------------------------------------------------------------------
   Editorial column left, photograph right with the quote card straddling its
   corner. Not a centred carousel: a carousel puts the words and the proof in
   the same box and makes the section look like a widget.

   THE QUOTE CARD SITS BOTTOM-RIGHT because this photograph carries its own
   caption baked into the lower LEFT of the artwork. Move the card and you
   cover the words in the picture.
   ========================================================================== */
.sv-reviews {
  position: relative;
  z-index: 1;
  padding-block: var(--sv-pad);
  background: linear-gradient(180deg, #eef5fd 0%, #e6f0fb 100%);
}
.sv-reviews__inner {
  width: var(--sv-shell);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.06fr);
  align-items: center;
  gap: var(--sv-gap);
}
.sv-reviews__copy .sv-h2 { margin-top: clamp(1rem, 2vh, 1.5rem); }
.sv-reviews__lede {
  max-width: 46ch;
  margin-top: clamp(1rem, 2.2vh, 1.5rem);
  font-size: var(--fs-body);
  line-height: 1.7;
  color: var(--c-ink-soft);
}

.sv-reviews__stat {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  margin-top: clamp(1.6rem, 3vh, 2.25rem);
  padding-top: clamp(1.25rem, 2.6vh, 1.75rem);
  border-top: 1px solid rgba(120, 170, 225, .35);
}
.sv-reviews__stat-n {
  flex: none;
  font-family: var(--f-display);
  font-size: clamp(2.2rem, 1.4rem + 2vw, 3.2rem);
  line-height: 1;
  color: var(--c-blue-700);
  font-variant-numeric: var(--nums-tab);
}
.sv-reviews__stat-l {
  display: flex;
  flex-direction: column;
  font-family: var(--f-ui);
  font-size: 0.79rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--c-blue-900);
}
.sv-reviews__stat-l em {
  margin-top: .25rem;
  font-family: var(--f-sans);
  font-size: 0.86rem;
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--c-ink-faint);
}

.sv-reviews__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: clamp(1.5rem, 3vh, 2rem);
}
.sv-reviews__controls { display: flex; gap: .5rem; }
.sv-reviews__arrow {
  display: grid;
  place-items: center;
  width: 42px; height: 42px;
  color: var(--c-blue-700);
  background: rgba(255, 255, 255, .8);
  border: 1px solid var(--glass-brd);
  border-radius: 50%;
  transition: background var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.sv-reviews__arrow svg { width: 18px; height: 18px; }
.sv-reviews__arrow[data-review-prev] svg { transform: rotate(180deg); }
.sv-reviews__arrow:hover { background: #fff; transform: translateY(-2px); }

.sv-reviews__stage { position: relative; }
.sv-reviews__media {
  overflow: hidden;
  aspect-ratio: 4 / 3.4;
  border-radius: var(--sv-r-xl);
  background: linear-gradient(120deg, #dceaf8, #bcd8f2);
  box-shadow: 0 26px 60px rgba(11, 45, 82, .16);
}
.sv-reviews__media img { width: 100%; height: 100%; object-fit: cover; }

.sv-reviews__track {
  position: absolute;
  right: clamp(-2rem, -2.5vw, -0.75rem);
  bottom: clamp(-2.5rem, -3vw, -1rem);
  z-index: 3;
  width: min(24rem, 88%);
}
.sv-review {
  padding: clamp(1.25rem, 2.2vw, 1.75rem);
  background: rgba(255, 255, 255, .95);
  border: 1px solid var(--glass-brd);
  border-radius: var(--sv-r-lg);
  box-shadow: var(--sh-lg);
  -webkit-backdrop-filter: blur(18px) saturate(165%);
  backdrop-filter: blur(18px) saturate(165%);
}
.sv-review[aria-hidden="true"] { display: none; }
.sv-review__top { display: flex; align-items: center; gap: .75rem; }
.sv-review__g svg { width: 22px; height: 22px; }
.sv-review__stars { display: inline-flex; gap: 2px; }
.sv-review__stars svg { width: 15px; height: 15px; fill: var(--c-star); }

.sv-review__quote p {
  margin-top: .9rem;
  font-family: var(--f-display);
  font-size: clamp(1rem, 0.92rem + 0.4vw, 1.16rem);
  font-style: italic;
  line-height: 1.5;
  color: var(--c-ink);
}
.sv-review__by { display: flex; flex-direction: column; gap: .15rem; margin-top: 1rem; }
.sv-review__name {
  font-family: var(--f-ui);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--c-blue-900);
}
.sv-review__src { font-family: var(--f-ui); font-size: 0.76rem; color: var(--c-ink-faint); }


/* ==========================================================================
   12. CLINIC LOCATION
   The information panel OVERLAPS the photograph on a desktop — the overlap is
   what makes it one composition rather than a card beside a card.
   ========================================================================== */
.sv-visit {
  position: relative;
  z-index: 1;
  padding-block: var(--sv-pad);
  background:
    radial-gradient(70% 60% at 84% 10%, rgba(127, 227, 212, .14) 0%, rgba(127, 227, 212, 0) 60%),
    linear-gradient(170deg, #e6f0fb 0%, #eaf3fd 55%, #f3f8fd 100%);
}
.sv-visit__inner {
  width: var(--sv-shell);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  align-items: center;
  gap: var(--sv-gap);
}
.sv-visit__copy .sv-h2 { margin-top: clamp(1rem, 2vh, 1.5rem); }

.sv-visit__panel {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.25rem, 2.6vw, 2.25rem);
  margin-top: clamp(1.75rem, 3.6vh, 2.5rem);
  padding: clamp(1.4rem, 2.6vw, 2.1rem);
  background: rgba(255, 255, 255, .82);
  border: 1px solid var(--glass-brd);
  border-radius: var(--sv-r-lg);
  box-shadow: var(--sh-md);
  -webkit-backdrop-filter: blur(20px) saturate(165%);
  backdrop-filter: blur(20px) saturate(165%);
}
.sv-visit__label {
  font-family: var(--f-ui);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--c-blue-700);
}
.sv-visit__label + .sv-visit__line { margin-top: .6rem; }
.sv-visit__line + .sv-visit__label { margin-top: 1.4rem; }
.sv-visit__line {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  font-size: 0.935rem;
  line-height: 1.6;
  color: var(--c-ink-soft);
  font-variant-numeric: var(--nums-ui);
}
.sv-visit__line a { transition: color var(--t-fast) var(--ease-out); }
.sv-visit__line a:hover { color: var(--c-blue-700); }
.sv-visit__icon { flex: none; width: 18px; height: 18px; color: var(--c-blue-500); }
.sv-visit__icon svg { width: 18px; height: 18px; }
.sv-visit__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-top: 1.6rem;
}

.sv-hours { list-style: none; font-variant-numeric: var(--nums-tab); }
.sv-hours__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: .5rem 0;
  font-family: var(--f-ui);
  font-size: 0.855rem;
  border-bottom: 1px dashed rgba(120, 170, 225, .35);
}
.sv-hours__row:last-child { border-bottom: 0; }
.sv-hours__row span:first-child { color: var(--c-ink-soft); }
.sv-hours__row span:last-child { font-weight: 500; color: var(--c-blue-900); white-space: nowrap; }
.sv-hours__row--closed span:last-child { color: var(--c-ink-faint); font-weight: 400; }
.sv-hours__row.is-today { position: relative; padding-left: .8rem; }
.sv-hours__row.is-today::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  width: 4px; height: 60%;
  background: var(--c-accent);
  border-radius: 2px;
  transform: translateY(-50%);
}
.sv-hours__row.is-today span:first-child { color: var(--c-blue-900); font-weight: 500; }

.sv-visit__media { position: relative; }
.sv-visit__frame {
  overflow: hidden;
  aspect-ratio: 4 / 4.7;
  border-radius: var(--sv-r-xl);
  background: linear-gradient(120deg, #dceaf8, #bcd8f2);
  box-shadow: 0 30px 70px rgba(11, 45, 82, .16);
}
.sv-visit__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 42%;
  transition: transform 1.6s var(--ease-soft);
}
.sv-visit__frame:hover img { transform: scale(1.04); }

.sv-visit__inset {
  position: absolute;
  left: clamp(-3rem, -3.5vw, -1rem);
  bottom: clamp(4.5rem, 9vw, 7rem);
  z-index: 3;
  width: min(13rem, 46%);
  overflow: hidden;
  aspect-ratio: 4 / 3;
  border: 5px solid #fff;
  border-radius: var(--sv-r-md);
  box-shadow: var(--sh-lg);
}
.sv-visit__inset img { width: 100%; height: 100%; object-fit: cover; }

.sv-float--map {
  right: clamp(-2rem, -2.5vw, -0.75rem);
  bottom: clamp(-1rem, 1vw, 1.25rem);
  width: min(16rem, 72%);
}


/* ==========================================================================
   13. THE CLOSING CALL
   ---------------------------------------------------------------------------
   TWO LAYERS, AND THE BOTTOM ONE IS THE FOOTER'S. The band's lower layer is
   the footer's exact gradient — same angle, same three stops — and the upper
   layer is a navy that fades to nothing before it reaches the floor. So the
   pixel row where this section ends is the same colour as the row where the
   footer begins, at every x, and there is no seam. Change the footer's
   gradient and this one has to change with it.
   ========================================================================== */
.sv-final {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-block: clamp(4rem, 11vh, 8rem);
  color: var(--sv-on-dark);
  background:
    linear-gradient(180deg, #06213a 0%, rgba(6, 33, 58, .82) 38%, rgba(6, 33, 58, 0) 100%),
    linear-gradient(104deg, #324860 0%, #186d9f 46%, #0c4a5c 100%);
}
.sv-final__shape { position: absolute; z-index: -1; border-radius: 50%; pointer-events: none; }
.sv-final__shape--a {
  top: -30%; right: -8%;
  width: min(42vw, 560px);
  aspect-ratio: 1;
  background: radial-gradient(circle, rgba(127, 227, 212, .2) 0%, rgba(127, 227, 212, 0) 66%);
}
.sv-final__shape--b {
  bottom: -35%; left: -6%;
  width: min(38vw, 480px);
  aspect-ratio: 1;
  background: radial-gradient(circle, rgba(26, 114, 214, .3) 0%, rgba(26, 114, 214, 0) 68%);
}
.sv-final__inner {
  width: var(--sv-shell);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  align-items: center;
  gap: var(--sv-gap);
}
/* The artwork's own ratio — this card's caption is baked into the picture.
   The organic corners are on the diagonal the caption does NOT sit in. */
.sv-final__media {
  overflow: hidden;
  aspect-ratio: 428 / 362;
  border-radius: clamp(2rem, 6vw, 5rem) var(--sv-r-lg) clamp(2rem, 6vw, 5rem) var(--sv-r-lg);
  background: linear-gradient(120deg, #dceaf8, #bcd8f2);
  box-shadow: 0 30px 70px rgba(0, 0, 0, .32);
}
.sv-final__media img { width: 100%; height: 100%; object-fit: cover; }
.sv-final__copy .sv-h1 { margin-top: clamp(1rem, 2vh, 1.5rem); }
.sv-final__text {
  max-width: 46ch;
  margin-top: clamp(1.1rem, 2.4vh, 1.6rem);
  font-size: var(--fs-body);
  line-height: 1.7;
  color: var(--sv-on-dark-soft);
}
.sv-final__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(.7rem, 1.4vw, 1rem);
  margin-top: clamp(1.75rem, 3.4vh, 2.5rem);
}
/* The glass button was designed against a near-white page. On this band it
   needs its own ink and hairline or it disappears. */
.sv-final .btn--glass {
  color: #fff;
  background: rgba(255, 255, 255, .1);
  border-color: rgba(255, 255, 255, .34);
  box-shadow: none;
}
.sv-final .btn--glass:hover { background: rgba(255, 255, 255, .18); border-color: rgba(255, 255, 255, .55); }


/* ==========================================================================
   14. FOOTER ADDITIONS
   ---------------------------------------------------------------------------
   style.css already styles the footer. These are the pieces the shared
   component added: a fourth column carrying every treatment, and a booking
   action in the brand column.
   ========================================================================== */
/* FOUR COLUMNS, and the treatments column is the widest because it carries
   two sub-columns of fifteen links. Quick Links is the narrowest — five
   one-word labels. */
.foot__grid {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.75fr) minmax(0, 0.65fr) minmax(0, 1.05fr);
  column-gap: clamp(1.25rem, 2.6vw, 2.75rem);
}

.foot__cta {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  margin-top: 1.25rem;
  padding: .7rem 1.2rem;
  font-family: var(--f-ui);
  font-size: 0.85rem;
  font-weight: 500;
  color: #fff;
  background: var(--c-accent);
  border-radius: 100px;
  transition: background var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.foot__cta svg { width: 16px; height: 16px; transition: transform var(--t-med) var(--ease-out); }
.foot__cta:hover { background: #ff7d45; transform: translateY(-2px); }
.foot__cta:hover svg { transform: translateX(3px); }

.foot__treats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem; }
.foot__treat-head {
  margin-bottom: .5rem;
  font-family: var(--f-ui);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(127, 227, 212, .9);
}
.foot__list--tight li + li { margin-top: .3rem; }
.foot__list--tight a { font-size: 0.85rem; }
.foot__more {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  margin-top: 1.1rem;
  font-family: var(--f-ui);
  font-size: 0.82rem;
  font-weight: 500;
  color: #fff;
  opacity: .9;
}
.foot__more svg { width: 15px; height: 15px; transition: transform var(--t-med) var(--ease-out); }
.foot__more:hover { opacity: 1; }
.foot__more:hover svg { transform: translateX(3px); }
.foot__list a[aria-current] { color: var(--c-mint); }


/* ==========================================================================
   15. THE ACTION DOCK
   Below 980px the section rail can no longer hold its labels and a button, so
   the appointment action moves here: thumb height, always reachable, and away
   while the hero — which has its own button — is still on screen.
   ========================================================================== */
.sv-dock {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 45;
  display: none;
  align-items: center;
  gap: .6rem;
  padding: .6rem max(.75rem, env(safe-area-inset-left))
           calc(.6rem + env(safe-area-inset-bottom))
           max(.75rem, env(safe-area-inset-right));
  background: rgba(255, 255, 255, .94);
  border-top: 1px solid rgba(186, 214, 243, .7);
  box-shadow: 0 -8px 30px rgba(11, 45, 82, .12);
  -webkit-backdrop-filter: blur(18px) saturate(165%);
  backdrop-filter: blur(18px) saturate(165%);
  transform: translateY(0);
  transition: transform var(--t-med) var(--ease-out);
}
.sv-dock.is-away { transform: translateY(130%); }
.sv-dock__call {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  flex: none;
  /* 48px minimum: it is a touch target before it is a link. */
  min-height: 48px;
  padding-inline: 1rem;
  font-family: var(--f-ui);
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--c-blue-900);
  background: rgba(26, 114, 214, .08);
  border-radius: 100px;
}
.sv-dock__call svg { width: 18px; height: 18px; }
.sv-dock__cta { flex: 1 1 auto; }


/* ==========================================================================
   16. RESPONSIVE
   ---------------------------------------------------------------------------
   Three breakpoints, each with a reason rather than a device name:

     1180px  the two-column spreads still work but the floating cards no
             longer have gutters to hang in
     980px   two columns of body copy stop being readable. Everything stacks,
             the mega-menu becomes an accordion in the mobile menu, and the
             appointment button moves from the rail to the dock
     560px   the phone. Buttons go full width, grids go to one column, and the
             floating cards stop floating
   ========================================================================== */

@media (max-width: 1180px) {
  .sv-body { --sv-fs-h1: clamp(2.4rem, 1rem + 4.4vw, 4rem); }

  /* The floats come back INSIDE their frames: there is no page gutter left
     for them to hang in, and a card half off the edge of the viewport is a
     card with half a sentence. */
  .sv-hero .sv-chip--float { left: clamp(.75rem, 2vw, 1.25rem); }
  .sv-float--benefit { left: clamp(.75rem, 2vw, 1.25rem); width: min(17rem, 76%); }
  .sv-float--shade   { right: clamp(.75rem, 2vw, 1.25rem); }
  .sv-float--tl      { left: clamp(.75rem, 2vw, 1.25rem); }
  .sv-float--br      { right: clamp(.75rem, 2vw, 1.25rem); }
  .sv-visit__inset   { left: clamp(.75rem, 2vw, 1.25rem); }
  .sv-float--map     { right: clamp(.75rem, 2vw, 1.25rem); bottom: clamp(.75rem, 2vw, 1.25rem); }
  .sv-reviews__track { right: clamp(.75rem, 2vw, 1.25rem); bottom: clamp(.75rem, 2vw, 1.25rem); }

  .foot__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- Tablet: the spreads stack, the menu becomes an accordion ------------- */
@media (max-width: 980px) {
  .sv-body { --sv-pad: clamp(3.25rem, 8vh, 5rem); }

  .sv-hero__inner,
  .sv-break__inner,
  .sv-exp__inner,
  .sv-reviews__inner,
  .sv-visit__inner,
  .sv-final__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(2.25rem, 6vw, 3.5rem);
  }

  /* Copy first in the DOM and first on screen everywhere — the heading tells
     you what you are looking at. */
  .sv-break__media,
  .sv-final__media { order: 2; }
  .sv-break__copy,
  .sv-final__copy { order: 1; }

  .sv-hero__frame   { aspect-ratio: 16 / 11; }
  .sv-hero__photo   { object-position: 62% 46%; }
  .sv-visit__frame  { aspect-ratio: 16 / 12; }
  /* Keeps 428:362 at every width — its caption is baked into the artwork. */
  .sv-final__media  { max-width: 30rem; }
  .sv-reviews__media { max-width: 34rem; }

  .sv-hero__lede,
  .sv-lede,
  .sv-p { max-width: 62ch; }

  .sv-reviews__track { position: static; width: 100%; margin-top: 1.25rem; }
  .sv-exp__cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* --- The rail hands its button to the dock ---------------------------- */
  .sv-jump__cta { display: none; }
  .sv-jump__inner { padding-inline: .5rem; }
  .sv-dock { display: flex; }
  .sv-jump__list {
    flex: 1 1 auto;
    min-width: 0;
    -webkit-mask-image: linear-gradient(90deg, #000 88%, transparent 100%);
    mask-image: linear-gradient(90deg, #000 88%, transparent 100%);
  }
  /* Room for the dock, so the footer's last line is never under it. */
  .foot { padding-bottom: calc(clamp(1.5rem, 3vh, 2.25rem) + 76px); }

  .sv-hero__word { display: none; }

  /* --- THE MEGA-MENU BECOMES AN ACCORDION -------------------------------
     Same markup. It drops out of its absolute box and into the flow of the
     mobile menu; the category headings become live toggles (chrome.js gives
     them back their tabindex here) and the panels animate their height. */
  .mega {
    position: static;
    width: auto;
    padding: 0;
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    opacity: 1;
    visibility: visible;
    transform: none;
  }
  .mega::before { display: none; }
  .mega__inner { display: block; }
  .mega__aside { display: none; }
  .mega__cols { grid-template-columns: minmax(0, 1fr); gap: .25rem; }

  .mega__head { margin: 0; }
  .mega__toggle {
    padding: .8rem .25rem;
    border-bottom: 1px solid rgba(120, 170, 225, .28);
  }
  /* The plus, drawn from two bars so it becomes a minus by rotating one. */
  .mega__sign {
    position: relative;
    display: block;
    flex: none;
    width: 22px; height: 22px;
  }
  .mega__sign::before,
  .mega__sign::after {
    content: "";
    position: absolute;
    top: 50%; left: 50%;
    width: 11px; height: 1.6px;
    background: currentColor;
    border-radius: 2px;
    transform: translate(-50%, -50%);
    transition: transform var(--t-med) var(--ease-out);
  }
  .mega__sign::after { transform: translate(-50%, -50%) rotate(90deg); }
  .mega__toggle[aria-expanded="true"] .mega__sign::after { transform: translate(-50%, -50%) rotate(0deg); }

  /* Height is animated by chrome.js; the panel only has to clip. */
  .mega__panel { overflow: hidden; }
  .mega__list { padding: .35rem 0 .75rem; }
  .mega__item { padding: .55rem .5rem; font-size: 0.95rem; }
  .mega__item svg { opacity: 1; transform: none; }

  /* --- THE SMALL DROPDOWNS BECOME PLAIN NESTED LISTS ---------------------
     No disclosure down here. Two links do not earn a tap to reveal them
     inside a menu that is already open, so they drop into the flow and are
     always visible — chrome.js stays out of the way below this breakpoint. */
  .drop {
    position: static;
    width: auto;
    padding: 0 0 .35rem .85rem;
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    opacity: 1;
    visibility: visible;
    transform: none;
  }
  .drop::before { display: none; }
  .drop__item { padding: .5rem .5rem; }
  .drop__note { display: none; }
  .drop__arrow { opacity: 1; transform: none; }
  /* The caret points at a panel that is no longer a panel. */
  .nav__item--drop .nav__caret { display: none; }
}

/* --- The utility strip on a narrow screen ---------------------------------
   Three items and a strapline do not fit a phone. They go in order of what
   is least useful there:

     the strapline   it is on the page itself, twice
     the button      the pill above it and the dock below it both carry the
                     same action; three booking buttons on one 390px screen
                     is two too many

   What is left — the number and the forms link — is what somebody opening
   the site on a phone actually wants at the top.
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .util__note { display: none; }
  .util__inner { justify-content: center; }
}
@media (max-width: 560px) {
  .util__cta { display: none; }
  :root { --util-h: 36px; }
}

/* --- The mobile menu's anchor --------------------------------------------
   style.css pins the drop-down panel to a FIXED offset of --nav-h, which was
   right when the pill was the only thing in the header. With the utility
   strip above it — and with that strip collapsing on scroll — a fixed number
   is wrong at least half the time.

   ANCHORED TO THE PILL, and `position: relative` on the pill is what makes
   that deterministic. It would happen anyway — .nav__inner carries a
   backdrop-filter, and a backdrop-filter makes an element the containing
   block for its absolutely positioned descendants — but relying on that is
   relying on a side effect that disappears the day the blur does. Stated
   outright, the panel measures the pill's edges, follows it when the utility
   strip collapses, and needs no number of its own.

   It also has to SCROLL now: fifteen treatments plus six navigation items is
   taller than a phone. `overscroll-behavior` stops that scroll continuing
   into the page behind it when it reaches the end.
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .nav__inner { position: relative; }

  .nav__menu {
    position: absolute;
    inset: auto 0 auto 0;
    top: calc(100% + 10px);
    max-height: calc(100svh - 8rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    /* OPAQUE, and the blur goes with it. Glass was right for a six-item menu
       floating over a photograph; this one is twenty-one rows tall and every
       one of them is a destination. Even a 3% ghost of the hero headline
       behind a treatment name is noise on the one screen that has to be
       unambiguous — and with an opaque panel the backdrop-filter is a GPU
       layer rendering something nobody can see. */
    background: #ffffff;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

/* --- Phone ---------------------------------------------------------------- */
@media (max-width: 560px) {
  .sv-body {
    --sv-fs-h1: clamp(2.1rem, 8.6vw, 3rem);
    --sv-fs-h2: clamp(1.75rem, 7.4vw, 2.4rem);
    --sv-r-xl: 24px;
    --sv-r-lg: 18px;
  }

  .sv-hero__title--hub { font-size: clamp(3rem, 17vw, 4.5rem); }

  .sv-hero__actions .btn,
  .sv-break__actions .btn,
  .sv-final__actions .btn,
  .sv-exp__actions .btn { width: 100%; }
  .sv-hero__actions,
  .sv-final__actions { flex-direction: column; align-items: stretch; }
  .sv-dock .btn { width: auto; }

  .sv-hero__facts { gap: 1.25rem 1.75rem; }

  .sv-exp__list,
  .sv-exp__cards,
  .sv-visit__panel,
  .foot__grid,
  .foot__treats { grid-template-columns: minmax(0, 1fr); }
  .sv-exp__card--a,
  .sv-exp__card--b { aspect-ratio: 16 / 11; }
  .sv-exp__card--c { aspect-ratio: 16 / 10; }

  /* The floats stop floating: at this width there is nowhere for a card to
     overlap a picture without covering the subject of it. */
  .sv-hero__media,
  .sv-visit__media { display: flex; flex-direction: column; gap: .9rem; }
  .sv-float,
  .sv-hero .sv-chip--float { position: static; width: 100%; animation: none; }
  .sv-hero .sv-chip--float { width: max-content; }
  .sv-visit__inset { position: static; width: 100%; aspect-ratio: 16 / 9; border-width: 4px; }

  /* The index row loses its hover preview — there is no hover — and gives
     the space back to the name. */
  .svc--index .svc__media { display: none; }
  .svc--index .svc__link { padding-inline: .25rem; }
  .svc--index .svc__link:hover { padding-left: .25rem; }

  .svc-pager__inner { grid-template-columns: minmax(0, 1fr); }
  .svc-pager__side--next { border-left: 0; border-top: 1px solid rgba(120, 170, 225, .3); }
}


/* ==========================================================================
   17. REDUCED MOTION / PRINT
   Everything autonomous stops. The reveals are handled in site.js — it checks
   the same query and writes the finished state instead of animating to it —
   so all that is left here is the CSS-driven motion.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  [data-float],
  .sv-cta-breathe { animation: none !important; }

  .util,
  .sv-dock,
  .mega,
  .svc__link,
  .svc__media img,
  .sv-hero__photo,
  .sv-break__media img,
  .sv-exp__card img,
  .sv-visit__frame img { transition: none; }

  .sv-hero__frame:hover .sv-hero__photo,
  .svc__link:hover,
  .svc__link:hover .svc__media img,
  .sv-break__media:hover img,
  .sv-exp__card:hover img,
  .sv-visit__frame:hover img { transform: none; }
}

@media print {
  .sv-jump,
  .sv-dock,
  .util,
  .mega,
  .sv-hero__blob,
  .sv-hero__word,
  .sv-final__shape { display: none !important; }

  /* Nothing on a printed page should be invisible because a script did not
     get the chance to reveal it. */
  [data-sv],
  .line__inner { opacity: 1 !important; }
  [data-sv-mask] { clip-path: none !important; }

  .sv-final,
  .svc--feature .svc__body { color: #000 !important; background: none !important; }
  .sv-h2--light,
  .svc--index .svc__name { color: #000 !important; }
}
