/* ==========================================================================
   C&A Tanning & Beauty
   Design system — white / gold / black
   Gold values sampled from the client's own logo and shopfront fascia.
   ========================================================================== */

/* --- Tokens ------------------------------------------------------------- */

:root {
  /* Gold ramp. 300–500 come straight off the logo gradient. 600/700 are
     darkened so text and icons pass contrast on the cream surfaces too. */
  --gold-50:  #FBF7EE;
  --gold-100: #F5EDDC;
  --gold-200: #EDE0C4;
  --gold-300: #E0D0B0;  /* logo — pale champagne */
  --gold-400: #D0C090;  /* logo — mid */
  --gold-500: #C0A080;  /* logo — deep */
  --gold-600: #A98842;
  --gold-700: #836728;  /* 4.8:1 on --card, the darkest surface it sits on */

  --ink:        #0D0D0D;
  --ink-soft:   #1A1A1A;
  --ink-line:   #262626;

  --text:       #4A4A4A;
  --text-strong:#111111;
  --text-mute:  #6B6B6B;  /* 4.8:1 on --card; #767676 only reached 4.1:1 there */
  --text-on-dark:      #FFFFFF;
  --text-on-dark-mute: #A8A8A8;

  --white: #FFFFFF;
  --cream: #FAF7F0;
  --card:  #F7F3E9;

  --rule: rgba(13, 13, 13, .10);
  --rule-gold: rgba(138, 109, 44, .28);

  /* Type */
  --font-display: "Onest", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body:    "Onest", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-eyebrow: "Poppins", system-ui, sans-serif;

  /* Fluid type scale */
  /* Dropped ~22% on 24 Aug 2026 - it was clamp(2.75rem, 1.6rem + 5.1vw, 5.75rem),
     which read as 92px at 1280 and up and overwhelmed the subhead under it.
     Now 72px there and 38px on a phone. */
  --fs-hero:    clamp(2.375rem, 1.4rem + 4vw, 4.5rem);
  --fs-section: clamp(2rem, 1.35rem + 2.9vw, 3.25rem);
  --fs-h3:      clamp(1.35rem, 1.2rem + .7vw, 1.75rem);
  --fs-body:    1rem;
  --fs-sm:      .875rem;

  /* Rhythm */
  --container: 1240px;
  --gutter: clamp(1.25rem, .6rem + 2.6vw, 3rem);
  --header-h: 76px;
  /* Everything stacked above the hero: the gold utility strip plus the nav bar.
     The strip is min-height 44px and measured exactly 44 at every width from 300
     to 1440 - its list hides below 460px rather than wrapping - so this is a real
     constant, not an approximation. The hero subtracts it to fill the rest of the
     screen; if either band ever changes height, change it here. */
  --above-hero: calc(var(--header-h) + 44px);
  /* White margin round the home hero, which sits as a rounded panel (Lewis,
     11 Oct 2026). Subtracted twice from the hero height so it still fills the
     screen exactly. */
  --hero-gap: clamp(10px, 1.4vw, 22px);
  /* Was 8.5rem at the top end, which left the page reading as half-empty while
     images are still placeholders. */
  --section-y: clamp(3.25rem, 2.25rem + 3.4vw, 5.5rem);

  /* Shape */
  --r-card: 16px;
  --r-input: 8px;
  --r-pill: 1000px;
  --r-arch: 200px 200px 0 0;

  /* Motion — one curve for the whole site, as per the reference */
  --ease: cubic-bezier(.22, 1, .36, 1);
  --dur:  .6s;
  --dur-fast: .42s;
}

/* --- Reset -------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--text);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-display);
  color: var(--text-strong);
  line-height: 1.1;
  letter-spacing: -.02em;
  font-weight: 700;
  text-wrap: balance;
}

p { margin: 0; }
img, svg, video { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; border: 0; background: none; cursor: pointer; }
input, textarea, select { font: inherit; color: inherit; }
ul { margin: 0; padding: 0; list-style: none; }

:focus-visible {
  outline: 3px solid var(--gold-700);
  outline-offset: 3px;
  border-radius: 4px;
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
/* The honeypot input keeps its default ~213px width otherwise, which is
   clipped and harmless but shows up in every overflow audit. */
.visually-hidden input { width: 100%; }

.skip-link {
  position: absolute; top: 0; left: 50%; z-index: 200;
  transform: translate(-50%, -110%);
  padding: .75rem 1.25rem;
  background: var(--ink); color: var(--white);
  border-radius: 0 0 8px 8px;
  transition: transform .2s var(--ease);
}
.skip-link:focus { transform: translate(-50%, 0); }

/* --- Layout ------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: var(--section-y); position: relative; }
.section--cream { background: var(--cream); }
.section--dark  { background: var(--ink); color: var(--text-on-dark-mute); }
/* A soft gold hatch for sections that carry no photograph, so they read as
   deliberate rather than as an empty column. Same motif as the .ph blocks.
   Sits on --cream so it stays distinct from the plain white sections. */
.section--hatch {
  background:
    repeating-linear-gradient(135deg, transparent 0 20px, rgba(131,103,40,.045) 20px 40px),
    linear-gradient(165deg, var(--gold-50), var(--cream) 55%, var(--white));
}
/* Less vertical padding for sections with no image to balance against. */
.section--tight { padding-block: clamp(2.5rem, 1.9rem + 2.2vw, 4rem); }

.section--dark h2, .section--dark h3 { color: var(--text-on-dark); }

.section-head { max-width: 720px; margin-inline: auto; text-align: center; margin-bottom: clamp(1.75rem, 2.5vw, 2.75rem); }
.section-head--left { margin-inline: 0; text-align: left; }

.eyebrow {
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--font-eyebrow);
  font-size: .8125rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--gold-700);
  margin-bottom: 1rem;
}
.eyebrow::before { content: "◆"; font-size: .7em; }
.section--dark .eyebrow { color: var(--gold-400); }

.section-title { font-size: var(--fs-section); }
.section-sub { margin-top: 1rem; color: var(--text-mute); font-size: 1.0625rem; }
.section--dark .section-sub { color: var(--text-on-dark-mute); }

/* Faint oversized botanical watermark behind a section */
.section__watermark {
  position: absolute; inset: 0;
  background-repeat: no-repeat;
  opacity: .04;
  pointer-events: none;
  z-index: 0;
}
.section > .container { position: relative; z-index: 1; }

/* --- Buttons ------------------------------------------------------------ */

.btn {
  --btn-bg: var(--gold-300);
  --btn-fg: var(--ink);
  display: inline-flex; align-items: center; gap: .875rem;
  padding: 1rem 1.75rem;
  background: var(--btn-bg); color: var(--btn-fg);
  font-family: var(--font-eyebrow);
  font-size: .8125rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  border-radius: var(--r-pill);
  transition: background var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease);
  /* No will-change here. It was promoting every button on the page to its own
     compositor layer permanently, which held the page at ~30fps while idle.
     will-change is a hint for imminent change, not a blanket optimisation. */
}
.btn:hover { transform: translateY(-2px); }

.btn--gold  { background: linear-gradient(105deg, var(--gold-300), var(--gold-400)); }
.btn--gold:hover { background: linear-gradient(105deg, var(--gold-400), var(--gold-500)); }
.btn--dark  { --btn-bg: var(--ink); --btn-fg: var(--white); }
.btn--dark:hover { --btn-bg: var(--ink-soft); }
.btn--ghost {
  --btn-bg: transparent; --btn-fg: var(--text-strong);
  box-shadow: inset 0 0 0 1px var(--rule-gold);
}
.btn--ghost:hover { --btn-bg: var(--gold-50); }

/* Label roll-up: two stacked copies, both slide on hover.
   Three things have to hold or this breaks:
   - nowrap, or a narrow button wraps the label and the clipped second line
     shows through the roll (the nav CTA read "Book" then "now" on hover);
   - flex: none, or the label shrinks below its text width and wraps anyway;
   - height must equal the line-height, since the roll moves exactly 100% of
     the span, and any mismatch leaves the copy half-out of the window. */
.btn__label {
  position: relative; display: block; flex: none;
  overflow: hidden;
  height: 1.25em; line-height: 1.25;
  white-space: nowrap;
}
.btn__label span {
  display: block; line-height: 1.25; white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease);
}
.btn__label span + span { position: absolute; inset: 100% auto auto 0; }
.btn:hover .btn__label span { transform: translateY(-100%); }

/* Twin arrows: one leaves right, one enters from the left. */
.btn__arrow { position: relative; width: 20px; height: 20px; overflow: hidden; flex: none; }
.btn__arrow svg { position: absolute; inset: 0; width: 20px; height: 20px; transition: transform var(--dur-fast) var(--ease); }
.btn__arrow svg:last-child { transform: translateX(-160%); }
.btn:hover .btn__arrow svg:first-child { transform: translateX(160%); }
.btn:hover .btn__arrow svg:last-child  { transform: translateX(0); }


/* --- Hero intro --------------------------------------------------------- */

/* The hero plays once on load rather than waiting for the IntersectionObserver,
   so its timing is deterministic and it can never be left hidden if the
   observer is slow. Gated on .js like every other hiding rule — see the note
   in CLAUDE.md about the blank-page risk. */

/* Scale only, never opacity: the hero photograph is the LCP element, so it
   must be painted on the first frame. A settle from 1.06 reads as an intro
   without costing anything in Largest Contentful Paint. */
.js .hero__bg img { transform: scale(1.06); }
.hero.is-intro .hero__bg img {
  transform: none;
  transition: transform 1.5s var(--ease);
}

/* Offsets so the copy follows the photograph in rather than racing it. The
   base .reveal delay is var(--i) * 55ms; inside the hero the copy waits for the
   headline to finish landing (words run 300-510ms) and then steps wider. */
.js .hero .reveal { transition-delay: calc(420ms + var(--i, 0) * 120ms); }
.js .hero .reveal-words .word { transition-delay: calc(300ms + var(--w, 0) * 42ms); }

@media (prefers-reduced-motion: reduce) {
  .js .hero__bg img,
  .hero.is-intro .hero__bg img { transform: none !important; transition: none !important; }
  .js .hero .reveal, .js .hero .reveal-words .word { transition-delay: 0s !important; }
}
/* --- Motion: reveal on scroll ------------------------------------------- */

/* Blur was 8–10px over 600ms with a 90ms stagger. Mid-scroll that left whole
   sections smeared and reading as broken, so it is lighter and quicker now. */
.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  filter: blur(4px);
  transition: opacity .5s var(--ease),
              transform .5s var(--ease),
              filter .5s var(--ease);
  transition-delay: calc(var(--i, 0) * 55ms);
}
.reveal.is-in { opacity: 1; transform: none; filter: blur(0); }

/* Per-word heading reveal */
.js .reveal-words .word {
  display: inline-block;
  opacity: 0;
  transform: translateY(.32em);
  filter: blur(5px);
  transition: opacity .45s var(--ease), transform .45s var(--ease), filter .45s var(--ease);
  transition-delay: calc(var(--w, 0) * 26ms);
}
.reveal-words.is-in .word { opacity: 1; transform: none; filter: blur(0); }

/* Arched / framed media wipes open from the bottom as it enters. */
.js .reveal-media { clip-path: inset(0 0 100% 0); transition: clip-path .9s var(--ease); }
.reveal-media.is-in { clip-path: inset(0 0 0 0); }
.js .reveal-media img { transform: scale(1.12); transition: transform 1.2s var(--ease); }
.reveal-media.is-in img { transform: scale(1); }

/* Elements given a parallax drift by JS */
.parallax { will-change: transform; }

/* --- Lenis smooth scroll ------------------------------------------------ */

html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }

/* --- Marquee ------------------------------------------------------------ */

/* Light band, 24 Aug 2026. This was black and so was the header; with the hero
   between them the page top read as three dark bands stacked. The hero is now
   the only dark block up there, and this band is cream with a gold hairline so
   it still separates from the hatched About section below it. */
.marquee {
  overflow: hidden;
  background: var(--cream);
  padding-block: 1.15rem;
  border-block: 1px solid var(--rule-gold);
}
.marquee__track {
  display: flex; width: max-content;
  /* Duration = group width / 46px/s, the speed the ribbon has always run at.
     The group is 1578px at desktop with the seven-item list of 10 Oct 2026, so
     34s; it was 27s for the six-item 1252px group, and keeping that would have
     run 26% fast. Change the items and this has to be re-derived. */
  animation: marqueeScroll 34s linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__group {
  display: flex; align-items: center; gap: 2rem;
  padding-right: 2rem; flex: none;
}
.marquee__item {
  display: inline-flex; align-items: center; gap: 2rem;
  font-family: var(--font-display); font-weight: 700;
  /* Down from clamp(1.15rem, .95rem + .9vw, 1.85rem) on 24 Aug 2026: 28px at
     desktop had the ribbon competing with the section headings. 22px now, and
     the dot and gaps came down with it or they read as oversized. */
  font-size: clamp(1rem, .8rem + .7vw, 1.4rem);
  letter-spacing: -.01em; white-space: nowrap;
  color: var(--text-strong);
}
.marquee__item::after {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--gold-600); flex: none;
}
/* Alternating items are gold rather than near-black. A solid fill, not an
   outline stroke: the stroke read as hollow and thinned the word out at small
   sizes. gold-700 rather than the logo gold-300, because the band is light now
   - gold-300 on cream is about 1.3:1 and simply vanishes. */
.marquee__item:nth-child(even) { color: var(--gold-700); }
/* -25% = exactly one of the four groups. See the note in index.html: the group
   count and this percentage have to agree, and together they set the widest
   viewport that loops without a gap. */
@keyframes marqueeScroll { to { transform: translateX(-25%); } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .marquee__track { animation: none; }
  .reveal, .reveal-words .word {
    opacity: 1 !important; transform: none !important;
    filter: none !important; transition: none !important;
  }
  .reveal-media { clip-path: none !important; }
  .reveal-media img { transform: none !important; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* --- Header ------------------------------------------------------------- */

.utility {
  background: linear-gradient(100deg, var(--gold-300), var(--gold-400));
  color: var(--ink);
  font-size: .8125rem;
}
.utility__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; min-height: 44px; padding-block: .4rem;
}
.utility__list { display: flex; align-items: center; gap: 1.75rem; flex-wrap: wrap; }
.utility__item { display: inline-flex; align-items: center; gap: .5rem; }
.utility__item svg { width: 15px; height: 15px; flex: none; }
.utility a:hover { text-decoration: underline; }

.utility__right { display: flex; align-items: center; gap: 1.25rem; }
/* The number is the main call to action on a salon site, so it gets weight. */
.utility__phone {
  display: inline-flex; align-items: center; gap: .5rem;
  font-weight: 700; font-size: .9375rem;
  letter-spacing: .01em;
}
.utility__phone svg { width: 16px; height: 16px; flex: none; }

@media (max-width: 720px) {
  .utility__inner { justify-content: space-between; gap: .75rem; }

  .utility__list { gap: 1rem; font-size: .75rem; }
}
@media (max-width: 460px) {
  .utility__list { display: none; }
  .utility__inner { justify-content: center; }
}

.utility__socials { display: flex; gap: .875rem; }
.utility__socials a {
  display: grid; place-items: center; width: 26px; height: 26px;
  color: var(--ink);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.utility__socials a:hover { opacity: .7; transform: translateY(-1px); }
.utility__socials svg { width: 19px; height: 19px; }

/* Cream bar as of 24 Aug 2026, requested, and the logo tab with it. Two
   knock-ons handled below: the tab needed a darkened copy of the logo, because
   the shipped one is pale champagne on transparency and measures ~1.3:1 on
   cream; and the Book pill had to go dark, because a gold-300 fill is ~1.3:1
   against cream and stopped reading as a button. */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: var(--cream);
  transition: box-shadow var(--dur-fast) var(--ease);
  /* No backdrop-filter here on purpose: it would make this a containing block
     for the fixed mobile drawer, and it would disqualify the header from
     iOS 26 status-bar colour sampling. Keep it opaque. */
}
/* Three columns so the centre one reserves clear space for the logo tab.
   The middle column is fixed, so the two 1fr columns absorb every width change
   and the clearance either side of the tab is constant at any viewport.

   That clearance is the whole point. With Pricing, Locations and Contact all
   in the right-hand group, that group measured 458px against a 407px column;
   .nav__right is justify-content: flex-end, so the overflow ran leftward and
   the links sat 18.7px *under* the tab. Moving Pricing into the left group
   brought it to 371px, and the 200px centre column adds a little more margin.
   Check the real content edges, not the ul box, which stretches to its column. */
.nav {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 200px 1fr;
  align-items: center;
  gap: 1rem;
  min-height: var(--header-h);
}
.nav__links--left { grid-column: 1; }
/* The notch is absolutely positioned and so occupies no cell — without an
   explicit column this lands in the middle one, under the logo. */
.nav__right {
  grid-column: 3;
  display: flex; align-items: center; justify-content: flex-end;
  gap: clamp(1rem, 2vw, 1.75rem);
}

/* The tab is cream too as of 24 Aug 2026, so the whole header is one light
   surface with a bulge at the bottom centre. That needed a second logo file:
   logo.png is pale champagne on transparency and measures about 1.3:1 on cream,
   so the tab carries logo-on-light.png, the same artwork multiplied down to an
   average of --gold-700. See CLAUDE.md before swapping either one back.

   Two consequences. The tab only reads as a tab where it overhangs something
   darker, which in practice means the hero - elsewhere it dissolves into the
   bar, and that is a feature, because a black tab used to track over every
   centred section heading it passed. And the concave fillets are inert again:
   they sit inside the header's own box, so they only show when the tab and the
   bar are different colours. They were ink-on-ink for their whole life before
   today, and were briefly visible while the tab was black on a cream bar.

   Centred logo in a black tab that hangs below the bar — but only at the very
   top of the page, where it has the hero beneath it and nothing to obscure.
   The moment the header condenses (past 80px) the tab retracts flush into the
   bar, see .is-scrolled below.

   That condition is the whole point. Rising above the bar clipped the logo
   once the header stuck, because the utility strip scrolls away. Hanging below
   it permanently put an opaque tab over every centred section heading it
   passed. Protruding only while parked at the top avoids both. */
.nav__notch {
  --notch-drop: 26px;   /* how far the tab hangs below the bar */
  --notch-fillet: 20px;
  position: absolute; left: 50%; top: 0; transform: translateX(-50%);
  display: grid; place-items: center;
  width: 168px;
  height: calc(100% + var(--notch-drop));
  padding-bottom: .35rem;
  background: var(--cream);
  border-radius: 0 0 34px 34px;
  transition: width var(--dur-fast) var(--ease),
              height var(--dur-fast) var(--ease),
              border-radius var(--dur-fast) var(--ease);
}
/* Concave fillets, sitting where the tab exits the underside of the bar —
   which is --notch-drop up from the tab's own bottom edge, not at its top. */
.nav__notch::before,
.nav__notch::after {
  content: ""; position: absolute;
  bottom: var(--notch-drop);
  width: var(--notch-fillet); height: var(--notch-fillet);
  opacity: 1; transition: opacity var(--dur-fast) var(--ease);
}
.nav__notch::before {
  left: calc(var(--notch-fillet) * -1);
  background: radial-gradient(circle at 0 0, transparent var(--notch-fillet), var(--cream) calc(var(--notch-fillet) + .5px));
}
.nav__notch::after {
  right: calc(var(--notch-fillet) * -1);
  background: radial-gradient(circle at 100% 0, transparent var(--notch-fillet), var(--cream) calc(var(--notch-fillet) + .5px));
}
.nav__logo img { width: 72px; height: auto; transition: width var(--dur-fast) var(--ease); }

/* Condense once the page has scrolled, so the header stops eating the screen. */
.site-header.is-scrolled { box-shadow: 0 14px 26px -16px rgba(13,13,13,.55); }
/* The tab is a child painted over that shadow and hangs 26px past it, so
   without a matching shadow of its own the header appears to cast one
   everywhere except under the logo. Same values, so the two read as one edge. */
.site-header.is-scrolled .nav__notch { box-shadow: 0 14px 26px -16px rgba(13,13,13,.55); }
.site-header.is-scrolled .nav { min-height: 64px; }
/* Requested 23 Aug 2026: the tab keeps its bulge while scrolled instead of
   retracting flush. It still narrows with the condensed bar, but the drop and
   the fillets stay, so the logo reads as a tab rather than a black panel. */
.site-header.is-scrolled .nav__notch {
  width: 132px;
  height: calc(100% + var(--notch-drop));
  padding-bottom: .35rem;
  border-radius: 0 0 30px 30px;
}
.site-header.is-scrolled .nav__logo img { width: 56px; }
.nav__notch { transition: width var(--dur-fast) var(--ease); }

.nav__links { display: flex; align-items: center; gap: clamp(1rem, 2.2vw, 2.25rem); }
.nav__link {
  font-family: var(--font-eyebrow);
  font-size: .8125rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-strong);
  position: relative; padding-block: .35rem;
  transition: color var(--dur-fast) var(--ease);
}
.nav__link::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1px; background: var(--gold-600);
  transform: scaleX(0); transform-origin: right;
  transition: transform var(--dur-fast) var(--ease);
}
.nav__link:hover, .nav__link[aria-current="page"] { color: var(--gold-700); }
.nav__link:hover::after,
.nav__link[aria-current="page"]::after { transform: scaleX(1); transform-origin: left; }

.nav__cta { display: none; }
@media (min-width: 1100px) { .nav__cta { display: inline-flex; padding: .7rem 1.4rem; } }
/* Dark pill, not the site's gold one. On the old black bar the gold gradient
   was the obvious contrast; against cream a gold-300 fill is about 1.3:1 and
   stops reading as a button at all. Ink gives 18:1 for the label and echoes
   the logo tab. Overrides .btn--gold's own background, which is a gradient and
   so needs the property set rather than just the token - same specificity,
   later in the file, so this wins on source order. Keep it after .btn--gold.
   The hero and drawer CTAs stay gold; they have backdrops that suit it. */
.nav__cta { --btn-fg: var(--white); background: var(--ink); }
.nav__cta:hover { background: var(--ink-soft); }

.nav__toggle {
  display: grid; place-items: center;
  width: 46px; height: 46px; border-radius: 50%;
  background: rgba(13,13,13,.06); color: var(--ink);
}
.nav__toggle svg { width: 20px; height: 20px; }
@media (min-width: 1100px) { .nav__toggle { display: none; } }

@media (max-width: 1099px) {
  .nav__links { display: none; }
  .nav { grid-template-columns: 1fr 128px 1fr; }
  .nav__notch { --notch-drop: 18px; --notch-fillet: 14px; width: 128px; border-radius: 0 0 26px 26px; }
  .nav__logo img { width: 58px; }

  /* display: contents promotes the button and the toggle into the nav grid
     itself, so the empty left cell can hold the CTA instead of both fighting
     over the narrow right cell. Book left, logo centre, menu right. */
  .nav__right { display: contents; }
  .nav__cta {
    display: inline-flex;
    grid-column: 1; justify-self: start;
    /* min-height rather than padding alone: this is the primary booking action
       on a phone, so it needs a 44px tap target regardless of font size. */
    min-height: 44px;
    padding: .5rem 1.05rem;
    font-size: .6875rem;
    letter-spacing: .06em;
    gap: .4rem;
  }
  .nav__cta .btn__arrow { display: none; }
  .nav__toggle { grid-column: 3; justify-self: end; }
}

/* Very narrow phones: drop to just the word, so it never crowds the logo. */
@media (max-width: 400px) {
  .nav { grid-template-columns: 1fr 108px 1fr; }
  .nav__notch { width: 108px; }
  .nav__logo img { width: 50px; }
  .nav__cta { padding: .5rem .85rem; font-size: .625rem; }
}

/* Below 360px the 108px notch plus the Book button no longer fit between the
   gutters: at 320px the button ran 3px under the logo tab. Measured, not eyeballed. */
@media (max-width: 359px) {
  .nav { grid-template-columns: 1fr 96px 1fr; }
  .nav__notch { width: 96px; }
  .nav__logo img { width: 44px; }
  .nav__cta { padding: .5rem .6rem; letter-spacing: .04em; }
}

/* --- Mobile drawer ------------------------------------------------------ */

.drawer-backdrop {
  position: fixed; inset: 0; z-index: 110;
  background: rgba(13, 13, 13, .5);
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur-fast) var(--ease), visibility var(--dur-fast);
}
.drawer-backdrop.is-open { opacity: 1; visibility: visible; }

.drawer {
  position: fixed; inset: 0 0 0 auto; z-index: 120;
  width: min(360px, 88vw);
  display: flex; flex-direction: column; gap: .5rem;
  padding: 1.5rem;
  background: var(--white);
  transform: translateX(100%);
  transition: transform var(--dur) var(--ease);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.drawer.is-open { transform: none; }
.drawer__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; }
.drawer__head img { width: 88px; }
.drawer__close { display: grid; place-items: center; width: 42px; height: 42px; border-radius: 50%; background: var(--cream); }
.drawer__close svg { width: 20px; height: 20px; }
.drawer__link {
  display: block; padding: .9rem .25rem;
  font-family: var(--font-display); font-weight: 600; font-size: 1.125rem;
  color: var(--text-strong);
  border-bottom: 1px solid var(--rule);
}
.drawer__link[aria-current="page"] { color: var(--gold-700); }
.drawer .btn { margin-top: 1.25rem; justify-content: center; }

/* --- Hero --------------------------------------------------------------- */

/* The frame paints the gap round the hero in the nav bar's cream (Lewis,
   11 Oct 2026); a plain margin showed the white page behind it. */
.hero-frame { background: var(--cream); padding: 0 var(--hero-gap) var(--hero-gap); }
.hero { position: relative; overflow: hidden; background: var(--ink); border-radius: clamp(16px, 2vw, 28px); }
.hero__slides { position: relative; }
.hero__slide {
  display: grid; align-content: center;
  /* Fill the screen exactly, so the marquee below does not half-show. This was
     clamp(500px, 66vh, 680px), which stopped ~140px short of the bottom on a
     760px-tall window and left a slice of the ribbon peeking under the fold.

     svh, not vh or dvh, and the distinction matters on a phone. svh is the
     viewport at its *smallest* - URL bar showing - which is the state at first
     paint, so the hero fits exactly when it is first seen. dvh would track the
     bar as it collapses and resize the hero mid-scroll, which visibly shifts the
     centred headline; vh is the largest viewport and would overflow instead.
     The plain-vh line is the fallback for browsers without svh.

     Deliberately uncapped: a ceiling would bring the peeking ribbon straight
     back on tall windows, which is the thing being fixed. */
  min-height: calc(100vh - var(--above-hero) - var(--hero-gap));
  min-height: calc(100svh - var(--above-hero) - var(--hero-gap));
  padding-block: clamp(2.5rem, 5vw, 4.5rem);
}
/* Single hero now — the rotating slider was dropped. */
.hero__inner { max-width: 790px; }
/* The hero sits on a dark wash, so its type is light. Kept scoped to .hero
   rather than reusing .section--dark, which also restyles eyebrows and cards. */
.hero__title { font-size: var(--fs-hero); letter-spacing: -.035em; color: var(--text-on-dark); }
/* The logo gold itself, ~11:1 on the wash. This is the pairing the marquee
   already uses; it only works because the backdrop is dark. */
.hero__title em { font-style: normal; color: var(--gold-300); display: block; }
.hero__text { margin-top: 1.5rem; font-size: 1.0625rem; max-width: 46ch; color: rgba(255,255,255,.86); }
/* The ghost button's ink-on-cream would vanish here. */
.hero__actions .btn--ghost {
  --btn-fg: var(--white);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.45);
}
.hero__actions .btn--ghost:hover { --btn-bg: rgba(255,255,255,.12); }
.hero__actions { margin-top: 2.25rem; display: flex; flex-wrap: wrap; gap: .875rem; }

.hero__bg { position: absolute; inset: 0; z-index: 0; }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; object-position: 70% 50%; }
/* Dark warm wash on the left, so the headline can carry the actual logo gold.
   The pale ramp golds are unusable on a light backdrop — measured against the
   composited photo they come out below 2:1, and even --gold-600 only reaches
   2.49:1 against a 3:1 floor for large text. On this the logo gold is ~11:1,
   the same relationship the marquee already uses (gold-300 on --ink).
   It has to reach far enough right to cover the whole headline: the second
   line runs to about 63% of the viewport at 1280. */
.hero__bg::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg,
    rgba(18, 15, 11, .92) 0%,
    rgba(18, 15, 11, .86) 46%,
    rgba(18, 15, 11, .55) 72%,
    rgba(18, 15, 11, 0) 94%);
}
/* On a phone the headline spans nearly the full width, so a left-to-right
   scrim leaves its right-hand end over the busiest part of the picture. Below
   860px the wash goes vertical instead and the crop pulls back towards the
   plain wall. Dark, to match the desktop treatment. */
@media (max-width: 860px) {
  .hero__bg img { object-position: 58% 50%; }
  .hero__bg::after {
    background: linear-gradient(180deg, rgba(18,15,11,.90) 0%, rgba(18,15,11,.82) 45%, rgba(18,15,11,.62) 100%);
  }
}
.hero .container { position: relative; z-index: 2; }

/* Slide counter with progress rule */
.hero__counter {
  position: absolute; left: 50%; bottom: 2.25rem; z-index: 3;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 1rem;
  font-family: var(--font-eyebrow); font-size: .8125rem; font-weight: 600;
  color: var(--gold-700);
}
.hero__track { position: relative; width: 88px; height: 2px; background: var(--gold-200); overflow: hidden; }
.hero__track i { position: absolute; inset: 0 auto 0 0; width: 0; background: var(--gold-600); }
.hero__slides.is-playing .hero__track i { animation: heroProgress 6s linear forwards; }
@keyframes heroProgress { to { width: 100%; } }

/* --- Arched media ------------------------------------------------------- */

.arch { border-radius: var(--r-arch); overflow: hidden; }
.arch img { width: 100%; height: 100%; object-fit: cover; }

.media-zoom { overflow: hidden; }
.media-zoom img { transition: transform .55s var(--ease); }
.media-zoom:hover img { transform: scale(1.06); }

/* --- About -------------------------------------------------------------- */

/* Heading left, copy right, stats spanning underneath. .about__media and its
   aspect-ratio rules went with the placeholder; put them back alongside these
   tracks if a real interior photograph arrives. */
.about__grid {
  display: grid; gap: clamp(1.75rem, 3.5vw, 3.25rem);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 900px) {
  .about__grid { grid-template-columns: 1fr 1fr; }
  .about__stats { grid-column: 1 / -1; }
  /* The heading is short, so let it sit against the copy rather than drifting
     to the top of a tall row. */
  .about__head { align-self: center; }
}
.about__copy .section-sub:first-child { margin-top: 0; }
.about__stats {
  margin-top: clamp(.5rem, 2vw, 1.5rem);
  padding-top: clamp(1.5rem, 3vw, 2.25rem);
  border-top: 1px solid var(--rule-gold);
}
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 1.5rem; margin-top: 2.75rem; }
.stat__num { font-family: var(--font-display); font-size: clamp(2.25rem, 1.6rem + 2.4vw, 3.25rem); font-weight: 700; color: var(--text-strong); line-height: 1; }
.stat__label { margin-top: .4rem; font-size: var(--fs-sm); color: var(--text-mute); }

/* --- Service cards ------------------------------------------------------ */

.cards { display: grid; gap: 1.5rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr)); }

.card {
  display: flex; flex-direction: column;
  background: var(--card);
  border-radius: var(--r-card);
  overflow: hidden;
  transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.card:hover { transform: translateY(-6px); box-shadow: 0 18px 40px -22px rgba(13,13,13,.35); }
.card__media { aspect-ratio: 16 / 10; overflow: hidden; }
.card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform .55s var(--ease); }
/* The lash photo is a portrait of a reclining head dropped into a 16:10 card,
   so cover keeps only the middle 50% of its height. Centred, that clipped the
   lower lash line; biasing the crop down brings that eye fully into frame. */
.card__media img[src*="lashes"] { object-position: 50% 62%; }
.card:hover .card__media img { transform: scale(1.06); }
.card__body { padding: 1.5rem 1.5rem 1.75rem; display: flex; flex-direction: column; gap: .75rem; flex: 1; }

/* Treatment icon, sitting over the seam between media and body.
   position/z-index are load-bearing: .card__media img gets a transform on
   hover, which promotes it into the positioned paint layer and would otherwise
   paint straight over this icon. */
.card__icon {
  position: relative; z-index: 1;
  display: grid; place-items: center;
  width: 54px; height: 54px; flex: none;
  margin: -3.4rem 0 .25rem;
  background: var(--white);
  border: 1px solid var(--rule-gold);
  border-radius: 16px;
  color: var(--gold-700);
  box-shadow: 0 8px 22px -14px rgba(13,13,13,.5);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.card__icon svg { width: 26px; height: 26px; }
.card:hover .card__icon {
  background: linear-gradient(140deg, var(--gold-300), var(--gold-400));
  color: var(--ink);
}
.card__title { font-size: var(--fs-h3); }
.card__text { color: var(--text-mute); font-size: .9375rem; }
.card__list { display: grid; gap: .5rem; margin-top: .25rem; }
.card__list li { position: relative; padding-left: 1.5rem; font-size: .9375rem; }
.card__list li::before {
  content: ""; position: absolute; left: 0; top: .55em;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--gold-400);
}
.card__note {
  font-size: .8125rem; color: var(--gold-700);
  padding-top: .25rem; font-weight: 600;
}
.card__foot { margin-top: auto; padding-top: .5rem; }

/* Statutory notice band — sunbeds are regulated under the
   Sunbeds (Regulation) Act 2010. */
.notice {
  display: flex; gap: 1rem; align-items: flex-start;
  margin-top: 2.5rem; padding: 1.25rem 1.5rem;
  background: var(--white);
  border: 1px solid var(--rule-gold);
  border-left: 4px solid var(--gold-600);
  border-radius: var(--r-input);
}
.notice__icon { flex: none; color: var(--gold-700); }
.notice__icon svg { width: 24px; height: 24px; }
.notice__title { font-family: var(--font-display); font-weight: 700; color: var(--text-strong); margin-bottom: .25rem; }
.notice__text { font-size: .9375rem; color: var(--text); }

/* --- Pricing ------------------------------------------------------------ */

.pricing__grid {
  display: grid; gap: clamp(2rem, 4vw, 3.5rem);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 1000px) { .pricing__grid { grid-template-columns: 1fr auto 1fr; } }

.pricing__portrait { display: none; }
@media (min-width: 1000px) {
  .pricing__portrait {
    display: block; width: 300px; aspect-ratio: 3 / 4;
    border-radius: 50%; overflow: hidden;
    box-shadow: 0 0 0 1px var(--gold-300), 0 0 0 12px var(--white), 0 0 0 13px var(--gold-200);
  }
  .pricing__portrait img { width: 100%; height: 100%; object-fit: cover; }
}

.price-row {
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: center; gap: 1.125rem;
  padding-block: 1.125rem;
  border-bottom: 1px dashed var(--rule);
}
.price-row:last-child { border-bottom: 0; }
.price-row__icon {
  display: grid; place-items: center; flex: none;
  width: 48px; height: 48px; border-radius: 12px;
  background: linear-gradient(140deg, var(--gold-100), var(--gold-50));
  border: 1px solid var(--gold-200);
  color: var(--gold-700);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.price-row__icon svg { width: 24px; height: 24px; }
.price-row:hover .price-row__icon {
  background: linear-gradient(140deg, var(--gold-300), var(--gold-400));
  color: var(--ink);
}
.price-row__name { font-family: var(--font-display); font-weight: 700; font-size: 1.0625rem; color: var(--text-strong); }
.price-row__desc { font-size: .875rem; color: var(--text-mute); }
.price-row__price { font-family: var(--font-display); font-weight: 700; font-size: 1.5rem; color: var(--text-strong); white-space: nowrap; }

/* Placeholder pricing marker — remove once real prices land */
.is-placeholder { position: relative; }
.is-placeholder .price-row__price { color: var(--gold-700); }
.pricing__notice {
  margin-top: 2rem; padding: 1rem 1.25rem;
  background: var(--gold-50); border-left: 3px solid var(--gold-500);
  border-radius: var(--r-input);
  font-size: .875rem; color: var(--text);
}

/* --- Testimonial -------------------------------------------------------- */

.testimonial { position: relative; overflow: hidden; }
/* Centred with left/right + text-align rather than translateX, because the
   parallax script writes to `transform` and would wipe the centring out. */
.testimonial__ghost {
  position: absolute; left: 0; right: 0; bottom: -.15em;
  text-align: center;
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(6rem, 18vw, 15rem);
  color: #171717;
  white-space: nowrap; pointer-events: none; user-select: none;
  line-height: 1;
}
.testimonial .container { position: relative; z-index: 1; }
.testimonial__stars { display: flex; gap: .3rem; color: var(--gold-400); margin-bottom: 1.5rem; }
.testimonial__stars svg { width: 18px; height: 18px; }

/* Slides stack in the same grid cell so the band keeps a constant height
   and one can cross-fade over another. */
.testimonial__slides { display: grid; }
.testimonial__slide {
  grid-area: 1 / 1;
  margin: 0;
  opacity: 0; visibility: hidden;
  transform: translateY(14px);
  transition: opacity .55s var(--ease), transform .55s var(--ease), visibility .55s;
}
.testimonial__slide.is-active { opacity: 1; visibility: visible; transform: none; }
.testimonial__quote {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.25rem, .95rem + 1.4vw, 1.875rem);
  line-height: 1.45; color: var(--white); max-width: 60ch;
}
.testimonial__person { display: flex; align-items: center; gap: 1rem; margin-top: 2rem; }
.testimonial__avatar { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; }
.testimonial__name { font-family: var(--font-display); font-weight: 700; color: var(--white); font-size: 1.125rem; }
.testimonial__role { font-size: var(--fs-sm); color: var(--text-on-dark-mute); }
/* The dot stays 9px, but the button around it is 25px so the tap target clears
   the 24px minimum. Negative margins keep the row sitting where it used to. */
.testimonial__dots { display: flex; gap: .125rem; margin: calc(2rem - 8px) 0 -8px -8px; }
.testimonial__dots button { width: 25px; height: 25px; display: grid; place-items: center; background: none; }
.testimonial__dots button::after { content: ""; width: 9px; height: 9px; border-radius: 50%; background: #3A3A3A; transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease); }
.testimonial__dots button[aria-selected="true"]::after { background: var(--gold-400); transform: scale(1.25); }
.testimonial__source { margin-top: 1.5rem; font-size: .875rem; color: var(--text-on-dark-mute); }
.testimonial__source strong { color: var(--gold-300); }

/* --- Locations ---------------------------------------------------------- */

.location {
  display: flex; flex-direction: column; gap: 1rem;
  padding: 1.75rem;
  background: var(--white);
  border: 1px solid var(--rule);
  border-radius: var(--r-card);
  transition: border-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.location:hover { border-color: var(--gold-400); transform: translateY(-4px); }
.location--primary { background: var(--ink); border-color: var(--ink); color: var(--text-on-dark-mute); }
.location--primary .location__name,
.location--primary .location__addr { color: var(--white); }
.location--primary .location__tag { background: rgba(255,255,255,.1); color: var(--gold-300); }

.location__tag {
  align-self: flex-start;
  padding: .3rem .75rem;
  background: var(--gold-100); color: var(--gold-700);
  font-family: var(--font-eyebrow); font-size: .6875rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase;
  border-radius: var(--r-pill);
}
.location__name { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h3); color: var(--text-strong); }
/* Who works at that address. Tight to the name above it, so the card reads
   name - people - address rather than three equal lines. */
.location__who { margin-top: -.6rem; font-weight: 600; color: var(--gold-700); font-size: .9375rem; }
.location--primary .location__who { color: var(--gold-300); }
.location__addr { font-size: .9375rem; }
/* One row of pills in every card (Lewis, 11 Oct 2026) - labels are kept short
   enough to fit, and the narrowest phones tighten the padding. */
.location__services { display: flex; flex-wrap: nowrap; gap: .5rem; margin-top: auto; padding-top: .5rem; }
@media (max-width: 359px) { .location__services { gap: .35rem; } .location__services span { padding-inline: .6rem; } }
.location__services span {
  padding: .35rem .75rem; font-size: .8125rem;
  border-radius: var(--r-pill);
  background: var(--gold-50); color: var(--gold-700);
}
.location--primary .location__services span { background: rgba(255,255,255,.08); color: var(--gold-300); }

/* --- Hours -------------------------------------------------------------- */

.hours__media { min-height: 320px; position: relative; }
.hours__media img { width: 100%; height: 100%; object-fit: cover; position: absolute; inset: 0; }
.hours__grid { display: grid; grid-template-columns: 1fr; }
@media (min-width: 950px) {
  .hours__grid { grid-template-columns: 1fr 1fr; }
  /* The shopfront is a 1.395 landscape photo. Letting it stretch to the full
     height of the untrimmed hours panel made the column 633x791 (0.80) and
     object-fit cover threw away 43% of its width — the fascia and both window
     boards. The panel is tightened instead, so the photo fills the row with no
     cream left over and still shows ~88% of the frame. Holding it at exactly
     4:3 would need 28px hour rows, which reads cramped. */
  .hours__panel .section-title { font-size: clamp(1.75rem, 1.1rem + 1.6vw, 2.5rem); }
}
/* Tightened so the panel comes down to meet the shopfront photo rather than
   towering over it and leaving cream above and below. */
.hours__panel {
  padding: clamp(1.5rem, 2.6vw, 2.25rem);
  background: linear-gradient(150deg, var(--gold-100), var(--gold-50));
}
.hours__table { margin-top: 1.1rem; }
.hours__row {
  line-height: 1.4;
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding-block: .3rem;
  border-bottom: 1px solid var(--rule-gold);
}
.hours__row:last-child { border-bottom: 0; }
.hours__day { font-family: var(--font-display); font-weight: 700; color: var(--text-strong); }
.hours__time { color: var(--text); font-size: .9375rem; }
.hours__row--head .hours__day,
.hours__row--head .hours__time { font-size: .8125rem; letter-spacing: .08em; text-transform: uppercase; color: var(--gold-700); font-weight: 600; font-family: var(--font-eyebrow); }
.hours__row--closed .hours__time { color: var(--text-mute); }
.hours__note { margin-top: .85rem; font-size: .875rem; color: var(--text-mute); font-style: italic; }

/* --- Booking form ------------------------------------------------------- */

.booking__grid { display: grid; gap: clamp(2rem, 4vw, 3.5rem); grid-template-columns: 1fr; align-items: start; }
@media (min-width: 950px) { .booking__grid { grid-template-columns: .85fr 1.15fr; } }

.info-card {
  padding: clamp(1.75rem, 3vw, 2.5rem);
  background: var(--card);
  border-radius: var(--r-card);
  border-bottom: 3px solid var(--gold-500);
}
.info-card__title { font-size: var(--fs-h3); }
.info-card__rule { width: 56px; height: 3px; background: var(--gold-500); margin: 1rem 0 2rem; }
.info-row { display: flex; gap: 1rem; padding-block: 1rem; }
.info-row + .info-row { border-top: 1px solid var(--rule); }
.info-row__icon {
  display: grid; place-items: center; flex: none;
  width: 48px; height: 48px;
  background: var(--white); color: var(--gold-700);
  border: 1px solid var(--rule-gold);
  border-radius: 12px;
}
.info-row__icon svg { width: 22px; height: 22px; }
.info-row__label { font-family: var(--font-display); font-weight: 700; color: var(--text-strong); }
.info-row__value { font-size: .9375rem; color: var(--text-mute); }
.info-row__value a:hover { color: var(--gold-700); text-decoration: underline; }

.form-panel {
  padding: clamp(1.75rem, 3vw, 2.5rem);
  background: var(--card);
  border-radius: var(--r-card);
}
.form-grid { display: grid; gap: 1rem; grid-template-columns: 1fr; }
@media (min-width: 560px) { .form-grid { grid-template-columns: 1fr 1fr; } }
.field--full { grid-column: 1 / -1; }

/* Floating labels: the label starts inside the box as a placeholder and rises
   to a caption when the field is focused or filled. Saves a stacked label row
   per field, which is what made the form so tall. */
.field { position: relative; display: flex; flex-direction: column; }
/* The label mirrors the control's box — same height, same transparent border —
   and centres its line in it, so at rest the placeholder sits dead centre of
   the field. It is deliberately NOT aligned to where the value text will sit:
   the value text is low in the box because the floated label needs the top
   third, and a placeholder parked down there reads as badly aligned.
   It used to be top: 50% of .field, but .field also contains .field__error,
   so 50% of it was 7.8px below the middle of the input. */
.field label {
  position: absolute; left: 0; right: 0; top: 0;
  height: 58px;
  display: flex; align-items: center;
  padding: 0 1rem;
  border: 1px solid transparent;
  /* Origin at the padding edge, not the box edge, so scale(.75) keeps the
     floated label on the same left margin as the value text. */
  transform-origin: 1rem center;
  font-size: .9375rem; line-height: 20px; color: var(--text-mute);
  pointer-events: none;
  white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.field .req { color: var(--gold-700); }

.field input,
.field select,
.field textarea {
  width: 100%;
  height: 58px;
  /* Explicit line-height. The inherited 1.65 produced a 26.4px line box inside
     a 22.8px content box, so the value text overflowed its own padding and
     rendered 8.8px below the centre of the field, crammed against the bottom
     edge. 1.25 fits, and the padding split below leaves room for the label. */
  line-height: 1.25;
  padding: 1.4rem 1rem .6rem;
  background: var(--white);
  border: 1px solid var(--rule);
  border-radius: var(--r-input);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
/* The textarea keeps more headroom: its floated label lands lower than the
   inputs', so a 1.4rem top padding would run the first line into it. */
.field textarea { height: auto; min-height: 96px; resize: vertical; padding-top: 1.75rem; }

/* Textareas anchor their label near the top rather than the middle */
.field--area label { height: auto; padding-top: 1.75rem; }

.field input:focus + label,
.field select:focus + label,
.field input:not(:placeholder-shown) + label,
.field select:valid + label {
  transform: translateY(-1.125rem) scale(.75);
  color: var(--gold-700);
}
.field--area textarea:focus + label,
.field--area textarea:not(:placeholder-shown) + label {
  transform: translateY(-1.6rem) scale(.75);
  color: var(--gold-700);
}
.field select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23836728' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 1rem center; background-size: 18px; padding-right: 2.75rem; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--gold-500);
  box-shadow: 0 0 0 3px var(--gold-100);
}
.field input[aria-invalid="true"],
.field select[aria-invalid="true"],
.field textarea[aria-invalid="true"] { border-color: #B3261E; }
.field__error { font-size: .8125rem; color: #B3261E; min-height: 1.2em; }

.form-note { margin-top: .5rem; font-size: .875rem; color: var(--text-mute); }
.form-status { margin-top: 1rem; padding: .875rem 1rem; border-radius: var(--r-input); font-size: .9375rem; }
.form-status[data-state="success"] { background: #EAF5EC; color: #1B5E20; border-left: 3px solid #2E7D32; }
.form-status[data-state="error"]   { background: #FBEAE9; color: #8C1D18; border-left: 3px solid #B3261E; }
.form-status:empty { display: none; }

/* --- Footer ------------------------------------------------------------- */

.site-footer { background: var(--ink); color: var(--text-on-dark-mute); }

.footer__cta {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 1.5rem; padding-block: clamp(2.5rem, 4vw, 3.5rem);
}
.footer__cta-text { display: flex; align-items: center; gap: 1rem; }
.footer__cta-icon { display: grid; place-items: center; width: 56px; height: 56px; border-radius: 14px; background: linear-gradient(135deg, var(--gold-300), var(--gold-500)); color: var(--ink); flex: none; }
.footer__cta-icon svg { width: 26px; height: 26px; }
.footer__cta h2 { font-size: 1.5rem; color: var(--white); }
.footer__cta p { font-size: .9375rem; }

.footer__body {
  display: grid; gap: 2.5rem;
  grid-template-columns: 1fr;
  padding: clamp(2.5rem, 4vw, 3.5rem);
  background: var(--ink-soft);
  border-radius: var(--r-card);
}
@media (min-width: 760px) { .footer__body { grid-template-columns: 1.4fr 1fr 1fr; } }
.footer__logo img { width: 120px; margin-bottom: 1.25rem; }
.footer__blurb { font-size: .9375rem; max-width: 38ch; }
.footer__socials { display: flex; gap: .75rem; margin-top: 1.5rem; }
.footer__socials a {
  display: grid; place-items: center; width: 42px; height: 42px;
  border-radius: 50%; background: var(--white); color: var(--ink);
  transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.footer__socials a:hover { background: var(--gold-300); transform: translateY(-3px); }
.footer__socials svg { width: 18px; height: 18px; }

.footer__col h3 { font-size: 1.125rem; color: var(--white); }
.footer__col-rule { width: 40px; height: 2px; background: var(--gold-500); margin: .875rem 0 1.5rem; }
.footer__list { display: grid; gap: .875rem; }
.footer__list a { display: inline-flex; align-items: center; gap: .625rem; font-size: .9375rem; transition: color var(--dur-fast) var(--ease); }
.footer__list a::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--gold-500); flex: none; }
.footer__list a:hover { color: var(--gold-300); }

.footer__bottom {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 1rem; padding-block: 1.75rem;
  font-size: .875rem;
}
.footer__bottom a { color: var(--gold-300); }
.footer__bottom a:hover { text-decoration: underline; }

/* --- Image placeholders --------------------------------------------------
   Every .ph is a slot waiting on a real photograph. The label states the shot
   that belongs there, so the gaps are legible in the browser and double as a
   shot list. Delete the .ph and drop in an <img> as photos arrive.
   ------------------------------------------------------------------------- */

.ph {
  display: grid; place-items: center; gap: .4rem;
  min-height: 150px; height: 100%; width: 100%;
  padding: 1.25rem; text-align: center;
  background:
    repeating-linear-gradient(135deg, transparent 0 14px, rgba(138,109,44,.035) 14px 28px),
    linear-gradient(140deg, var(--gold-100), var(--gold-50));
  color: var(--gold-700);
  border: 1px dashed var(--gold-300);
}
.ph__icon svg { width: 30px; height: 30px; opacity: .55; }
.ph__label { font-family: var(--font-eyebrow); font-size: .6875rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; }
.ph__hint { font-size: .8125rem; color: var(--text-mute); max-width: 30ch; }
.arch .ph, .card__media .ph, .hours__media .ph { border: 0; }
.hours__media .ph { position: absolute; inset: 0; }

/* In the hero the placeholder fills the whole band, so its label is pinned to
   the bottom-right instead of the centre, where it collided with the headline. */
.hero__bg .ph {
  align-content: end; justify-items: end;
  padding: 2rem clamp(1.25rem, 3vw, 3rem);
  border: 0; text-align: right;
}
.hero__bg .ph__icon { display: none; }
.hero__bg .ph__label, .hero__bg .ph__hint { opacity: .75; }

/* --- Page banner (inner pages) ------------------------------------------ */

.page-banner { position: relative; padding-block: clamp(3rem, 7vw, 6rem); background: var(--gold-50); overflow: hidden; }
.page-banner__crumb { display: flex; align-items: center; gap: .6rem; font-size: .875rem; color: var(--text-mute); margin-bottom: 1rem; }
.page-banner__crumb a { color: var(--gold-700); }
.page-banner__crumb a:hover { text-decoration: underline; }
.page-banner__crumb svg { width: 14px; height: 14px; color: var(--gold-500); }
.page-banner__title { font-size: clamp(2.5rem, 1.6rem + 4vw, 4.5rem); }

/* ==========================================================================
   Multi-page build, 10 Oct 2026 - from Luke's meeting with the client.
   Home stays the overview; /services carries every price with a WhatsApp
   enquiry to the right person; /about introduces the three of them.
   ========================================================================== */

/* --- Marble --------------------------------------------------------------- */

/* "Honed" marble, option C from the mockups, chosen by Lewis 10 Oct 2026 after
   the five-layer recipe from 8cf8ef9 went live for a few hours and read as far
   too strong. Three layers: one very large soft cloud, one faint long vein, a
   white glint. It goes on every cream section.

   The strength is a contrast budget, not a taste setting. The darkest point
   measures L=0.781 (the old recipe was 0.538), which leaves the original muted
   tokens at 4.22:1 - just short of 4.5. So the section redeclares them, each
   darkened only as far as it has to go, keeping its hue: grey #6B6B6B -> #656565
   (6% darker, 4.61:1) and gold #836728 -> #7D6226 (5% darker, 4.56:1). Neither
   change is visible by eye. Redeclaring the token, rather than restyling
   element by element, keeps anything added later inside a marble section legal
   too. Make the marble any stronger and these must be re-derived.

   cover, not repeat: the rotation inside the SVG defeats stitchTiles, so a
   tiled version seams. */
.section--marble {
  --text-mute: #656565;
  --gold-700: #7D6226;
  background-color: #F9F6EF;
  /* Pre-rendered from tools/marble.svg (option C) - 21 Oct 2026. The SVG used to
     be inline here, and its three feTurbulence filters were recomputed by the
     browser at each section's full size x device pixel ratio: ~20,000px square
     for the services list on a phone, which made mobile slow. Same pixels as a
     14KB WebP (darkest L 0.780, mean 0.860, identical to the browser render).
     To change the marble, edit the SVG and re-render at 1600px with sharp. */
  background-image: url("/assets/img/marble.webp?v=1");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* --- Inner page header ------------------------------------------------------ */

/* Dark, like the home hero, for two reasons: the cream logo tab only reads as a
   tab where it overhangs something darker, and the gold <em> needs the dark
   ground to carry --gold-300 (the same pairing as the home headline). Top
   padding clears the tab's 26px overhang. */
.page-hero {
  position: relative; overflow: hidden;
  background:
    radial-gradient(120% 140% at 85% 0%, rgba(192,160,128,.18), transparent 60%),
    linear-gradient(160deg, #1B1712, var(--ink) 70%);
  padding-block: clamp(4.25rem, 3rem + 4vw, 6.5rem) clamp(2.75rem, 2rem + 3vw, 4.5rem);
}
.page-hero .eyebrow { color: var(--gold-400); }
.page-hero__title {
  font-size: clamp(2.25rem, 1.5rem + 3.2vw, 3.75rem);
  letter-spacing: -.03em; line-height: 1.08; color: var(--white);
  max-width: 18ch;
}
.page-hero__title em { font-style: normal; color: var(--gold-300); display: block; }
.page-hero__text { margin-top: 1.25rem; max-width: 56ch; font-size: 1.0625rem; color: rgba(255,255,255,.86); }

/* --- Price list ------------------------------------------------------------- */

.price-nav { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }
.price-nav button {
  min-height: 44px; padding: .5rem 1.05rem;
  border-radius: var(--r-pill);
  background: var(--white); color: var(--text-strong);
  border: 1px solid var(--rule-gold);
  font-family: var(--font-eyebrow); font-size: .75rem; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.price-nav button:hover { border-color: var(--gold-600); }
.price-nav button[aria-pressed="true"] { background: var(--ink); color: var(--white); border-color: var(--ink); }
/* On a phone nine chips wrapped to four rows - ~200px of buttons before the
   first price. One swipeable row instead, bleeding to the screen edge. */
@media (max-width: 759px) {
  .price-nav {
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
    margin-inline: calc(var(--gutter) * -1); padding: 2px var(--gutter);
  }
  .price-nav::-webkit-scrollbar { display: none; }
  .price-nav button { flex: none; }
}

/* Full container width, matching the filter chips above (Lewis, 11 Oct 2026). */
.price-groups { display: grid; gap: 1.5rem; }
.price-group {
  background: var(--white);
  border-radius: var(--r-card);
  padding: clamp(1.25rem, 1rem + 1.5vw, 2.25rem);
  box-shadow: 0 1px 0 var(--rule), 0 18px 40px -30px rgba(13,13,13,.35);
  scroll-margin-top: 110px;
}
.price-group[hidden] { display: none; }
/* Photo beside the title: a square crop, so portrait and landscape sources
   sit at the same size and every group head lines up. */
.price-group__head {
  display: grid; grid-template-columns: 88px 1fr; align-items: center;
  gap: 1rem 1.25rem; padding-bottom: .5rem;
}
@media (min-width: 760px) { .price-group__head { grid-template-columns: 132px 1fr; gap: 1rem 1.75rem; } }
.price-group__media { margin: 0; aspect-ratio: 1; border-radius: 12px; overflow: hidden; background: var(--card); }
.price-group__media img { width: 100%; height: 100%; object-fit: cover; }
.price-group__intro { display: grid; gap: .35rem; min-width: 0; }
.price-group__title { font-size: var(--fs-h3); }
.price-group__blurb { color: var(--text-mute); font-size: .9375rem; max-width: 62ch; }
.price-group__note { margin-top: .5rem; color: var(--gold-700); font-size: .875rem; font-weight: 600; }

.price-person + .price-person { margin-top: 1.5rem; }
/* "With Paige ——— [Message Paige]": the one WhatsApp button for that person's
   part of the group sits on their heading, the rule running between. */
.price-person__head {
  display: flex; align-items: center; flex-wrap: wrap; gap: .5rem .75rem;
  margin-top: 1.25rem; margin-bottom: .25rem;
}
.price-person__who {
  flex: 1 1 auto; min-width: 0; margin: 0;
  display: flex; align-items: center; gap: .6rem;
  font-family: var(--font-eyebrow); font-size: .75rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--gold-700);
}
.price-person__who::after { content: ""; flex: 1; height: 1px; background: var(--rule-gold); }

.price-item {
  display: grid; grid-template-columns: 1fr auto;
  align-items: center; gap: .5rem 1.25rem;
  padding-block: .9rem;
  border-bottom: 1px dashed var(--rule);
}
.price-item:last-child { border-bottom: 0; }
.price-item__name { font-family: var(--font-display); font-weight: 700; font-size: 1.0625rem; color: var(--text-strong); }
.price-item__desc { font-size: .875rem; color: var(--text-mute); margin-top: .15rem; }
.price-item__price { font-family: var(--font-display); font-weight: 700; font-size: 1.25rem; color: var(--text-strong); white-space: nowrap; text-align: right; }
.price-item__price--ask { font-size: .9375rem; color: var(--text-mute); font-weight: 600; }

/* WhatsApp enquiry button. White pill with an ink label so it sits with the
   rest of the site; the glyph carries the WhatsApp green, as an icon only. */
.wa-btn {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 44px; padding: .45rem 1rem .45rem .8rem;
  border-radius: var(--r-pill);
  background: var(--white); color: var(--text-strong);
  border: 1px solid var(--rule-gold);
  font-family: var(--font-eyebrow); font-size: .75rem; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.wa-btn svg { width: 18px; height: 18px; flex: none; color: #1FAF55; transition: color var(--dur-fast) var(--ease); }
.wa-btn:hover { background: var(--ink); color: var(--white); border-color: var(--ink); }
.wa-btn:hover svg { color: #25D366; }
.wa-btn--solid { background: var(--ink); color: var(--white); border-color: var(--ink); }
.wa-btn--solid svg { color: #25D366; }
.wa-btn--solid:hover { background: var(--ink-soft); }

.price-foot {
  margin-top: 2rem; display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem;
  color: var(--text); font-size: .9375rem;
}

/* --- Home service cards: who does it ---------------------------------------- */

.card__who {
  font-family: var(--font-eyebrow); font-size: .75rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--gold-700);
  margin-top: -.35rem;
}

/* --- About: one section per specialist --------------------------------------- */

.team { display: grid; gap: clamp(2rem, 4vw, 4rem); grid-template-columns: 1fr; align-items: start; }
@media (min-width: 900px) {
  .team { grid-template-columns: minmax(260px, 360px) 1fr; }
  .team--flip { grid-template-columns: 1fr minmax(260px, 360px); }
  .team--flip .team__photo { order: 2; }
}
.team__photo {
  aspect-ratio: 4 / 5; max-width: 420px; width: calc(100% - 22px);
  border-radius: var(--r-card); overflow: hidden;
  box-shadow: 0 0 0 1px var(--gold-300), 0 0 0 10px var(--white), 0 0 0 11px var(--gold-200);
  margin: 11px;
}
.team__photo .ph { height: 100%; border: 0; align-content: center; }
.team__head { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.team__logo { width: 76px; height: 76px; border-radius: 50%; overflow: hidden; flex: none; box-shadow: 0 0 0 1px var(--rule-gold); }
.team__logo img { width: 100%; height: 100%; object-fit: cover; }
.team__name { font-size: var(--fs-section); line-height: 1.05; }
.team__role { margin-top: .4rem; }
.team__bio { margin-top: 1.25rem; color: var(--text-mute); font-size: 1.0625rem; max-width: 60ch; }
.team__bio + .team__bio { margin-top: .85rem; }
.team__services { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1.5rem; }
.team__services span {
  padding: .4rem .85rem; font-size: .8125rem;
  border-radius: var(--r-pill);
  background: var(--white); color: var(--text-strong);
  border: 1px solid var(--rule-gold);
}
.team__actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.75rem; align-items: center; }
.team__link { font-weight: 600; color: var(--text-strong); text-decoration: underline; text-underline-offset: .2em; text-decoration-color: var(--gold-500); }

.portfolio { margin-top: 2rem; }
.portfolio__label {
  font-family: var(--font-eyebrow); font-size: .75rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--gold-700);
  margin-bottom: .85rem;
}
.portfolio__grid { display: grid; gap: .75rem; grid-template-columns: repeat(auto-fill, minmax(min(100%, 140px), 1fr)); }
.portfolio__grid figure { margin: 0; aspect-ratio: 1; overflow: hidden; border-radius: 12px; background: var(--card); }
.portfolio__grid img { width: 100%; height: 100%; object-fit: cover; transition: transform .55s var(--ease); }
.portfolio__grid figure:hover img { transform: scale(1.05); }

/* --- Home About, option E (11 Oct 2026) ----------------------------------- */
/* Short copy left, a 2x2 grid of tiles right: two stats and two salon photos.
   Tiles carry their own white or gold ground, so their text never sits on the
   marble. The stat numbers keep data-count so they still count up. */
.about-e { display: grid; gap: 2rem 3.5rem; grid-template-columns: 1fr; align-items: center; }
@media (min-width: 900px) { .about-e { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); } }
.about-e__lede { margin-top: 1.1rem; font-size: 1.0625rem; line-height: 1.65; color: var(--text); max-width: 46ch; }
.about-e__team { margin-top: 1rem; color: var(--text); max-width: 46ch; }
.about-e__team b { color: var(--text-strong); }
.about-e__tiles { display: grid; grid-template-columns: 1fr 1fr; gap: .875rem; }
.about-e__tile {
  background: var(--white); border-radius: var(--r-card);
  padding: clamp(1rem, 2vw, 1.4rem); min-height: clamp(140px, 16vw, 190px);
  display: flex; flex-direction: column; justify-content: flex-end;
  box-shadow: 0 18px 40px -30px rgba(13,13,13,.35);
}
.about-e__tile--gold { background: linear-gradient(140deg, var(--gold-300), var(--gold-400)); }
.about-e__tile--img { padding: 0; overflow: hidden; }
.about-e__tile--img img { width: 100%; height: 100%; object-fit: cover; }
.about-e__tile .stat__num { font-size: clamp(2rem, 1.4rem + 2vw, 3rem); }
.about-e__label { margin-top: .35rem; font-size: .9rem; color: var(--text); }
.about-e__tile--gold .about-e__label { color: #3A2E12; }

/* Divider between the treatment chips and the person chips on /services. */
.price-nav__sep { flex: none; width: 1px; align-self: stretch; margin-inline: .25rem; background: var(--rule-gold); }
.price-person[hidden] { display: none; }

/* One line under the home treatment cards for the things that are not a card. */
.services-extras { margin-top: 2rem; text-align: center; color: var(--text); }
.services-extras b { color: var(--text-strong); }
.services-extras a { font-weight: 600; color: var(--text-strong); text-decoration: underline; text-underline-offset: .2em; text-decoration-color: var(--gold-500); margin-left: .25rem; }

/* On wider screens the person chips always start their own row, rather than
   wrapping there by accident; on phones the chips are one sideways row and
   the divider stays a short vertical rule. */
@media (min-width: 760px) {
  .price-nav__sep { flex-basis: 100%; width: auto; height: 0; margin: 0; background: none; }
}

/* Touch hit areas (mobile audit, 11 Oct 2026). These links measured 19-26px tall,
   under the 44px touch guidance. Padding plus an equal negative margin enlarges
   what a finger can hit without moving or restyling anything. Inline links take
   vertical padding with no layout effect at all. */
@media (pointer: coarse) {
  .utility__phone { padding-block: 9px; margin-block: -9px; }
  /* Grow the fixed 26px box rather than pad it: padding inside a fixed
     border-box squeezed the 19px icon into 8px and it spilled downward,
     sitting below the phone number on touch screens (fixed 21 Oct 2026). */
  .utility__socials a { width: 44px; height: 44px; margin: -9px; }
  .testimonial__dots button { height: 44px; margin-block: -9.5px; }
  .footer__list a { padding-block: 9px; margin-block: -9px; }
  .info-row__value a { padding-block: 10px; }
  .team__link { display: inline-block; padding-block: 9px; margin-block: -9px; }
  /* Added 21 Oct 2026 with the treatment pages: breadcrumb, links in the
     about copy, and the footer credit. Inline, so padding moves nothing. */
  .page-hero .eyebrow a, .treat__copy p a, .footer__bottom a { padding-block: 12px; }
}

/* A three-photo strip in two columns leaves the third alone beside a gap on
   phones (Caroline's "The salon"). Three photos take three columns instead. */
@media (max-width: 480px) {
  .portfolio__grid:has(> :nth-child(3):last-child) { grid-template-columns: repeat(3, 1fr); }
}

/* Price group closing note - nails' "prices vary", head spa's blow-dry choice
   (client amendments, 13 Oct 2026). Sits under the last price row. */
.price-group__foot { margin-top: 1rem; padding-top: .875rem; border-top: 1px dashed var(--rule, rgba(0,0,0,.12)); color: var(--text-mute); font-size: .875rem; font-style: italic; }

/* Gift vouchers, made prominent on request (13 Oct 2026): a gold panel under
   the treatment cards. Gold surface takes ink text - never white. */
.voucher-callout { margin: 2.5rem auto 0; max-width: 760px; padding: clamp(1.5rem, 4vw, 2.25rem); border-radius: var(--r-card); background: linear-gradient(135deg, var(--gold-200, #E0D0B0), var(--gold-300, #D0C090)); color: var(--ink); text-align: center; }
.voucher-callout__eyebrow { font-size: .75rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }
.voucher-callout__title { margin-top: .5rem; font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem); font-weight: 700; line-height: 1.2; color: var(--ink); }
.voucher-callout__text { margin-top: .75rem; color: var(--ink); }
.voucher-callout__link { display: inline-block; margin-top: 1.25rem; padding: .8rem 1.5rem; border-radius: 999px; background: var(--ink); color: var(--white); font-weight: 700; font-size: .8125rem; letter-spacing: .08em; text-transform: uppercase; }

/* A real portrait in a team frame (Paige's, 13 Oct 2026). */
.team__photo > img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ===================== Treatment pages (13 Oct 2026) =====================
   /sunbeds, /nails ... generated by tools/build-services.pl. About copy beside
   that treatment's price group, then a FAQ and links to the others. */
.page-hero .eyebrow a { color: inherit; text-decoration: none; }
.page-hero .eyebrow a:hover { text-decoration: underline; }

.treat__grid { display: grid; gap: clamp(2rem, 4vw, 3.5rem); align-items: start; }
@media (min-width: 960px) { .treat__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); } }
.treat__copy p { margin-top: 1rem; color: var(--text); max-width: 62ch; }
.treat__copy a { color: var(--text-strong); text-decoration: underline; text-underline-offset: .2em; text-decoration-color: var(--gold-500); }
.treat__facts { margin-top: 1.75rem; display: grid; gap: .75rem; }
.treat__facts div { display: grid; grid-template-columns: 6.5rem 1fr; gap: 1rem; padding-top: .75rem; border-top: 1px solid var(--rule); }
.treat__facts dt { font-size: .75rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--gold-700); padding-top: .15rem; }
.treat__facts dd { margin: 0; color: var(--text-strong); font-weight: 500; }

.treat-faq__inner { max-width: 820px; }
.faq { margin-top: 1.75rem; display: grid; gap: .75rem; }
.faq__item { background: var(--card); border-radius: 14px; padding: 0 1.25rem; }
.faq__item summary { cursor: pointer; list-style: none; display: flex; justify-content: space-between; align-items: center; gap: 1rem; min-height: 56px; padding-block: .9rem; font-weight: 600; color: var(--text-strong); }
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary::after { content: "+"; flex: none; font-size: 1.4rem; line-height: 1; color: var(--gold-700); transition: transform var(--dur-fast) var(--ease); }
.faq__item[open] summary::after { transform: rotate(45deg); }
.faq__item p { padding-bottom: 1.1rem; color: var(--text); }

.treat-more__links { margin-top: 1.5rem; display: flex; flex-wrap: wrap; gap: .625rem; }
.treat-more__link { display: inline-flex; align-items: center; min-height: 44px; padding: .5rem 1.1rem; border-radius: 999px; border: 1px solid var(--gold-300); background: var(--white); color: var(--text-strong); font-weight: 600; font-size: .9375rem; }
.treat-more__link:hover { border-color: var(--gold-600); }
.treat-more__link--all { background: var(--ink); border-color: var(--ink); color: var(--white); }

/* "More about ..." link on each group of the full price list. */
.price-group__more { display: inline-block; margin-top: .6rem; padding-block: .3rem; font-size: .875rem; font-weight: 600; color: var(--text-strong); text-decoration: underline; text-underline-offset: .2em; text-decoration-color: var(--gold-500); }

/* Treatments dropdown in the desktop nav (13 Oct 2026). Opens on hover and on
   keyboard focus (:focus-within). The menu's top padding bridges the gap under
   the link so the pointer can travel down without the menu closing. Desktop
   only - .nav__links is hidden on mobile, where the drawer takes over. */
.nav__drop { position: relative; }
.nav__drop > .nav__link::before {
  content: ""; position: absolute; right: -1.1rem; top: 50%; width: 6px; height: 6px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: translateY(-70%) rotate(45deg); transition: transform var(--dur-fast) var(--ease);
}
.nav__drop:hover > .nav__link::before, .nav__drop:focus-within > .nav__link::before { transform: translateY(-30%) rotate(225deg); }
.nav__drop > .nav__link { margin-right: 1.1rem; }
.nav__menu {
  position: absolute; top: 100%; left: -1.25rem; z-index: 120;
  min-width: 240px; padding: 14px 0 0;
  opacity: 0; visibility: hidden; transform: translateY(6px);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), visibility 0s linear var(--dur-fast);
}
.nav__drop:hover .nav__menu, .nav__drop:focus-within .nav__menu {
  opacity: 1; visibility: visible; transform: none;
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), visibility 0s;
}
.nav__menu::before { content: ""; position: absolute; inset: 14px 0 0; background: var(--white); border-radius: 14px; box-shadow: 0 18px 40px -18px rgba(13,13,13,.35), 0 0 0 1px var(--rule); z-index: -1; }
.nav__menu li:first-child { padding-top: .5rem; }
.nav__menu li:last-child { padding-bottom: .5rem; }
.nav__menu a { display: block; padding: .6rem 1.25rem; font-size: .9375rem; font-weight: 500; color: var(--text-strong); white-space: nowrap; transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease); }
.nav__menu a:hover, .nav__menu a[aria-current="page"] { color: var(--gold-700); background: var(--card); }
.nav__menu-all { margin-top: .35rem; border-top: 1px solid var(--rule); padding-top: .35rem; }
.nav__menu-all a { font-weight: 700; font-size: .8125rem; letter-spacing: .08em; text-transform: uppercase; }

/* ===================== About: Inside C&A showcase (21 Oct 2026) ============
   Copy, then two arched photos staggered - the sunbed tall, the head spa set
   lower and slightly smaller, with a thin gold ring behind it. Dark band so the
   neon sunbed and the warm spa photo both glow, and so the page breaks between
   the marble intro and the cream team sections. */
.showcase__grid { display: grid; gap: clamp(1.5rem, 3vw, 3rem); align-items: start; }
.showcase__copy .section-title em { font-style: normal; color: var(--gold-300); }
.showcase__copy .section-sub { margin-top: 1rem; max-width: 46ch; }
.showcase__links { margin-top: 1.75rem; display: flex; flex-wrap: wrap; gap: .75rem; }
.showcase__link { display: inline-flex; align-items: center; gap: .5rem; min-height: 46px; padding: .55rem 1.2rem; border-radius: 999px; border: 1px solid rgba(224,208,176,.45); color: var(--gold-200); font-weight: 600; font-size: .9375rem; transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); }
.showcase__link:hover { background: var(--gold-300); border-color: var(--gold-300); color: var(--ink); }
.showcase__item { margin: 0; position: relative; }
.showcase__frame { border-radius: 999px 999px 18px 18px; overflow: hidden; aspect-ratio: 4 / 5; background: #1d1a16; box-shadow: 0 0 0 1px rgba(224,208,176,.25), 0 30px 60px -30px rgba(0,0,0,.8); }
.showcase__frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.showcase__item figcaption { margin-top: .9rem; font-size: .875rem; color: var(--text-on-dark-mute); }
.showcase__item figcaption span { display: block; font-size: .75rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--gold-300); margin-bottom: .2rem; }
.showcase__item--low::before { content: ""; position: absolute; z-index: 0; width: 70%; aspect-ratio: 1; right: -14%; top: -9%; border-radius: 50%; border: 1px solid rgba(224,208,176,.35); pointer-events: none; }
.showcase__item--low .showcase__frame { position: relative; z-index: 1; }

/* Phones: copy on top, the two photos side by side, the head spa dropped. */
@media (max-width: 759px) {
  .showcase__grid { grid-template-columns: 1fr 1fr; column-gap: 1rem; }
  .showcase__copy { grid-column: 1 / -1; }
  .showcase__item--low { margin-top: 3.5rem; }
  .showcase__item--low::before { display: none; }
  .showcase__item figcaption { font-size: .8125rem; }
}
/* Desktop: three columns, the head spa smaller and lower. */
@media (min-width: 760px) {
  .showcase__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 4.2fr) minmax(0, 3.6fr); align-items: center; }
  .showcase__item--low { margin-top: 9rem; }
  .showcase { overflow: hidden; }
}

/* Treatments in the phone drawer (21 Oct 2026): a native <details> that opens
   to list every treatment page, mirroring the desktop dropdown. No JS - the
   summary is in the drawer's focus trap list in main.js. */
.drawer__group summary { list-style: none; cursor: pointer; display: flex; justify-content: space-between; align-items: center; }
.drawer__group summary::-webkit-details-marker { display: none; }
.drawer__group summary::after {
  content: ""; width: 8px; height: 8px; margin-right: .4rem;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: translateY(-25%) rotate(45deg); transition: transform var(--dur-fast) var(--ease);
}
.drawer__group[open] summary::after { transform: translateY(25%) rotate(225deg); }
.drawer__sub { display: grid; padding: .35rem 0 .6rem .75rem; border-bottom: 1px solid var(--rule); }
.drawer__sub a { display: block; padding: .6rem .25rem; min-height: 44px; font-size: 1rem; font-weight: 500; color: var(--text); }
.drawer__sub a:first-child { font-weight: 700; color: var(--text-strong); }
.drawer__sub a[aria-current="page"] { color: var(--gold-700); }

/* Eight treatment cards on the home page (22 Oct 2026): 4x2 on desktop, 2x4 on
   tablets, one column on phones - so the grid is symmetrical at every size.
   auto-fit would give 3+3+2 at mid widths. */
.cards--treatments { grid-template-columns: 1fr; }
@media (min-width: 600px) { .cards--treatments { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .cards--treatments { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.25rem; } }
.card__media img[src*="paige-lips"] { object-position: 50% 45%; }

/* Main salon lists every treatment (client, 2 Nov 2026) - too many for the
   one-line rule the other cards keep, so this one wraps. */
.location__services--all { flex-wrap: wrap; }

/* ===================== Facebook (3 Nov 2026) =====================
   Copy and button left, Meta's Page Plugin right in a white card. The plugin
   is 180-500px wide and sizes its own height, so the card hugs it; until Meta
   restores the timeline it is just the page header, hence the button. */
.fb-feed__grid { display: grid; gap: clamp(2rem, 4vw, 3.5rem); align-items: center; }
@media (min-width: 900px) { .fb-feed__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 500px); } }
.fb-feed__copy .section-title em { font-style: normal; color: var(--gold-700); }
.fb-feed__copy .section-sub { margin-top: 1rem; max-width: 44ch; }
/* The label must stay on one line for the roll, so on the narrowest phones the
   button tightens rather than wrapping (it ran 27px off a 320px screen). */
@media (max-width: 380px) { .fb-feed .btn { padding-inline: 1.1rem; gap: .5rem; font-size: .75rem; } }

/* Our own Facebook card (3 Nov 2026) - replaces Meta's Page Plugin, which
   Meta currently renders broken. The whole card is one link to her page. */
.fb-card { display: block; width: 100%; max-width: 440px; justify-self: center; background: var(--white); border-radius: var(--r-card); overflow: hidden; color: var(--text); box-shadow: 0 0 0 1px var(--rule), 0 24px 48px -32px rgba(13,13,13,.35); transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease); }
.fb-card:hover { transform: translateY(-3px); box-shadow: 0 0 0 1px var(--gold-300), 0 30px 56px -30px rgba(13,13,13,.4); }
.fb-card__band { position: relative; display: block; height: 96px; background: linear-gradient(135deg, var(--gold-200), var(--gold-300) 55%, var(--gold-400, #C0A080)); }
.fb-card__logo { position: absolute; right: 18px; top: 18px; width: 26px; height: 26px; color: rgba(13,13,13,.55); }
.fb-card__body { display: flex; flex-direction: column; align-items: flex-start; padding: 0 1.5rem 1.5rem; }
.fb-card__avatar { position: relative; z-index: 1; width: 76px; height: 76px; margin-top: -38px; border-radius: 50%; object-fit: cover; border: 4px solid var(--white); box-shadow: 0 0 0 1px var(--rule); background: var(--card); }
.fb-card__name { margin-top: .75rem; font-family: var(--font-display); font-size: 1.375rem; font-weight: 700; color: var(--text-strong); line-height: 1.2; }
.fb-card__meta { margin-top: .2rem; font-size: .875rem; color: var(--text-mute); }
.fb-card__text { margin-top: .9rem; color: var(--text); }
.fb-card__follow { margin-top: 1.25rem; display: inline-flex; align-items: center; gap: .55rem; min-height: 46px; padding: .6rem 1.25rem; border-radius: 999px; background: var(--ink); color: var(--white); font-weight: 700; font-size: .875rem; }
.fb-card__follow svg { width: 18px; height: 18px; }

/* Three hand-picked Facebook posts under the card (3 Nov 2026). Three across,
   a sideways swipe on phones so they do not add ~1000px of scroll. */
.fb-posts-wrap { margin-top: clamp(2.5rem, 5vw, 3.5rem); }
.fb-posts__label { font-size: .75rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--gold-700); }
.fb-posts { margin-top: 1rem; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(.75rem, 2vw, 1.25rem); }
.fb-post { position: relative; display: block; overflow: hidden; border-radius: var(--r-card); aspect-ratio: 1; background: var(--card); }
.fb-post img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .55s var(--ease); }
.fb-post:hover img { transform: scale(1.04); }
.fb-post__cap { position: absolute; inset: auto 0 0 0; padding: 2.25rem 1rem .85rem; color: var(--white); font-size: .875rem; font-weight: 600; background: linear-gradient(to top, rgba(13,13,13,.72), rgba(13,13,13,0)); }
@media (max-width: 599px) {
  .fb-posts { display: flex; gap: .75rem; overflow-x: auto; scroll-snap-type: x mandatory; margin-inline: calc(var(--gutter, 20px) * -1); padding-inline: var(--gutter, 20px); scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .fb-posts::-webkit-scrollbar { display: none; }
  .fb-post { flex: 0 0 74%; scroll-snap-align: center; }
}
