/* ===================================================================
   MANA — SITE STYLES
   Layout and page composition. Every value comes from mana-tokens.css.
   If you're about to type a hex code or a px value here, stop and add
   a token instead.
   =================================================================== */

/* --- Skip link ---------------------------------------------------- */
.skip-link {
  position: absolute;
  left: var(--space-s);
  top: -5rem;
  z-index: var(--z-modal);
  background: var(--mana-ink);
  color: var(--text-on-dark);
  padding: var(--space-2xs) var(--space-s);
  text-decoration: none;
  transition: top var(--duration-fast) var(--ease-out);
}
.skip-link:focus { top: var(--space-s); color: var(--text-on-dark); }


/* --- Utility bar ---------------------------------------------------
   Address and phone, above the masthead. Quiet by design — this is the
   line people scan when they've already decided to come in. */
.utility {
  background: var(--surface-sunk);
  color: var(--text-secondary);
  font-size: var(--step--1);
  letter-spacing: 0.06em;
}
/* Centred, not justified. This bar held two facts — address on the left,
   phone on the right — and space-between was right for that. With the address
   gone it left "Consultation first" stranded alone in the left corner, reading
   as a fragment rather than a sentence. One centred line says one thing. */
.utility__inner {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--space-m);
  padding-block: var(--space-2xs);
}
.utility__line {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: var(--space-2xs);
}
.utility__item { color: var(--text-secondary); text-decoration: none; }
.utility__item:hover { color: var(--text-primary); text-decoration: underline; }
.utility__sep { color: var(--mana-sand); }
/* Phone: the number alone. The lead-in is the first thing worth losing when
   the bar gets tight — it is framing, and the number is the action. */
@media (max-width: 48rem) {
  .utility__lead, .utility__sep { display: none; }
}


/* --- Masthead ------------------------------------------------------
   Desktop: nav | logo | action, logo centered. A centered mark is the
   one layout decision that most separates a practice from a franchise
   template, and it costs nothing.
   Mobile: logo left, toggle right. */
.masthead {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: rgba(253, 252, 250, 0.92);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: var(--hairline);
}
.masthead__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  padding-block: var(--space-s);
}
@media (min-width: 64rem) {
  .masthead__inner { padding-block: var(--space-m); gap: var(--space-l); }

  /* Mark left, navigation and booking CTA together on the right.
     A centered mark was the first attempt and it does not survive contact with
     this nav: centering needs the left track and the right track to be equal
     widths, but five nav items are far wider than one button, so the center
     cell gets shoved right until the mark sits against the CTA. Pushing the
     nav right instead gives the mark clear space at every width. */
  .masthead__nav { margin-left: auto; }

  /* The masthead button keeps nowrap: it has room at every width this rule
     applies to, and letting it wrap would change the header's height as the
     window resizes. Everywhere else, buttons wrap rather than overflow. */
  .masthead__action .c-btn { white-space: nowrap; }

  /* The booking CTA appears twice in the DOM — once inside the nav list for
     the mobile menu, once in .masthead__action for desktop. Exactly one is
     ever visible. */
  .nav__item--cta { display: none; }
}

/* --- Wordmark ------------------------------------------------------
   Real artwork from the logo kit, sized by WIDTH rather than height.
   The kit's rule is a width floor — the compact lockup below 240px, the
   full lockup above it — so width is the dimension worth controlling.
   Height follows from the file's own aspect ratio. */
.wordmark { display: block; text-decoration: none; line-height: 0; }
.wordmark__img { width: 100%; height: auto; }

/* Masthead: compact lockup, 4.67:1. Kept under the kit's 240px floor at
   every width, which is exactly why it is the compact one. */
.wordmark { width: 10.5rem; }
@media (min-width: 64rem) { .wordmark { width: 12rem; } }

/* Footer: full lockup with the descriptor, 4.01:1. Comfortably over the
   240px floor, so the descriptor stays legible. */
.wordmark--footer { width: 15rem; max-width: 100%; }

/* Clear space. The kit specifies the height of the mark divided by three,
   kept free of type, rules and image edges. At footer scale the lockup is
   ~60px tall, so 20px. */
.wordmark--footer { margin-bottom: 1rem; }

/* --- Masthead wordmark, set as live text ---------------------------------
   The masthead no longer renders the lockup as an image, so it must undo the
   three rules above that only ever made sense for one: the fixed 10.5rem
   width, the block display, and `line-height: 0` — that last one is what
   stacked "Mana" and "Wellness & Aesthetics" on top of each other when the
   markup changed under it.

   Sizes are in rem, not px, so the descriptor scales with the user's text
   settings. The mark keeps its own optical size beside the type. */
.wordmark--type {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: auto;
  line-height: 1;
}
.wordmark__mark {
  width: 2.375rem;
  height: auto;
  flex-shrink: 0;
}
.wordmark__type {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* 1.5rem is the floor for the gold here — see the contrast note in
   _includes/wordmark.html. Below 24px this colour stops passing. */
.wordmark__name {
  font-family: var(--font-body);
  font-weight: var(--weight-regular);
  font-size: 1.5rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--mana-gold);
  line-height: 1;
}
.wordmark__desc {
  font-size: 0.5625rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-top: 0.34rem;
  line-height: 1;
  white-space: nowrap;
}
/* Tighten the tracking rather than hiding the descriptor — the whole point of
   rebuilding the lockup as text was that it survives at narrow widths. */
@media (max-width: 25rem) {
  .wordmark__name { font-size: 1.25rem; }
  .wordmark__desc { font-size: 0.5rem; letter-spacing: 0.18em; }
}


/* --- Facility row ---------------------------------------------------------
   Three portraits, contained rather than full-bleed. The previous attempt put
   a single photograph in a full-width band whose ratio swings from ~1.8:1 on a
   phone to ~3.6:1 on a desktop; nothing in the library survives that, and the
   result was a small logo adrift in a dark rectangle on mobile.

   A contained 3:4 grid asks nothing of the source but its own aspect ratio.
   Each image is served at 720x960 from a 765px-or-larger original, so nothing
   is upscaled, and the row simply stacks on a phone at close to native size. */
.facility-row {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-m);
}
@media (min-width: 40rem) {
  .facility-row { grid-template-columns: repeat(3, 1fr); gap: var(--space-l); }
}
.facility-row img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--radius-s);
  background: var(--mana-sand);
}
.facility-row p {
  margin: var(--space-2xs) 0 0;
  font-size: var(--step--1);
  color: var(--text-secondary);
}

/* --- Treatments at a glance ----------------------------------------------
   A band, not a row of cards. Sand ground with a hairline top and bottom so it
   reads as its own layer between the hero photograph and the trust trio,
   without introducing a filled box — same reason the rest of the site gets its
   weight from space and rules.

   The scroll behaviour is the point on a phone: the row bleeds past the wrap
   to the screen edge so a pill is visibly cut off at the right, which is what
   tells you it moves. Hiding the scrollbar without disabling the scroll needs
   all three of the declarations below; they are not redundant. */
.strip {
  background: var(--surface-sunk);
  border-block: var(--hairline);
}
.strip__inner {
  display: flex;
  align-items: center;
  gap: var(--space-m);
  padding-block: var(--space-s);
}
.strip__label {
  flex-shrink: 0;
  max-width: 6.5rem;
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-secondary);
  line-height: 1.4;
}
/* Wraps on a wide screen, scrolls on a narrow one. These are different
   problems and one rule cannot solve both.

   The eight pills overrun the content wrap by a little at desktop widths, so
   left to scroll they clipped "Hair restoration" against the right edge with
   nothing to indicate the row moved — on a phone a cut-off pill reads as
   "swipe me", on a desktop it just reads as broken. Wrapping to a second row
   shows all eight and needs no affordance at all. */
.strip__scroll {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  padding-block: 0.15rem;
}
.strip__pill {
  flex-shrink: 0;
  border: var(--hairline);
  background: var(--surface-page);
  padding: var(--space-2xs) var(--space-s);
  font-size: var(--step--1);
  color: var(--text-primary);
  text-decoration: none;
  white-space: nowrap;
  transition: border-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}
.strip__pill:hover,
.strip__pill:focus-visible {
  border-color: var(--mana-gold);
  color: var(--text-accent);
}
/* Stack the label above the row on a phone, and let the row run to both
   screen edges. The negative margin has to be matched by equal padding or the
   first pill starts off-screen. */
/* Phone: one line that scrolls and bleeds to both screen edges, so a pill is
   deliberately cut off at the right — there, that IS the affordance. Hiding
   the scrollbar without killing the scroll needs all three declarations. */
@media (max-width: 45rem) {
  .strip__inner {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2xs);
  }
  .strip__label { max-width: none; }
  .strip__scroll {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;          /* Firefox */
    -ms-overflow-style: none;       /* old Edge */
    margin-inline: calc(var(--space-m) * -1);
    padding-inline: var(--space-m);
  }
  .strip__scroll::-webkit-scrollbar { display: none; }
}

/* --- Nav ------------------------------------------------------------ */
.nav__list {
  display: flex;
  align-items: center;
  gap: var(--space-m);
  list-style: none;
  margin: 0;
  padding: 0;
}
@media (min-width: 76rem) { .nav__list { gap: var(--space-l); } }
.nav__link {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: var(--weight-regular);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--text-primary);
  text-decoration: none;
  background: none;
  border: 0;
  padding: var(--space-2xs) 0;
  cursor: pointer;
  position: relative;
}
/* Gold underline that draws in on hover — the only flourish in the nav. */
.nav__link::before {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--mana-gold);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-base) var(--ease-out);
}
.nav__link:hover::before,
.nav__link[aria-current="page"]::before,
.nav__link[aria-expanded="true"]::before { transform: scaleX(1); }

.nav__item--has-sub { position: relative; }
.nav__disclosure::after {
  content: '';
  display: inline-block;
  width: 0.35em; height: 0.35em;
  margin-left: 0.6em;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: translateY(-0.2em) rotate(45deg);
  transition: transform var(--duration-fast) var(--ease-out);
}
.nav__disclosure[aria-expanded="true"]::after { transform: translateY(0.05em) rotate(-135deg); }

.nav__sub { list-style: none; margin: 0; padding: 0; display: none; }
.nav__sub[data-open="true"] { display: block; }
.nav__sub a {
  display: block;
  padding: var(--space-xs) var(--space-s);
  border-left: 2px solid var(--mana-gold);
  text-decoration: none;
  color: var(--text-primary);
  transition: background var(--duration-fast) var(--ease-out);
}
.nav__sub a:hover { background: var(--surface-raised); color: var(--text-primary); }
.nav__sub-name {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: var(--weight-regular);
}
.nav__sub-desc { display: block; font-size: var(--step--1); color: var(--text-secondary); }

@media (min-width: 64rem) {
  .nav__sub {
    position: absolute;
    top: calc(100% + var(--space-s));
    left: calc(var(--space-s) * -1);
    min-width: 22rem;
    background: var(--surface-page);
    border: var(--hairline);
    border-top: 1px solid var(--mana-gold);
    box-shadow: var(--shadow-menu);
    padding: var(--space-2xs);
    z-index: var(--z-overlay);
  }

  /* Transparent bridge across the gap between the button and the panel.
     Without it the menu is unusable: the pointer leaves .nav__item--has-sub
     while crossing the gap, mouseleave fires, and the panel closes before you
     reach the links. A pseudo-element hit-tests as its originating element, so
     hovering here still counts as hovering the submenu. */
  .nav__sub::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 100%;
    height: calc(var(--space-s) + 2px);
  }
}

.nav-toggle {
  display: none;
  background: none;
  border: 0;
  padding: var(--space-2xs);
  cursor: pointer;
  color: var(--text-primary);
}
.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  display: block;
  width: 22px; height: 1px;
  background: currentColor;
  content: '';
  transition: transform var(--duration-base) var(--ease-out),
              opacity var(--duration-fast) var(--ease-out);
}
.nav-toggle__bars { position: relative; }
.nav-toggle__bars::before { position: absolute; top: -7px; }
.nav-toggle__bars::after  { position: absolute; top: 7px; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::before { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::after  { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 63.99rem) {
  .nav-toggle { display: block; }
  .masthead__action { display: none; }
  .nav {
    display: none;
    position: absolute;
    inset-inline: 0;
    top: 100%;
    background: var(--surface-page);
    border-bottom: var(--hairline);
    box-shadow: var(--shadow-menu);
    padding: var(--space-m) var(--gutter) var(--space-xl);
    max-height: calc(100vh - 100%);
    overflow-y: auto;
  }
  .nav[data-open="true"] { display: block; }
  .nav__list { flex-direction: column; align-items: stretch; gap: 0; }
  .nav__item { border-bottom: var(--hairline); }
  .nav__item--cta { border: 0; margin-top: var(--space-l); }
  .nav__item--cta .c-btn { width: 100%; }
  .nav__link { width: 100%; text-align: left; padding: var(--space-s) 0; }
  .nav__link::before { display: none; }
  .nav__disclosure::after { float: right; margin-top: 0.55em; }
  .nav__sub { padding-bottom: var(--space-s); }
}


/* --- Page head ------------------------------------------------------
   Interior pages. Centered, with air above the heading — the space is the
   luxury signal, not an ornament. Was space-xl/space-l with an h1 at the
   top of the scale, which on a laptop meant the eyebrow, heading and
   standfirst owned the entire first screen on their own. */
.page-head {
  padding-block: var(--space-l) var(--space-m);
  text-align: center;
}
/* One step down from the homepage h1. The hero heading is the brand
   statement and earns step-5; an interior page title is wayfinding, and
   at step-5 it cost two 92px lines before the page had said anything. */
.page-head h1 {
  font-size: var(--step-4);
  margin-bottom: var(--space-s);
  max-width: 20ch;
  margin-inline: auto;
}
/* Flush where an image follows immediately: the heading should introduce
   the picture, not hold the whole first screen on its own. Tracks the
   padding above — if that changes, change this with it. */
.page-head + .team-photo { margin-top: calc(var(--space-m) * -1); }
.standfirst {
  font-size: var(--step-1);
  font-weight: var(--weight-light);
  line-height: var(--leading-snug);
  color: var(--text-secondary);
  max-width: 46ch;
}
.page-head .standfirst { margin-inline: auto; }


/* --- Home hero ------------------------------------------------------
   Same padding as an interior page head now, but it keeps the full step-5
   h1 — this is the one heading on the site allowed to be an entrance. */
.hero {
  padding-block: var(--space-l) var(--space-m);
  text-align: center;
}
.hero h1 {
  margin-bottom: var(--space-m);
  max-width: 16ch;
  margin-inline: auto;
}
.hero h1 em {
  font-style: italic;
  font-weight: var(--weight-light);
  color: var(--text-accent);
}
.hero__lede {
  font-size: var(--step-1);
  font-weight: var(--weight-light);
  line-height: var(--leading-snug);
  color: var(--text-secondary);
  max-width: 48ch;
  margin-inline: auto;
}
.hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-s);
  margin-top: var(--space-l);
}

/* The wide image band under the hero. Swap the placeholder for real
   photography of the practice or the clinicians — never stock. The whole
   argument of this page is that these are real people you can drive to. */
.hero__figure {
  position: relative;
  /* Fluid height, not aspect-ratio + min-height. Those two together let the
     browser derive WIDTH from the constrained height: at 375px the 18rem floor
     resolved to a 672px-wide band and put the homepage into horizontal scroll.
     Same trap as .map-slot — if an element has aspect-ratio, never also give it
     a minimum on the cross axis. */
  width: 100%;
  /* 46vw tracks the source crop's own 2.16:1 ratio almost exactly, so at
     typical desktop widths the band shows the whole photograph and `cover`
     has nothing left to trim. The floor keeps it from collapsing to a sliver
     on a phone; the ceiling stops it eating a large monitor.

     Still a plain height, not aspect-ratio plus a minimum — that pairing lets
     the browser solve for WIDTH and is what put this page into horizontal
     scroll once already. */
  height: clamp(15rem, 46vw, 44rem);
  background: var(--mana-sand);
  overflow: hidden;
  display: grid;
  place-items: center;
  text-align: center;
}
/* Padding belongs to the placeholder, never the frame. This is the third time
   the same mistake has shipped — provider photos, the map, and now the hero
   band were each matted inside a sand border by padding meant for the text
   that used to sit in the empty slot. */
.hero__figure .placeholder { padding: var(--space-l); }
/* The source is now a purpose-made 1600x740 crop rather than the full 3:2
   frame, so both founders are already composed inside it and there is very
   little for `cover` to remove. What it does remove comes off the bottom,
   keeping faces in view at every width. */
.hero__figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 35%;
}
.placeholder {
  font-size: var(--step--1);
  color: var(--mana-ink-soft);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  max-width: 30ch;
  margin: 0;
}


/* --- Trust strip ----------------------------------------------------- */
.trust { border-bottom: var(--hairline); }
.trust__list {
  display: grid;
  gap: var(--space-l);
  list-style: none;
  margin: 0;
  padding: 0;
  padding-block: var(--space-l);
}
@media (min-width: 52rem) {
  .trust__list { grid-template-columns: repeat(3, 1fr); gap: var(--space-xl); }
  .trust__list > div + div { border-left: var(--hairline); padding-left: var(--space-xl); }
}
.trust__list dt {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: var(--weight-regular);
  color: var(--text-primary);
  margin-bottom: var(--space-2xs);
}
.trust__list dd {
  margin: 0;
  font-size: var(--step--1);
  line-height: 1.7;
  color: var(--text-secondary);
}


/* --- Bands ----------------------------------------------------------- */
.band--raised  { background: var(--surface-raised); }
.band--sunk    { background: var(--surface-sunk); }
.band--inverse { background: var(--surface-inverse); color: var(--text-on-dark); }
.band--inverse h2, .band--inverse h3 { color: var(--text-on-dark); }
.band--inverse p { color: #C9C4BA; }
/* On the dark band the logo gold drops to 2.7:1 against #0B0B0B, so the
   eyebrow uses the kit's on-dark tint instead. Same hue, AA at 4.59:1. */
.band--inverse .c-eyebrow { color: var(--mana-gold-on-dark); }
.band--inverse a { color: var(--text-on-dark); text-decoration-color: var(--mana-gold); }

.band__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-l);
}
.band__inner > div { max-width: 46ch; }
.band__inner p:last-of-type { margin-bottom: 0; }


/* --- Meaning block (brand story) -------------------------------------
   The two definitions of the word, set as a dictionary entry. This is
   the practice's best piece of differentiation — give it room. */
.meaning__grid { display: grid; gap: var(--space-xl); }
@media (min-width: 56rem) {
  .meaning__grid { grid-template-columns: 0.85fr 1fr; gap: var(--space-2xl); align-items: start; }
}
.meaning__term {
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: var(--weight-light);
  font-style: italic;
  margin-bottom: var(--space-3xs);
}
.meaning__gloss {
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-accent);
  margin-bottom: var(--space-2xs);
}
.meaning__def { font-size: var(--step-0); color: var(--text-secondary); }


/* --- Pillar grid ------------------------------------------------------
   Five outcome pillars, presented as peers. Nobody arrives knowing the
   generic name of an injectable — they arrive knowing they don't like their
   double chin. These are the five doors in. */
.pillar-grid { display: grid; gap: var(--space-l); }
@media (min-width: 44rem) { .pillar-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 62rem) { .pillar-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 82rem) { .pillar-grid { grid-template-columns: repeat(5, 1fr); gap: var(--space-m); } }


/* --- Steps ------------------------------------------------------------
   A real sequence, so the numbering carries information. */
.steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-xl);
  counter-reset: step;
}
@media (min-width: 56rem) { .steps { grid-template-columns: repeat(3, 1fr); gap: var(--space-l); } }
.steps li {
  counter-increment: step;
  padding-top: var(--space-m);
  border-top: 1px solid var(--mana-gold);
}
.steps li::before {
  content: counter(step, decimal-leading-zero);
  display: block;
  font-family: var(--font-body);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  color: var(--text-accent);
  margin-bottom: var(--space-s);
}
.steps h3 { font-size: var(--step-2); margin-bottom: var(--space-2xs); }
.steps p { font-size: var(--step--1); line-height: 1.7; color: var(--text-secondary); margin-bottom: 0; }


/* --- Pillar page ------------------------------------------------------ */
.pillar-head {
  text-align: center;
  padding-block: var(--space-l) var(--space-m);
  border-bottom: 1px solid var(--mana-gold);
}
.pillar-head .c-eyebrow { color: var(--text-accent); }
.pillar-head h1 { font-size: var(--step-4); margin-bottom: var(--space-s); }
.pillar-head .standfirst { margin-inline: auto; }
.pillar-head__intro {
  margin-top: var(--space-m);
  max-width: var(--prose-max);
  margin-inline: auto;
  text-align: left;
}

.pillar-jump { border-bottom: var(--hairline); padding-block: var(--space-m); }
.pillar-jump ul {
  display: flex; flex-wrap: wrap; gap: var(--space-2xs);
  list-style: none; margin: 0; padding: 0;
  justify-content: center;
}
.pillar-jump a {
  display: inline-block;
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  padding: var(--space-2xs) var(--space-s);
  border: var(--hairline);
  text-decoration: none;
  color: var(--text-primary);
  transition: background var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}
.pillar-jump a:hover {
  background: var(--mana-ink);
  border-color: var(--mana-ink);
  color: var(--mana-ivory);
}

.treatment {
  display: grid;
  gap: var(--space-m);
  padding-block: var(--space-l);
  border-top: var(--hairline);
  scroll-margin-top: 7rem;
}
.treatment:first-of-type { border-top: 0; }
@media (min-width: 56rem) {
  .treatment { grid-template-columns: 1fr 1.7fr; gap: var(--space-2xl); }
}
.treatment__head h2 { font-size: var(--step-2); margin-bottom: var(--space-2xs); }
.treatment__aka {
  font-size: var(--step--1);
  letter-spacing: 0.04em;
  color: var(--text-secondary);
  margin: 0;
}
.treatment__body { margin: 0; display: grid; gap: var(--space-m); }
.treatment__body dt {
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-accent);
  margin-bottom: var(--space-3xs);
}
.treatment__body dd { margin: 0; max-width: var(--measure); }


/* --- Team photo --------------------------------------------------------
   A candid group shot above the roster. Wide crop so it reads as a band
   rather than a snapshot dropped into the page. */
/* Full-bleed band, like the homepage hero. Inside the content wrap it read as
   a figure dropped into an article; edge to edge it reads as the page opening
   with the people on it, which is what a page called "our team" should do. */
.team-photo { margin: 0; position: relative; }
.team-photo img {
  width: 100%;
  height: clamp(15rem, 40vw, 30rem);
  object-fit: cover;
  /* Retuned for founders-portrait.jpg, which replaced the launch group shot.
     42% was framed for that photograph and cut this one below the wall sign
     and across the chest.

     WHY THE SIGN IS NOT IN FRAME. This band is ~3.6:1 on a desktop and drops
     to ~1.6:1 on a phone, so `cover` only ever shows a horizontal slice of a
     4:3 source — about a third of its height at the wide end. In the original
     photograph the sign sits well above their heads: sign and faces together
     span more than half the frame, and no slice this shallow holds both. It is
     one or the other.

     Faces win. The page is headed "The people you will actually see", and the
     wall sign is already carried by the share card and the lobby shot.

     50% centres the slice on head-to-shoulders with headroom above. If this
     image is ever replaced, re-measure — this number belongs to the file, not
     to the component. */
  object-position: 50% 50%;
}
/* Sat under the photo, where it read as a stray line of body copy belonging to
   the roster below rather than a caption belonging to the image above. Set into
   the bottom right corner of the picture it is unambiguously part of it.

   The dark chip is not decoration. Laid straight over a photograph the text is
   legible or not depending on who is standing in that corner, which is not
   something a caption should depend on — the chip holds contrast whatever the
   image does. Kept small and inset so it reads as a credit line, not a badge. */
/* --- The team photo as navigation ----------------------------------------
   Two link targets over the band, one per founder, each carrying that person's
   name and jumping to their card in the roster. Halves rather than pixel
   hotspots — see the note in about.html for why coordinates cannot survive a
   `cover` crop that reshapes with the viewport. */
.team-photo__people {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  z-index: 1;
}
/* Labels sit at the TOP of the band, not the bottom. At the bottom, Oscar's
   label landed in the same corner as the caption chip and the two overlapped
   into an unreadable stack. The top of this crop is wall and sconce, so a chip
   there covers nothing and collides with nothing. */
.team-photo__person {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: var(--space-m);
  text-decoration: none;
}
/* Same chip as the caption, for the same reason: laid straight over a
   photograph, text is legible or not depending on who is standing there. */
.team-photo__label {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.1rem;
  padding: var(--space-3xs) var(--space-s);
  background: rgba(24, 20, 16, 0.62);
  border-radius: var(--radius-s);
  color: rgba(255, 255, 255, 0.94);
  font-size: var(--step--1);
  letter-spacing: 0.04em;
  text-align: center;
  opacity: 0;
  transform: translateY(0.4rem);
  transition: opacity var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}
.team-photo__person:hover .team-photo__label,
.team-photo__person:focus-visible .team-photo__label {
  opacity: 1;
  transform: none;
}
.team-photo__cue {
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: rgba(255, 255, 255, 0.72);
}
/* A touch screen has no hover, so a label that only appears on hover never
   appears at all. Show both permanently where there is no pointer — which
   also makes it obvious the picture is clickable. */
@media (hover: none) {
  .team-photo__label { opacity: 1; transform: none; }
}
/* The caption sits over the right-hand link. It is not interactive, so let
   clicks reach the link underneath instead of dying on a line of text. */
.team-photo figcaption { z-index: 2; pointer-events: none; }

.team-photo figcaption {
  position: absolute;
  right: var(--space-s);
  bottom: var(--space-s);
  /* Wide enough that a short credit line stays on one line at desktop widths —
     wrapped across two it stopped reading as a caption and started reading as a
     note stuck to the picture. Still yields to the viewport on small screens. */
  max-width: min(42ch, calc(100% - var(--space-l)));
  padding: var(--space-3xs) var(--space-2xs);
  background: rgba(24, 20, 16, 0.62);
  border-radius: var(--radius-s);
  font-size: var(--step--1);
  letter-spacing: 0.04em;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.94);
}
@supports (backdrop-filter: blur(2px)) {
  .team-photo figcaption { backdrop-filter: blur(2px); background: rgba(24, 20, 16, 0.46); }
}

/* --- Team roster -------------------------------------------------------
   Editorial rows rather than a grid of large portraits. The first attempt put
   four half-meter faces in a two-column grid above 200-word bios, which read
   as confrontational — you were looked at rather than introduced. Here the
   portrait is a modest fixed column and the credentials lead, which is also
   the honest hierarchy: what these people trained in matters more than what
   they look like. */
.roster { display: grid; }
.roster__item {
  display: grid;
  gap: var(--space-m);
  /* space-l each side put 80px between two names. The hairline is what
     separates one person from the next; the gap only has to be bigger
     than the gap inside a row, not four times it. */
  padding-block: var(--space-m);
  border-top: var(--hairline);
}
.roster__item:first-child { border-top: 0; padding-top: 0; }

@media (min-width: 44rem) {
  .roster__item {
    grid-template-columns: 7.5rem minmax(0, 1fr);
    gap: var(--space-l);
    align-items: start;
  }
}
@media (min-width: 68rem) {
  .roster__item { grid-template-columns: 8.5rem minmax(0, 1fr); gap: var(--space-xl); }
}

/* --- Roster section headings ---------------------------------------------
   "Founders" and "The team". Quiet by design: these separate two groups on one
   page, they do not introduce two pages, so they sit closer to a label than to
   a section title. */
.roster__section {
  font-size: var(--step-0);
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-secondary);
  padding-bottom: var(--space-2xs);
  margin-bottom: var(--space-m);
  border-bottom: var(--hairline);
}
/* Air above the second group, so it reads as a new group rather than as more
   of the first one. */
.roster__section--later { margin-top: var(--space-xl); }

/* Jump targets for the photo links above. The masthead is sticky, so an
   anchor without scroll-margin parks the card behind it. */
.roster__item { scroll-margin-top: 6rem; }

.roster__figure {
  aspect-ratio: 4 / 5;
  background: var(--mana-sand);
  display: grid;
  place-items: center;
  text-align: center;
  /* Rounds the photo, not just the frame: overflow:hidden is what clips the
     img to the corner curve, so the two have to stay together. */
  border-radius: var(--radius-portrait);
  overflow: hidden;
  /* Cap the width on narrow screens so the portrait does not blow up to full
     bleed and reintroduce exactly the problem this layout solves. */
  max-width: 8.5rem;
}
.roster__figure .placeholder { padding: var(--space-2xs); font-size: 0.625rem; }
/* Sources are landscape or square dropping into a portrait frame, so a centered
   cover crop cuts heads off. This is the fallback; individual photos override
   it via the `focus` field in _data/providers.yml, set inline. */
.roster__figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 22%;
}

.roster__name {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: var(--weight-light);
  margin: 0 0 var(--space-3xs);
}
.roster__creds {
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-accent);
  margin: 0 0 var(--space-m);
}
.roster__blurb {
  font-size: var(--step-0);
  line-height: var(--leading-normal);
  color: var(--text-secondary);
  max-width: 52ch;
  margin: 0 0 var(--space-xs);
}

/* --- Disclosure ---------------------------------------------------------
   Native <details>. The summary is restyled as a quiet tracked-caps control
   with a rotating chevron; the default triangle marker is removed on both the
   standards path and the old WebKit one. */
.roster__more { margin-top: var(--space-2xs); }
.roster__more > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  cursor: pointer;
  list-style: none;                 /* Firefox / standards */
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-primary);
  padding-block: var(--space-3xs);
  transition: color var(--duration-fast) var(--ease-out);
}
.roster__more > summary::-webkit-details-marker { display: none; }
.roster__more > summary:hover { color: var(--text-accent); }

/* The label carries a gold underline that reads as an affordance without
   turning the control into a link. */
.roster__more-label {
  border-bottom: 1px solid var(--mana-gold);
  padding-bottom: 0.15em;
}

.roster__more > summary::after {
  content: '';
  width: 0.4em;
  height: 0.4em;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: translateY(-0.15em) rotate(45deg);
  transition: transform var(--duration-base) var(--ease-out);
}
.roster__more[open] > summary::after { transform: translateY(0.1em) rotate(-135deg); }
.roster__more[open] > summary { margin-bottom: var(--space-s); }

.roster__bio {
  font-size: var(--step--1);
  line-height: 1.75;
  color: var(--text-secondary);
  max-width: 58ch;
  margin: 0;
}
/* Fade the panel in rather than having it snap. Height is left alone — native
   details cannot animate it without interpolate-size, and a half-supported
   height transition is worse than none. */
.roster__more[open] .roster__bio { animation: roster-reveal var(--duration-base) var(--ease-out); }
@keyframes roster-reveal {
  from { opacity: 0; transform: translateY(-0.25rem); }
  to   { opacity: 1; transform: none; }
}

.roster__note { margin-top: var(--space-m); }


/* --- Results / gallery ------------------------------------------------ */
.gallery { display: grid; gap: var(--space-l); }
@media (min-width: 48rem) { .gallery { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 68rem) { .gallery { grid-template-columns: repeat(3, 1fr); } }
.gallery figure { margin: 0; }
.gallery__pair { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--surface-page); }
.gallery__slot {
  aspect-ratio: 1;
  background: var(--mana-sand);
  display: grid;
  place-items: center;
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--mana-ink-soft);
}
.gallery figcaption {
  padding-top: var(--space-s);
  font-size: var(--step--1);
  line-height: 1.7;
  color: var(--text-secondary);
}
.gallery figcaption b {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: var(--weight-regular);
  color: var(--text-primary);
  margin-bottom: var(--space-3xs);
}


/* The short-form FDA line, under the individual treatments that need it.
   Deliberately not styled as a warning box: a red panel per treatment would
   read as a hazard notice on a page where the point is candour, not alarm.
   A gold rule and small caps says "read this" without shouting. */
.treatment__fda {
  margin-top: var(--space-m);
  padding-top: var(--space-xs);
  border-top: var(--hairline-gold);
  font-size: var(--step--1);
  line-height: 1.7;
  color: var(--text-secondary);
  max-width: 60ch;
}


/* Effective / last-updated line under the Privacy heading. Set down and quiet:
   it is metadata about the policy, not part of it, and at body size it competed
   with the first real sentence. */
.policy-dates {
  font-size: var(--step--1);
  letter-spacing: 0.04em;
  color: var(--text-secondary);
  margin-top: calc(var(--space-xs) * -1);
}


/* A postal address set inside running prose. Needs its line breaks kept and a
   little room, without becoming a block quote. */
.prose-address {
  line-height: 1.7;
  margin-left: var(--space-s);
  border-left: var(--hairline-gold);
  padding-left: var(--space-s);
}


/* The four ways results arrive, on /results/. Cards rather than a table: each
   one is a paragraph of reasoning plus its examples, and a table would force
   them into cells they do not fit. Two-up rather than four-across — at four the
   examples wrap to six lines each and the grid reads as a spec sheet. */
.pattern-grid { display: grid; gap: var(--space-l); margin-top: var(--space-xl); }
@media (min-width: 52rem) {
  .pattern-grid { grid-template-columns: repeat(2, 1fr); gap: var(--space-xl); }
}
.pattern {
  border-top: var(--hairline-gold);
  padding-top: var(--space-m);
}
.pattern h3 { margin-bottom: var(--space-xs); }
/* The examples carry the actual numbers, so they get the quieter treatment that
   makes the reasoning above them read first. */
.pattern__eg {
  font-size: var(--step--1);
  line-height: 1.75;
  color: var(--text-secondary);
  border-left: var(--hairline);
  padding-left: var(--space-s);
  margin-bottom: var(--space-m);
}
.pattern__eg strong { color: var(--text-primary); font-weight: var(--weight-medium); }


/* --- Published reviews -------------------------------------------------
   Three .c-quote figures under the reviews band. The component itself lives
   in mana-tokens.css; this is only the arrangement.

   Single column until there is room for three, because a quote set in display
   italic at 34ch is unreadable in a third of a narrow viewport. No 2-up
   middle step: three quotes in two columns leaves one orphan, which reads as
   a mistake rather than a layout. */
.quotes {
  display: grid;
  gap: var(--space-l);
  margin-top: var(--space-xl);
}
@media (min-width: 56rem) {
  .quotes {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-xl);
  }
}
/* The component caps itself at 34ch for a full-width setting. Inside a third
   of the wrap that cap fights the column, leaving a ragged gutter. */
.quotes .c-quote { max-width: none; }


/* --- Contact ----------------------------------------------------------
   Two blocks, one job each: where the place is, then how to reach it.
   The map leads the first block and takes the wider column — on a page
   called "Visit us" the location is the content, not an illustration
   beside it. Was .contact-grid, two equal columns of six same-sized
   headings, which gave the page no first read and left the two columns
   ending at different heights. */
.visit-locate { display: grid; gap: var(--space-l); }
@media (min-width: 56rem) {
  .visit-locate { grid-template-columns: 1.35fr 1fr; gap: var(--space-2xl); align-items: start; }
}
.visit-locate__side h2 { margin-bottom: var(--space-s); }
/* A subhead inside the block, not a peer of "Where we are" — directions
   are an attribute of the address, so they read one level down. */
.visit-locate__side h3 {
  font-size: var(--step-2);
  margin-top: var(--space-l);
  padding-top: var(--space-m);
  border-top: var(--hairline);
}
.visit-address {
  font-style: normal;
  font-size: var(--step-1);
  font-weight: var(--weight-light);
  line-height: var(--leading-snug);
  margin-bottom: var(--space-s);
}

/* When we are open on the left, how to reach us on the right. Was three
   equal columns headed Hours / Call / Book, which named the channels but
   left you to work out which one your question belonged to. */
.visit-reach { display: grid; gap: var(--space-l); }
/* Hours is seven short rows and the contact column is roughly twice its
   height, so the columns will never end together. Narrowing the table side
   makes that rag read as a decision rather than as a hole: a short narrow
   column beside a tall one is a margin, a short wide one is a gap. */
@media (min-width: 56rem) {
  .visit-reach { grid-template-columns: 0.8fr 1.2fr; gap: var(--space-2xl); align-items: start; }
}
/* Block labels, not page titles. At step-3 these words were the loudest
   thing on the page and all shouted at the same volume. */
.visit-reach h2 { font-size: var(--step-2); margin-bottom: var(--space-s); }
.visit-reach > div > p:last-child { margin-bottom: 0; }

/* The two options stack, divided by a hairline rather than by a gap alone —
   they are alternatives, and a rule says "or" where whitespace only says
   "and then". The right column carries no wrapper heading: "Ask us something
   first" and "Book an appointment" are the headings that matter, and a
   "Get in touch" above them would only be a label for a label. They are h2s,
   peers of Hours — as h3s the outline read them as subsections of the opening
   times, which is not what they are. */
.visit-option + .visit-option {
  margin-top: var(--space-l);
  padding-top: var(--space-l);
  border-top: var(--hairline);
}
.visit-option h2 { margin-bottom: var(--space-2xs); }

/* The one sentence on this page written like a person talking. It was a
   clause in the middle of a paragraph and read as filler; on its own in
   display italic it is the reason to pick up the phone.

   Gold on the raised band is 4.24:1, under AA for body copy — which is why
   this rule also pins the size. step-2 never resolves below 24px, so this is
   large text, where AA asks 3:1. Do not reuse this color at body size. */
.visit-ask {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-style: italic;
  font-weight: var(--weight-light);
  line-height: var(--leading-snug);
  color: var(--text-accent);
  max-width: 24ch;
  margin-bottom: var(--space-m);
}
/* Same gold-dash rows as the membership tiers rather than a second list
   idiom invented for one block. */
.visit-asks {
  list-style: none;
  margin: 0 0 var(--space-m);
  padding: 0;
}
.visit-asks li {
  padding-block: var(--space-2xs);
  border-bottom: var(--hairline);
  font-size: var(--step-0);
}
.visit-asks li::before {
  content: '\2014';
  color: var(--mana-gold);
  margin-right: 0.6em;
}
.visit-option > p:last-child { margin-bottom: 0; }
.visit-phones {
  font-size: var(--step-2);
  font-weight: var(--weight-light);
  line-height: var(--leading-snug);
  margin-bottom: 0;
}
.visit-note {
  font-size: var(--step--1);
  line-height: 1.7;
  color: var(--text-secondary);
  margin-top: var(--space-s);
}
.visit-flags { margin: 0; max-width: none; }

.hours-table { width: 100%; border-collapse: collapse; font-size: var(--step-0); }
.hours-table th, .hours-table td {
  text-align: left;
  padding: var(--space-xs) 0;
  border-bottom: var(--hairline);
}
.hours-table th { font-weight: var(--weight-regular); color: var(--text-secondary); }
.hours-table td { text-align: right; white-space: nowrap; }
.hours-table td.is-closed { color: var(--text-secondary); }

.map-slot {
  /* Fluid height rather than aspect-ratio plus min-height. Those two together
     let the browser derive WIDTH from the constrained height — at 375px the
     17rem floor resolved to a 435px-wide box and pushed the whole page into
     horizontal scroll. Height alone can never do that. */
  width: 100%;
  /* Taller now that the map leads its block rather than sharing half a
     column with the address — at 24rem beside a full address stack it read
     as a thumbnail of the place instead of the place. */
  height: clamp(18rem, 34vw, 27rem);
  background: var(--mana-sand);
  display: grid;
  place-items: center;
  text-align: center;
  overflow: hidden;
}
/* Padding belongs to the placeholder, never the frame. On the frame it inset
   the iframe and matted the map in a sand border — the same mistake that was
   quietly framing every provider photograph. */
.map-slot .placeholder { padding: var(--space-l); }
.map-slot iframe { width: 100%; height: 100%; border: 0; display: block; }


/* --- Membership tiers -------------------------------------------------- */
.tier-grid { display: grid; gap: var(--space-xl); }
@media (min-width: 52rem) { .tier-grid { grid-template-columns: repeat(2, 1fr); gap: var(--space-2xl); } }
.tier { border-top: 1px solid var(--mana-gold); padding-top: var(--space-m); }
.tier h2 { font-size: var(--step-2); }
.tier__list { list-style: none; margin: 0 0 var(--space-m); padding: 0; }
.tier__list li {
  padding-block: var(--space-2xs);
  border-bottom: var(--hairline);
  font-size: var(--step-0);
}
.tier__list li::before {
  content: '\2014';
  color: var(--mana-gold);
  margin-right: 0.6em;
}


/* --- Footer ------------------------------------------------------------ */
/* The bottom margin only exists to clear the fixed booking bar, so it only
   applies where that bar is actually shown. */
@media (max-width: 63.99rem) { .footer { margin-bottom: 4.5rem; } }

.footer {
  background: var(--surface-sunk);
  color: var(--text-primary);
  border-top: 1px solid var(--mana-gold);
  /* Was 6.5rem/4rem. A footer is the last thing on the page, not a section of
     it; that much air above the columns made it read as another band. */
  padding-block: var(--space-xl) var(--space-l);
}
.footer__grid { display: grid; gap: var(--space-xl); }
@media (min-width: 48rem) { .footer__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 62rem) { .footer__grid { grid-template-columns: 1.4fr 1fr 1fr; } }
/* Five columns, one thing in each. The address and the hours are separated
   because together they made one column twice the height of the others, and
   the tallest column is what sets the height of the whole footer. Both need
   more width than the link columns: "Wednesday" beside a full time range, and
   a street address, each have to sit on one line. */
@media (min-width: 78rem) {
  .footer__grid {
    grid-template-columns: 1.35fr 0.7fr 0.8fr 0.95fr 1.05fr;
    gap: var(--space-l);
  }
}
.footer__brand { grid-column: 1 / -1; }
@media (min-width: 76rem) { .footer__brand { grid-column: auto; } }
/* Sized to its label rather than stretched to the column, and with tighter
   side padding than a body button: at the brand column's width the default
   2.5rem each side pushed "BOOK A CONSULTATION" onto two lines. */
/* The phone number, promoted out of the address column. Set at display size
   because it is an action, not a detail — it sits directly above the booking
   button and the two should read as a pair of equals. */
.footer__call {
  margin: 0 0 var(--space-s);
}
.footer__call-label {
  display: block;
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: var(--space-3xs);
}
.footer__call a {
  /* Came down twice. It began at --step-2 in the display serif, which put it in
     competition with the wordmark above it; --step-1 still read as a heading
     rather than a phone number.

     Both levers now: body face instead of the display serif, and body size.
     The serif was carrying most of the weight — at a matched size it reads
     considerably heavier than Karla. What marks this as the action is the
     label above it and the button below it, not the type size. */
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.2;
  color: var(--text-primary);
  text-decoration: none;
}
.footer__call a:hover {
  color: var(--text-accent);
  text-decoration: underline;
  text-decoration-color: var(--mana-gold);
}

.footer__cta { align-self: start; padding-inline: var(--space-m); }
.footer__brand { display: flex; flex-direction: column; align-items: flex-start; }

.footer__motto {
  color: var(--text-secondary);
  font-size: var(--step--1);
  line-height: 1.7;
  max-width: 34ch;
  margin-block: var(--space-s) var(--space-m);
}
.footer__head {
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-accent);
  margin-bottom: var(--space-m);
}
/* --- Locations hub -------------------------------------------------------
   One block per location, separated by a rule rather than boxed. Same reason
   the rest of the site avoids filled cards: weight comes from space and
   hairlines. The separator goes on the adjacent sibling so a single-location
   site — or a third location — needs no change here. */
.location-card + .location-card {
  margin-top: var(--space-xl);
  padding-top: var(--space-xl);
  border-top: var(--hairline);
}
.location-card > h2 { margin-bottom: var(--space-2xs); }
.location-card .hours-table { margin-block: var(--space-s); }

.footer__list { list-style: none; margin: 0; padding: 0; font-size: var(--step--1); }
.footer__list li { padding-block: var(--space-3xs); }
/* Each address in the Visit column is now labelled with its town, and Toms
   River carries two qualifiers under it — the host building, and that it is
   appointment-only. Both are the kind of thing someone needs BEFORE they
   drive, so they sit with the address rather than on the location page alone. */
.footer__place {
  display: block;
  color: var(--text-primary);
  margin-bottom: var(--space-3xs);
}
.footer__inside {
  display: block;
  color: var(--text-secondary);
  font-size: var(--step--1);
}
/* Space between the two addresses, and before the phone line that follows
   them, so the column reads as three blocks rather than one run-on. */
.footer__address + .footer__address { margin-top: var(--space-s); }

.footer__list a, .footer__address a {
  color: var(--text-secondary);
  text-decoration: none;
}
.footer__list a:hover, .footer__address a:hover {
  color: var(--text-primary);
  text-decoration: underline;
  text-decoration-color: var(--mana-gold);
}
/* --- Social icons -------------------------------------------------------
   A row of bare glyphs under the brand. Sized generously and given real
   padding so the tap target clears 44px even though the mark itself is
   20px — an icon-only link that is only as big as its icon is a miss on a
   phone. */
.footer__social {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  list-style: none;
  margin: var(--space-s) 0 0;
  padding: 0;
}
.footer__social a {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  margin-left: -0.6rem;          /* optically flush the first glyph left */
  color: var(--text-accent);
  border-radius: var(--radius-pill);
  transition: color var(--duration-fast) var(--ease-out),
              background var(--duration-fast) var(--ease-out);
}
.footer__social a:hover,
.footer__social a:focus-visible {
  color: var(--mana-ink);
  background: rgba(172, 132, 0, 0.10);
}
.footer__social .c-icon { width: 1.25rem; height: 1.25rem; }

/* Two aligned columns, not space-between. Pushing the day left and the time
   hard right across a wide column opened a river down the middle and made four
   short rows read as a scattered table. A fixed day column puts the times in a
   tidy stack immediately after them. */
.footer__list--hours li {
  display: grid;
  grid-template-columns: 5.25rem 1fr;
  align-items: baseline;
  gap: var(--space-2xs);
  color: var(--text-secondary);
}
/* A time range is a single unit — never break it across lines. */
.footer__list--hours li > span:last-child { white-space: nowrap; }
/* Closed days read exactly like the open ones. They were set in --mana-sand,
   which is #E2DCD0 on a #F1ECE3 footer — about 1.1:1, so "Friday Closed" was
   very nearly invisible. Sand is a hairline color and is marked DECORATIVE
   ONLY in the tokens for this reason; it must never carry text. When a
   practice is closed on a weekday that is information people need, not
   something to play down. */
.footer__list--hours .is-closed span:first-child {
  font-weight: var(--weight-medium);
  color: var(--text-primary);
}
.footer__note { font-size: var(--step--1); color: var(--text-secondary); margin-top: var(--space-m); }
.footer__address {
  font-style: normal;
  font-size: var(--step--1);
  line-height: 1.8;
  color: var(--text-secondary);
  margin-bottom: var(--space-m);
}
.footer__address .footer__phones { display: block; margin-top: var(--space-2xs); }
.footer__legal {
  margin-top: var(--space-l);
  padding-top: var(--space-m);
  border-top: var(--hairline);
  font-size: var(--step--1);
  line-height: 1.7;
  color: var(--text-secondary);
}
/* Runs the full width of the footer. It was capped at 78 characters, which
   stopped it a little under halfway across and read as unfinished beneath a
   rule that spans everything. */
.footer__legal p { max-width: none; margin-bottom: var(--space-s); }
.footer__legal-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-m);
  margin-bottom: 0;
}


/* --- Prose pages (policies, accessibility) ------------------------------ */
.prose { max-width: var(--prose-max); margin-inline: auto; }
.prose h2 { font-size: var(--step-2); margin-top: var(--space-xl); scroll-margin-top: 7rem; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { font-size: var(--step-1); margin-top: var(--space-l); }
.prose ul { padding-left: 1.1em; }
.prose li { margin-bottom: var(--space-2xs); max-width: var(--measure); }
.prose li::marker { color: var(--mana-gold); }


/* --- Editorial note -----------------------------------------------------
   Visible marker for content that still needs a real answer. Delete the
   markup — and this rule — before launch. Nothing ships half-written by
   accident because these are impossible to miss. */
.todo {
  display: inline-block;
  background: #FBEFE9;
  border: 1px dashed var(--mana-alert);
  color: var(--mana-alert);
  font-size: var(--step--1);
  line-height: 1.6;
  padding: 0.15em 0.6em;
  border-radius: var(--radius-s);
}


/* --- Reveal on scroll ---------------------------------------------------
   Progressive enhancement. Elements are visible by default and only
   hidden once JS confirms it can bring them back — no-JS visitors and
   reduced-motion users see everything immediately. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(1.25rem);
  transition: opacity var(--duration-slow) var(--ease-out),
              transform var(--duration-slow) var(--ease-out);
}
.js [data-reveal].is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] { opacity: 1; transform: none; }
}
