@charset "UTF-8";
/* ==========================================================================
   FRSHR — Luxury Maintained
   Design system: ivory ground, warm ink, bronze light.
   Editorial serif display, geometric sans utility.
   ========================================================================== */

/* fonts.css is linked from includes/head.php, ahead of this file, rather than
   imported here: an @import cannot carry a cache-busting stamp, and it also
   serialises the download (fetch main.css, parse it, only then fetch fonts). */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Ground */
  --paper:        #F6F5ED;
  --paper-warm:   #EEEDE3;
  --paper-deep:   #E4E3D6;

  /* Ink */
  --ink:          #14120D;
  --ink-soft:     #1E1B15;
  --ink-lift:     #2A251C;

  /* Neutrals */
  --stone:        #B9B3A4;
  --stone-dim:    #6C6659;
  --stone-faint:  #D6D1C4;

  /* Accent — a low, warm metal. Used sparingly. */
  --bronze:       #9C7C4E;
  --bronze-lift:  #C4A472;

  /* Semantic (light section default) */
  --bg:           var(--paper);
  --fg:           var(--ink);
  --fg-muted:     var(--stone-dim);
  --rule:         rgba(20, 18, 13, 0.14);
  --rule-strong:  rgba(20, 18, 13, 0.28);

  /* Type */
  --serif: "Cormorant Garamond", "Times New Roman", serif;
  --sans:  "Jost", "Helvetica Neue", Arial, sans-serif;

  --fs-hero:    clamp(2.75rem, 9vw, 8.5rem);
  --fs-display: clamp(2.25rem, 5.4vw, 5rem);
  --fs-title:   clamp(1.75rem, 3.2vw, 3rem);
  --fs-sub:     clamp(1.25rem, 2vw, 1.875rem);
  --fs-lede:    clamp(1.0625rem, 1.25vw, 1.375rem);
  --fs-body:    clamp(0.9375rem, 0.95vw, 1.0625rem);
  --fs-label:   0.75rem;

  --track-label: 0.26em;
  --track-caps:  0.18em;
  --track-wide:  0.08em;

  /* Space */
  --gutter:  clamp(1.25rem, 5vw, 5.5rem);
  --section: clamp(5rem, 12vw, 11rem);
  --maxw:    1560px;
  --measure: 62ch;

  /* Motion */
  --ease:      cubic-bezier(0.22, 1, 0.36, 1);
  --ease-io:   cubic-bezier(0.65, 0, 0.35, 1);
  --dur:       0.8s;
  --dur-slow:  1.4s;

  --header-h: calc(84px + env(safe-area-inset-top, 0px));
}

@media (max-width: 860px) {
  :root { --header-h: calc(68px + env(safe-area-inset-top, 0px)); }
}

/* Dark sections opt in by class, not by media query. */
.is-dark {
  --bg:          var(--ink);
  --fg:          var(--paper);
  --fg-muted:    rgba(246, 245, 237, 0.74);
  --rule:        rgba(246, 245, 237, 0.16);
  --rule-strong: rgba(246, 245, 237, 0.34);
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */

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

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

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.75;
  letter-spacing: 0.012em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

h1, h2, h3, h4, h5, h6, figure, p, blockquote, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img, video, svg { display: block; max-width: 100%; }
img, video { height: auto; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, textarea, select { font: inherit; color: inherit; }

a {
  color: inherit;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}

::selection { background: var(--ink); color: var(--paper); }
.is-dark ::selection { background: var(--paper); color: var(--ink); }

:focus-visible {
  outline: 1px solid var(--bronze);
  outline-offset: 4px;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: fixed; top: 0; left: 50%; transform: translate(-50%, -140%);
  z-index: 300; padding: 0.9rem 1.75rem;
  background: var(--ink); color: var(--paper);
  font-family: var(--sans); font-size: var(--fs-label);
  text-transform: uppercase; letter-spacing: var(--track-label);
  transition: transform 0.3s var(--ease);
}
.skip-link:focus { transform: translate(-50%, 0); }

/* --------------------------------------------------------------------------
   3. Typography primitives
   -------------------------------------------------------------------------- */

.display,
.h-hero, .h-display, .h-title, .h-sub {
  font-family: var(--serif);
  font-weight: 300;
  line-height: 1.02;
  letter-spacing: -0.005em;
  text-wrap: balance;
}

.h-hero {
  font-size: var(--fs-hero);
  line-height: 0.94;
  letter-spacing: 0.02em;
}

.h-display { font-size: var(--fs-display); line-height: 1.04; }
.h-title   { font-size: var(--fs-title);   line-height: 1.1; }
.h-sub     { font-size: var(--fs-sub);     line-height: 1.2; }

.h-caps {
  font-family: var(--serif);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  line-height: 1.15;
}

.label {
  display: inline-block;
  font-family: var(--sans);
  font-size: var(--fs-label);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--fg-muted);
  line-height: 1;
}

.lede {
  font-size: var(--fs-lede);
  line-height: 1.7;
  font-weight: 300;
  max-width: var(--measure);
}

.prose p + p { margin-top: 1.35em; }
.prose { max-width: var(--measure); color: var(--fg); }
.prose--muted { color: var(--fg-muted); }

.serif-italic { font-family: var(--serif); font-style: italic; font-weight: 300; }

.numeral {
  font-family: var(--serif);
  font-weight: 300;
  font-variant-numeric: lining-nums;
  letter-spacing: 0.02em;
  /* Prices and figures stay LTR even inside Arabic copy — "840 AED" must
     never visually reorder to "AED 840" or worse by sitting inside RTL
     text. unicode-bidi: isolate keeps it from affecting the bidi run
     around it too. */
  direction: ltr;
  unicode-bidi: isolate;
}

/* Hairline that draws itself when revealed. */
.rule {
  display: block;
  width: 72px; height: 1px;
  background: var(--rule-strong);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-slow) var(--ease) 0.15s;
}
.rule--center { margin-inline: auto; transform-origin: center; }
.is-in .rule, .rule.is-in { transform: scaleX(1); }

/* --------------------------------------------------------------------------
   4. Layout
   -------------------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.shell--narrow { max-width: 1040px; }
.shell--tight  { max-width: 780px; }

.section {
  position: relative;
  background: var(--bg);
  color: var(--fg);
  padding-block: var(--section);
}
.section--flush   { padding-block: 0; }
.section--tight   { padding-block: clamp(3rem, 6vw, 6rem); }
.section--bleed   { padding-inline: 0; }
/* Sections that butt up against the one before, so the page reads as a
   sequence rather than a series of islands — the 31 Aug homepage note. */
.section--snug     { padding-block: clamp(2.5rem, 5vw, 4.5rem); }
.section--snug-top { padding-top: clamp(2.5rem, 5vw, 4.5rem); }
.section--snug-bot { padding-bottom: clamp(2.5rem, 5vw, 4.5rem); }
/* First section on a page with no hero and no .pintro — the header is fixed,
   so something has to reserve its height. */
.section--pagetop  { padding-top: calc(var(--header-h) + clamp(3rem, 7vw, 6rem)); }

.stack > * + * { margin-top: var(--sp, 1.5rem); }
.stack--sm { --sp: 0.85rem; }
.stack--lg { --sp: 2.5rem; }

.center { text-align: center; }
.center .lede { margin-inline: auto; }

.grid { display: grid; gap: clamp(1.5rem, 3vw, 3rem); }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Editorial two-column: sticky label rail + content */
.rail {
  display: grid;
  grid-template-columns: minmax(160px, 22%) minmax(0, 1fr);
  gap: clamp(1.5rem, 5vw, 6rem);
  align-items: start;
}
.rail__label { position: sticky; top: calc(var(--header-h) + 2.5rem); }

@media (max-width: 900px) {
  .grid--3, .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rail { grid-template-columns: 1fr; gap: 1.5rem; }
  .rail__label { position: static; }
}

@media (max-width: 620px) {
  .grid--2, .grid--3, .grid--4 { grid-template-columns: minmax(0, 1fr); }
}

/* --------------------------------------------------------------------------
   5. Scroll reveal
   -------------------------------------------------------------------------- */

/* Word-level display reveal (see reveal() in config.php) */
.rv {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: 0.06em;
  margin-bottom: -0.06em;
}
.rv-i {
  display: inline-block;
  transform: translateY(105%);
  transition: transform 1.05s var(--ease);
  transition-delay: calc(var(--i, 0) * 55ms + var(--d, 0ms));
}
.is-in .rv-i { transform: translateY(0); }

/* Block-level reveal */
[data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition:
    opacity 1.05s var(--ease) var(--d, 0ms),
    transform 1.05s var(--ease) var(--d, 0ms);
}
[data-reveal].is-in { opacity: 1; transform: none; }

[data-reveal="fade"]  { transform: none; }
[data-reveal="left"]  { transform: translateX(-32px); }
[data-reveal="right"] { transform: translateX(32px); }

/* Image mask reveal.
   A curtain wipe, not clip-path on the element itself — clipping the target to
   zero height also zeroes its IntersectionObserver rect, so it would never
   qualify to reveal. */
[data-reveal="mask"] {
  position: relative;
  opacity: 1;
  transform: none;
}
[data-reveal="mask"]::after {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: 3;
  background: var(--bg);
  transform-origin: 50% 100%;
  transition: transform 1.4s var(--ease) var(--d, 0ms);
  pointer-events: none;
}
[data-reveal="mask"].is-in::after { transform: scaleY(0); }

@media (prefers-reduced-motion: reduce) {
  .rv-i, [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
  }
  .rule { transform: scaleX(1) !important; transition: none !important; }
}

/* --------------------------------------------------------------------------
   6. Media
   -------------------------------------------------------------------------- */

.media {
  position: relative;
  overflow: hidden;
  background: var(--paper-deep);
}
.media > img,
.media > video {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

.media--1x1  { aspect-ratio: 1 / 1; }
.media--4x5  { aspect-ratio: 4 / 5; }
.media--3x4  { aspect-ratio: 3 / 4; }
.media--3x2  { aspect-ratio: 3 / 2; }
.media--16x9 { aspect-ratio: 16 / 9; }
.media--21x9 { aspect-ratio: 21 / 9; }

/* Slow parallax drift driven by JS (--py set per-frame).
   The overscale must always exceed the drift or the frame edge shows through —
   JS clamps --py to 10% of the element height, so 1.24 leaves 12% of slack. */
.media--parallax > img,
.media--parallax > video {
  transform: scale(1.24) translate3d(0, var(--py, 0px), 0);
  will-change: transform;
}

/* Hover zoom on linked media */
.media--zoom > img { transition: transform 1.6s var(--ease); }
a:hover .media--zoom > img,
.group:hover .media--zoom > img { transform: scale(1.045); }

.media__veil {
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(12, 11, 8, 0.44) 0%,
    rgba(12, 11, 8, 0.16) 34%,
    rgba(12, 11, 8, 0.20) 62%,
    rgba(12, 11, 8, 0.62) 100%);
  pointer-events: none;
}
.media__veil--soft  { background: rgba(12, 11, 8, 0.28); }
.media__veil--heavy { background: rgba(12, 11, 8, 0.58); }

/* Video that fades up once it can play. */
.bg-video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.6s var(--ease);
}
.bg-video.is-ready { opacity: 1; }

/* --------------------------------------------------------------------------
   7. Buttons & links
   -------------------------------------------------------------------------- */

.btn {
  --btn-fg: var(--paper);
  --btn-bg: var(--ink);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.8rem;
  padding: 1.15rem 2.6rem;
  border: 1px solid transparent;
  color: var(--btn-fg);
  background: transparent;
  font-family: var(--sans);
  font-size: var(--fs-label);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  line-height: 1;
  overflow: hidden;
  isolation: isolate;
  cursor: pointer;
  transition: color 0.55s var(--ease), border-color 0.55s var(--ease);
}
.btn::before {
  content: "";
  position: absolute; inset: 0;
  background: var(--btn-bg);
  transform: translateY(0);
  transition: transform 0.62s var(--ease);
  z-index: -1;
}
.btn:hover::before,
.btn:focus-visible::before { transform: translateY(-101%); }

.btn:hover, .btn:focus-visible {
  color: var(--btn-bg);
  border-color: var(--btn-bg);
}

/* Outline variant */
.btn--line {
  --btn-fg: var(--fg);
  border-color: var(--rule-strong);
}
.btn--line::before { background: var(--fg); transform: translateY(101%); }
.btn--line:hover::before,
.btn--line:focus-visible::before { transform: translateY(0); }
.btn--line:hover, .btn--line:focus-visible { color: var(--bg); border-color: var(--fg); }

/* On dark ground */
.is-dark .btn { --btn-fg: var(--ink); --btn-bg: var(--paper); }
.is-dark .btn--line { --btn-fg: var(--paper); }

.btn--ghost { --btn-bg: transparent; border-color: currentColor; }
.btn--wide  { width: 100%; }
.btn--lg    { padding: 1.4rem 3.2rem; letter-spacing: 0.3em; }

/* Underline link that wipes in */
.ulink {
  position: relative;
  display: inline-block;
  padding-bottom: 0.22em;
  font-family: var(--sans);
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--fg);
}
.ulink::after,
.ulink::before {
  content: "";
  position: absolute; left: 0; bottom: 0;
  height: 1px; width: 100%;
}
.ulink::before { background: var(--rule); }
.ulink::after {
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 0.6s var(--ease);
}
.ulink:hover::after,
.ulink:focus-visible::after { transform: scaleX(1); transform-origin: left center; }

/* --------------------------------------------------------------------------
   8. Header
   -------------------------------------------------------------------------- */

.header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 120;
  height: var(--header-h);
  display: flex;
  align-items: center;
  /* Ink is the safe default: on a page that opens on the ivory ground rather
     than a hero, ivory type would be invisible. JS opts into ivory only where a
     dark surface is measurably behind the header. */
  color: var(--ink);
  transition: color 0.5s var(--ease), transform 0.6s var(--ease);
}
.header::before {
  content: "";
  position: absolute; inset: 0;
  background: var(--paper);
  border-bottom: 1px solid rgba(20, 18, 13, 0.14);
  opacity: 0;
  transition: opacity 0.5s var(--ease);
  pointer-events: none;
}
.header.is-solid { color: var(--ink); }
.header.is-solid::before { opacity: 1; }

/* Over a hero, dark section, band or the footer: ivory type, no plate. */
.header.is-over-dark { color: var(--paper); }
.header.is-over-dark::before { opacity: 0; }

.header.is-hidden { transform: translateY(-100%); }

/* Before JS runs, assume no hero — ink on the page ground. Pages that do open
   on a hero mark themselves so the first paint is already correct. */
.has-hero .header { color: var(--paper); }
.has-hero .header.is-solid { color: var(--ink); }

.header__inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: max(var(--gutter), env(safe-area-inset-left, 0px)) max(var(--gutter), env(safe-area-inset-right, 0px));
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1rem;
}

.header__left  { display: flex; align-items: center; gap: 1.5rem; }
.header__right { display: flex; align-items: center; justify-content: flex-end; gap: clamp(0.9rem, 2vw, 2rem); }

.wordmark {
  display: block;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.35rem, 2vw, 1.85rem);
  letter-spacing: 0.16em;
  text-indent: 0.16em;
  line-height: 1;
  white-space: nowrap;
}
.wordmark--lg { font-size: clamp(2rem, 4.5vw, 3.5rem); }

/* --- Supplied logo artwork ------------------------------------------------
   The PNGs are true black, but the header sits ivory over a hero and ink once
   it goes solid, so the artwork is painted with currentColor through a mask
   rather than placed as an <img>. That keeps the exact colour behaviour the
   typographic wordmark had, in both the header and the drawer.

   Wrapped in @supports so a browser without mask support keeps the original
   serif wordmark instead of showing an empty box. */
@supports ((-webkit-mask-image: url("")) or (mask-image: url(""))) {
  .wordmark {
    width: clamp(5.6rem, 8vw, 7.2rem);
    aspect-ratio: 512 / 120;
    background: currentColor;
    -webkit-mask: url("../image/icon/frshr-wordmark.png") left center / contain no-repeat;
            mask: url("../image/icon/frshr-wordmark.png") left center / contain no-repeat;
  }
  .wordmark--lockup {
    width: clamp(9rem, 15vw, 13rem);
    aspect-ratio: 512 / 187;
    -webkit-mask-image: url("../image/icon/frshr-lockup.png");
            mask-image: url("../image/icon/frshr-lockup.png");
  }
  /* The text stays in the document for screen readers and for copy/paste. */
  .wordmark__t {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
}

/* Hamburger. The bars stay 34x24; the button carries a 44px hit area so it can
   be caught with a thumb rather than aimed at. */
.burger {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  width: 44px; height: 44px;
  padding-block: 10px;
  padding-inline: 5px;
}
.burger span {
  display: block; height: 1px; width: 100%;
  background: currentColor;
  transition: transform 0.5s var(--ease), opacity 0.35s var(--ease);
}
.burger:hover span:nth-child(1) { transform: translateX(3px); }
.burger:hover span:nth-child(3) { transform: translateX(-3px); }
.is-menu-open .burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.is-menu-open .burger span:nth-child(2) { opacity: 0; }
.is-menu-open .burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

.icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem;
  font-family: var(--sans);
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
}
.icon-btn svg { width: 19px; height: 19px; stroke: currentColor; fill: none; stroke-width: 1.1; }

.cart-count {
  position: absolute;
  top: -2px; right: -6px;
  min-width: 15px; height: 15px;
  display: grid; place-items: center;
  padding: 0 3px;
  border-radius: 999px;
  background: var(--bronze);
  color: var(--paper);
  font-size: 9px; letter-spacing: 0; line-height: 1;
}

/* Language switch */
.lang { position: relative; }
.lang__list {
  position: absolute;
  top: calc(100% + 0.9rem); inset-inline-end: 0;
  min-width: 148px;
  padding: 0.75rem 0;
  background: var(--paper);
  border: 1px solid var(--rule);
  color: var(--ink);
  opacity: 0; visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease), visibility 0.35s;
}
.lang.is-open .lang__list { opacity: 1; visibility: visible; transform: none; }
.lang__list a {
  display: block;
  padding: 0.5rem 1.25rem;
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  transition: background 0.3s var(--ease);
}
.lang__list a:hover { background: var(--paper-warm); }
.lang__list a[aria-current="true"] { color: var(--bronze); }

@media (max-width: 720px) {
  .header__right .icon-btn span { display: none; }
}

/* --------------------------------------------------------------------------
   9. Menu drawer
   -------------------------------------------------------------------------- */

.drawer {
  position: fixed;
  top: 0; bottom: 0;
  z-index: 130;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  color: var(--ink);
  visibility: hidden;
  transition: transform 0.9s var(--ease), visibility 0.9s;
}
.drawer--menu {
  inset-inline-start: 0;
  width: min(560px, 88vw);
  transform: translateX(-100%);
  border-inline-end: 1px solid var(--rule);
}
.drawer--cart {
  inset-inline-end: 0;
  width: min(460px, 92vw);
  transform: translateX(100%);
  border-inline-start: 1px solid var(--rule);
}
[dir="rtl"] .drawer--menu { transform: translateX(100%); }
[dir="rtl"] .drawer--cart { transform: translateX(-100%); }
.drawer.is-open { transform: none; visibility: visible; }

.drawer__scrim {
  position: fixed; inset: 0;
  z-index: 125;
  background: rgba(12, 11, 8, 0.5);
  backdrop-filter: blur(3px);
  opacity: 0; visibility: hidden;
  transition: opacity 0.7s var(--ease), visibility 0.7s;
}
.drawer__scrim.is-open { opacity: 1; visibility: visible; }

.drawer__head {
  display: flex; align-items: center; justify-content: space-between;
  height: var(--header-h);
  padding-inline: clamp(1.5rem, 4vw, 3.25rem);
  border-bottom: 1px solid var(--rule);
  flex: 0 0 auto;
}
.drawer__body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: clamp(2rem, 5vw, 3.5rem) clamp(1.5rem, 4vw, 3.25rem);
}
.drawer__foot {
  flex: 0 0 auto;
  padding: clamp(1.5rem, 3vw, 2.25rem) clamp(1.5rem, 4vw, 3.25rem);
  border-top: 1px solid var(--rule);
}

.close-btn {
  display: grid; place-items: center;
  width: 40px; height: 40px;
  transition: transform 0.5s var(--ease);
}
.close-btn:hover { transform: rotate(90deg); }
.close-btn svg { width: 17px; height: 17px; stroke: currentColor; stroke-width: 1.1; }

/* Menu list — oversized serif with staggered entrance */
.menu-list li {
  overflow: hidden;
  border-bottom: 1px solid var(--rule);
}
.menu-list a {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: clamp(0.7rem, 1.6vw, 1.05rem) 0;
  font-family: var(--serif);
  font-size: clamp(1.9rem, 4.2vw, 2.9rem);
  font-weight: 300;
  line-height: 1.15;
  transform: translateY(110%);
  transition: transform 0.9s var(--ease), color 0.4s var(--ease);
  transition-delay: calc(var(--i) * 60ms);
}
.drawer--menu.is-open .menu-list a { transform: none; }
.menu-list a:hover { color: var(--bronze); }

.menu-sub { margin-top: clamp(2rem, 4vw, 3rem); display: grid; gap: 2rem; grid-template-columns: repeat(2, 1fr); }
/* Was ".menu-sub h3" — the drawer markup (header.php) uses h2.label for
   this heading, so the rule never matched and the global reset's
   margin: 0 left it flush against the first link while the links below
   kept their own 0.55rem rhythm, reading as uneven/misaligned. */
.menu-sub h2 { margin-bottom: 1rem; }
.menu-sub li + li { margin-top: 0.55rem; }
.menu-sub a {
  font-size: 0.875rem;
  color: var(--stone-dim);
  transition: color 0.35s var(--ease);
}
.menu-sub a:hover { color: var(--ink); }

@media (max-width: 480px) { .menu-sub { grid-template-columns: 1fr; } }

/* Cart */
.cart-line {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  padding-block: 1.35rem;
  border-bottom: 1px solid var(--rule);
}
.cart-empty { padding-block: 2rem; color: var(--fg-muted); }
.cart-total {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 1.5rem;
}

/* --------------------------------------------------------------------------
   10. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  /* 14 Sep: was 100svh, the SMALLEST viewport, which on iOS Safari stops above
     the floating URL bar and leaves the next section showing beneath it. lvh is
     the full screen. Identical to vh on desktop and Android, so this is a no-op
     everywhere the hero is already correct. The phone caps in §27 and the
     homepage rule in §36 both override this; it governs tablets and desktop,
     and iPhone landscape, whose 874px width is over the 860px breakpoint. */
  min-height: 100vh;   /* fallback: browsers that do not parse lvh */
  min-height: 100lvh;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--ink);
  color: var(--paper);
  isolation: isolate;
}
.hero--short { min-height: min(78svh, 760px); }
.hero--mid   { min-height: min(88svh, 900px); }

.hero__media { position: absolute; inset: 0; z-index: -2; }
.hero__media img,
.hero__media video {
  width: 100%; height: 100%;
  object-fit: cover;
}
.hero__media::after {
  content: "";
  position: absolute; inset: 0;
  background:
    radial-gradient(90% 62% at 50% 52%, rgba(12, 11, 8, 0.58) 0%, rgba(12, 11, 8, 0.34) 55%, rgba(12, 11, 8, 0.68) 100%),
    linear-gradient(180deg, rgba(12, 11, 8, 0.62) 0%, rgba(12, 11, 8, 0.2) 26%, rgba(12, 11, 8, 0.34) 62%, rgba(12, 11, 8, 0.78) 100%);
}

.hero__inner {
  position: relative;
  width: 100%;
  max-width: var(--maxw);
  padding: calc(var(--header-h) + 4rem) var(--gutter) clamp(4.5rem, 9vw, 8rem);
  text-align: center;
}
.hero__inner--left { text-align: left; }

.hero__kicker { margin-bottom: clamp(1.5rem, 3vw, 2.25rem); color: rgba(246, 245, 237, 0.82); }
.hero__title  { margin-bottom: clamp(1.75rem, 3vw, 2.5rem); }
.hero__lede   { margin-inline: auto; color: rgba(246, 245, 237, 0.78); }

/* Scroll cue */
.scroll-cue {
  position: absolute;
  left: 50%;
  /* 14 Sep: the hero now runs to the bottom of the screen (§10, §36), so this
     sits over the iPhone home indicator and the landscape Safari bar unless it
     is lifted. Same calc + env pattern as .drawer__foot; env is 0 everywhere
     without an inset, so desktop is unchanged. */
  bottom: calc(clamp(1.5rem, 3vw, 2.75rem) + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 0.9rem;
  color: rgba(246, 245, 237, 0.6);
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: var(--track-label);
}
.scroll-cue__line {
  position: relative;
  width: 1px; height: 62px;
  background: rgba(246, 245, 237, 0.22);
  overflow: hidden;
}
.scroll-cue__line::after {
  content: "";
  position: absolute; inset: 0;
  background: var(--paper);
  animation: cue 2.6s var(--ease-io) infinite;
}
@keyframes cue {
  0%       { transform: translateY(-100%); }
  55%,100% { transform: translateY(100%); }
}

/* --------------------------------------------------------------------------
   11. Split panels (CLEAN / RESTORE)
   -------------------------------------------------------------------------- */

.split {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  min-height: clamp(420px, 62vw, 760px);
}
.split__panel {
  position: relative;
  display: grid;
  place-items: center;
  overflow: hidden;
  color: var(--paper);
  text-align: center;
  padding: clamp(2.5rem, 5vw, 5rem);
  isolation: isolate;
}
.split__panel img,
.split__panel video {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(1.02);
  transition: transform 1.9s var(--ease), filter 1.2s var(--ease);
  filter: grayscale(0.16) brightness(0.82);
}
.split__panel::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgba(12,11,8,0.28), rgba(12,11,8,0.62));
  transition: background 0.9s var(--ease);
}
.split__panel:hover img,
.split__panel:hover video { transform: scale(1.1); filter: grayscale(0) brightness(0.95); }
.split__panel:hover::after { background: linear-gradient(180deg, rgba(12,11,8,0.18), rgba(12,11,8,0.5)); }

.split__inner { position: relative; }
.split__title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(2rem, 4.6vw, 4rem);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  line-height: 1;
}
.split__sub { margin-top: 1.15rem; color: rgba(246, 245, 237, 0.75); }
.split__cta {
  display: inline-flex; align-items: center; gap: 0.7rem;
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  font-family: var(--sans);
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
}
.split__panel:hover .split__cta,
.split__panel:focus-within .split__cta { opacity: 1; transform: none; }

@media (max-width: 780px) {
  .split { grid-template-columns: 1fr; }
  .split__panel { min-height: 58vw; }
  .split__cta { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   12. Service bands (services index)
   -------------------------------------------------------------------------- */

.band {
  position: relative;
  display: flex;
  align-items: center;
  min-height: clamp(220px, 27vw, 400px);
  padding: clamp(2rem, 4vw, 3.5rem) var(--gutter);
  overflow: hidden;
  color: var(--paper);
  border-bottom: 1px solid rgba(246, 245, 237, 0.12);
  isolation: isolate;
}
.band:last-child { border-bottom: 0; }
.band__media { position: absolute; inset: 0; z-index: -2; }
.band__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(0.3) brightness(0.6);
  transform: scale(1.04);
  transition: transform 2s var(--ease), filter 1.1s var(--ease);
}
.band::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  /* Flat wash for overall mood, plus a directional scrim so the title always
     has ground beneath it whatever the photograph is doing. */
  background:
    linear-gradient(90deg, rgba(12, 11, 8, 0.72) 0%, rgba(12, 11, 8, 0.18) 62%, rgba(12, 11, 8, 0.05) 100%),
    rgba(12, 11, 8, 0.34);
  transition: background 0.8s var(--ease);
}
.band--right::after {
  background:
    linear-gradient(270deg, rgba(12, 11, 8, 0.72) 0%, rgba(12, 11, 8, 0.18) 62%, rgba(12, 11, 8, 0.05) 100%),
    rgba(12, 11, 8, 0.34);
}
.band:hover .band__media img { transform: scale(1.12); filter: grayscale(0) brightness(0.72); }
.band:hover::after,
.band--right:hover::after {
  background:
    linear-gradient(90deg, rgba(12, 11, 8, 0.58) 0%, rgba(12, 11, 8, 0.1) 70%, transparent 100%),
    rgba(12, 11, 8, 0.2);
}
.band--right:hover::after {
  background:
    linear-gradient(270deg, rgba(12, 11, 8, 0.58) 0%, rgba(12, 11, 8, 0.1) 70%, transparent 100%),
    rgba(12, 11, 8, 0.2);
}

.band__inner {
  position: relative;
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  display: flex;
  align-items: baseline;
  gap: clamp(1rem, 3vw, 2.5rem);
}
/* row-reverse flips the main axis, so flex-start packs to the right edge. */
.band--right .band__inner { justify-content: flex-start; text-align: right; flex-direction: row-reverse; }

.band__title {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.75rem, 5vw, 4.25rem);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  line-height: 1;
  text-shadow: 0 1px 26px rgba(12, 11, 8, 0.55);
}

/* Mirror the directional scrims so the title always keeps its dark ground. */
[dir="rtl"] .band::after {
  background:
    linear-gradient(270deg, rgba(12, 11, 8, 0.72) 0%, rgba(12, 11, 8, 0.18) 62%, rgba(12, 11, 8, 0.05) 100%),
    rgba(12, 11, 8, 0.34);
}
[dir="rtl"] .band--right::after {
  background:
    linear-gradient(90deg, rgba(12, 11, 8, 0.72) 0%, rgba(12, 11, 8, 0.18) 62%, rgba(12, 11, 8, 0.05) 100%),
    rgba(12, 11, 8, 0.34);
}
.band__kicker { font-size: 0.75rem; letter-spacing: var(--track-wide); color: rgba(246, 245, 237,0.7); font-style: italic; font-family: var(--serif); }

@media (max-width: 700px) {
  .band__inner, .band--right .band__inner { flex-direction: column; align-items: flex-start; text-align: left; gap: 0.5rem; }
}

/* --------------------------------------------------------------------------
   13. Horizontal drag carousel
   -------------------------------------------------------------------------- */

.carousel { position: relative; }

.carousel__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2rem;
  margin-bottom: clamp(2rem, 4vw, 3.5rem);
}

.carousel__nav { display: flex; align-items: center; gap: 1.25rem; }
.carousel__count {
  font-family: var(--serif);
  font-size: 0.95rem;
  letter-spacing: 0.16em;
  color: var(--fg-muted);
  min-width: 5.5ch;
  text-align: center;
}
.carousel__count .cur { color: var(--fg); }

.carousel__btn {
  display: grid; place-items: center;
  width: 46px; height: 46px;
  border: 1px solid var(--rule-strong);
  border-radius: 50%;
  transition: background 0.5s var(--ease), color 0.5s var(--ease), border-color 0.5s var(--ease), opacity 0.4s;
}
.carousel__btn svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 1.2; }
.carousel__btn:hover:not(:disabled) { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.carousel__btn:disabled { opacity: 0.28; cursor: default; }

.carousel__track {
  display: flex;
  gap: clamp(1rem, 2.2vw, 2.25rem);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding-inline: var(--gutter);
  margin-inline: calc(var(--gutter) * -1);
  cursor: grab;
  scroll-behavior: smooth;
}
.carousel__track::-webkit-scrollbar { display: none; }
.carousel__track.is-dragging { cursor: grabbing; scroll-behavior: auto; scroll-snap-type: none; }
.carousel__track.is-dragging * { pointer-events: none; user-select: none; }

.carousel__item {
  flex: 0 0 auto;
  width: clamp(240px, 27vw, 400px);
  scroll-snap-align: center;
}
.carousel__item--wide { width: clamp(280px, 42vw, 640px); }

/* Experience card */
.xp {
  display: block;
}
.xp__media { margin-bottom: clamp(1.25rem, 2.5vw, 2rem); }
.xp__n {
  display: block;
  font-family: var(--serif);
  font-size: clamp(2rem, 3.4vw, 3.1rem);
  font-weight: 300;
  line-height: 1;
  text-align: center;
}
.xp__rule {
  width: 26px; height: 1px;
  margin: 0.65rem auto 1.05rem;
  background: var(--rule-strong);
}
.xp__title {
  max-width: 30ch;
  margin-inline: auto;
  text-wrap: balance;
  text-align: center;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 0.95rem;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  line-height: 1.3;
}
.xp__body {
  margin-top: 0.75rem;   /* same gap as .feature__title, so the two sections share a rhythm */
  /* One measure for all six, and balanced wrapping so no card ends up with a
     line running the full width of its box while its neighbours do not. */
  max-width: 38ch;
  margin-inline: auto;
  text-wrap: balance;
  text-align: center;
  font-size: 0.875rem;
  line-height: 1.7;
  color: var(--fg-muted);
}

/* --------------------------------------------------------------------------
   14. Before / after comparison
   -------------------------------------------------------------------------- */

.compare {
  position: relative;
  overflow: hidden;
  user-select: none;
  touch-action: pan-y;
  background: var(--paper-deep);
  cursor: ew-resize;
}
.compare img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}
.compare__after {
  position: absolute; inset: 0;
  clip-path: inset(0 0 0 var(--pos, 50%));
}
.compare__handle {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--pos, 50%);
  width: 1px;
  background: rgba(246, 245, 237, 0.9);
  pointer-events: none;
}
.compare__grip {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 54px; height: 54px;
  display: grid; place-items: center;
  border: 1px solid rgba(246, 245, 237, 0.9);
  border-radius: 50%;
  background: rgba(20, 18, 13, 0.24);
  backdrop-filter: blur(4px);
  color: var(--paper);
}
.compare__grip svg { width: 22px; height: 12px; stroke: currentColor; fill: none; stroke-width: 1.1; }
.compare__tag {
  position: absolute;
  bottom: 1.1rem;
  padding: 0.45rem 0.9rem;
  background: rgba(20, 18, 13, 0.55);
  backdrop-filter: blur(4px);
  color: var(--paper);
  font-size: 0.5625rem;
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  pointer-events: none;
}
.compare__tag--before { left: 1.1rem; }
.compare__tag--after  { right: 1.1rem; }

/* --------------------------------------------------------------------------
   15. Diagram (service anatomy)
   -------------------------------------------------------------------------- */

.anatomy {
  display: grid;
  grid-template-columns: 1fr minmax(220px, 34%) 1fr;
  gap: clamp(1rem, 2.5vw, 3rem);
  align-items: center;
}
.anatomy__col { display: grid; gap: clamp(2rem, 4vw, 3.5rem); }
.anatomy__col--l { text-align: right; }

.spec { position: relative; }
.spec__title {
  display: block;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  padding-bottom: 0.55rem;
  margin-bottom: 0.7rem;
}
.spec__title::after {
  content: "";
  position: absolute; left: 0; right: 0;
  bottom: calc(100% - 1.9rem);
  height: 1px;
  background: var(--rule-strong);
  transform: scaleX(0);
  transition: transform 1.1s var(--ease) calc(var(--i, 0) * 90ms);
}
.anatomy__col--l .spec__title::after { transform-origin: left; }
.anatomy__col--r .spec__title::after { transform-origin: right; }
.is-in .spec__title::after { transform: scaleX(1); }
.spec__body { font-size: 0.8125rem; line-height: 1.7; color: var(--fg-muted); }

@media (max-width: 900px) {
  .anatomy { grid-template-columns: 1fr; }
  .anatomy__col--l { text-align: left; order: 2; }
  .anatomy__media { order: 1; }
  .anatomy__col--r { order: 3; }
  .anatomy__col--l .spec__title::after,
  .anatomy__col--r .spec__title::after { transform-origin: left; }
}

/* --------------------------------------------------------------------------
   16. Accordion
   -------------------------------------------------------------------------- */

.acc { border-top: 1px solid var(--rule); }
.acc__item { border-bottom: 1px solid var(--rule); }

.acc__btn {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  width: 100%;
  padding: clamp(1.4rem, 2.4vw, 2rem) 0;
  text-align: left;
  transition: color 0.4s var(--ease);
}
.acc__btn:hover { color: var(--bronze); }

.acc__n {
  flex: 0 0 auto;
  font-family: var(--sans);
  font-size: 0.625rem;
  letter-spacing: var(--track-label);
  color: var(--fg-muted);
}
.acc__q {
  flex: 1 1 auto;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.05rem, 1.8vw, 1.5rem);
  line-height: 1.3;
}
.acc__sign {
  flex: 0 0 auto;
  position: relative;
  width: 15px; height: 15px;
}
.acc__sign::before,
.acc__sign::after {
  content: "";
  position: absolute; top: 50%; left: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transition: transform 0.55s var(--ease);
}
.acc__sign::after { transform: rotate(90deg); }
.acc__item.is-open .acc__sign::after { transform: rotate(0deg); }

.acc__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.7s var(--ease);
}
.acc__item.is-open .acc__panel { grid-template-rows: 1fr; }
.acc__panel > div { overflow: hidden; }
.acc__a {
  padding: 0 0 clamp(1.4rem, 2.4vw, 2rem) calc(0.625rem + 1.5rem + 2ch);
  max-width: 72ch;
  color: var(--fg-muted);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.6s var(--ease) 0.1s, transform 0.6s var(--ease) 0.1s;
}
.acc__item.is-open .acc__a { opacity: 1; transform: none; }

@media (max-width: 620px) {
  .acc__a { padding-left: 0; }
  .acc__btn { gap: 1rem; }
}

/* --------------------------------------------------------------------------
   17. Marquee
   -------------------------------------------------------------------------- */

.marquee {
  position: relative;
  overflow: hidden;
  padding-block: clamp(2rem, 4vw, 3.25rem);
  border-block: 1px solid var(--rule);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.marquee__track {
  display: flex;
  width: max-content;
  gap: clamp(2.5rem, 6vw, 6rem);
  animation: marquee 46s linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__item {
  display: flex; align-items: center; gap: clamp(2.5rem, 6vw, 6rem);
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.5rem, 3vw, 2.6rem);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  white-space: nowrap;
  color: var(--fg);
  transition: color 0.5s var(--ease), opacity 0.5s var(--ease);
  opacity: 0.5;
}
.marquee__item:hover { opacity: 1; color: var(--bronze); }
.marquee__item::after { content: "◦"; font-size: 0.5em; opacity: 0.45; }
@keyframes marquee { to { transform: translateX(-50%); } }

@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; }
}

/* --------------------------------------------------------------------------
   18. Cards & tiles
   -------------------------------------------------------------------------- */

.tile {
  position: relative;
  display: block;
  padding: clamp(1.75rem, 3vw, 2.75rem);
  border: 1px solid var(--rule);
  background: transparent;
  overflow: hidden;
  isolation: isolate;
  transition: color 0.6s var(--ease), border-color 0.6s var(--ease);
}
.tile::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background: var(--fg);
  transform: translateY(101%);
  transition: transform 0.7s var(--ease);
}
a.tile:hover, a.tile:focus-visible { color: var(--bg); border-color: var(--fg); }
a.tile:hover::before, a.tile:focus-visible::before { transform: translateY(0); }
a.tile:hover .tile__body, a.tile:focus-visible .tile__body { color: var(--bg); opacity: 0.78; }

.tile__icon { width: 26px; height: 26px; margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }
.tile__icon svg, .tile__icon img { width: 100%; height: 100%; stroke: currentColor; fill: none; stroke-width: 1.1; }
.tile__title { margin-bottom: 0.85rem; }
.tile__body { font-size: 0.875rem; line-height: 1.75; color: var(--fg-muted); transition: color 0.6s var(--ease), opacity 0.6s var(--ease); }

/* Numbered feature list */
.feature { position: relative; padding-top: 1.75rem; border-top: 1px solid var(--rule); }
.feature__n {
  display: block;
  font-family: var(--sans);
  font-size: 0.625rem;
  letter-spacing: var(--track-label);
  color: var(--fg-muted);
  margin-bottom: 1.25rem;
}
.feature__title { margin-bottom: 0.75rem; }
.feature__body { font-size: 0.875rem; line-height: 1.75; color: var(--fg-muted); }

/* Maison card */
.maison-card { position: relative; display: block; overflow: hidden; }
.maison-card__media { aspect-ratio: 3 / 4; }
.maison-card__media img,
.maison-card__media video {
  width: 100%; height: 100%; object-fit: cover;
  filter: grayscale(0.35) brightness(0.72);
  transform: scale(1.03);
  transition: transform 1.8s var(--ease), filter 1s var(--ease);
}
.maison-card:hover .maison-card__media img,
.maison-card:hover .maison-card__media video { transform: scale(1.11); filter: grayscale(0) brightness(0.85); }
.maison-card__body {
  position: absolute; inset: auto 0 0 0;
  padding: clamp(1.25rem, 2.5vw, 2rem);
  color: var(--paper);
  background: linear-gradient(180deg, transparent, rgba(12,11,8,0.72));
}
.maison-card__name {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.15rem, 1.8vw, 1.6rem);
  text-transform: uppercase;
  letter-spacing: 0.15em;
  line-height: 1;
}
.maison-card__quote {
  margin-top: 0.6rem;
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.875rem;
  color: rgba(246, 245, 237, 0.72);
  line-height: 1.5;
}

/* Pill list of maison services */
.pills { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.pill {
  padding: 0.6rem 1.1rem;
  border: 1px solid var(--rule);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--fg-muted);
  transition: color 0.45s var(--ease), border-color 0.45s var(--ease);
}
.pill:hover { color: var(--fg); border-color: var(--rule-strong); }

/* --------------------------------------------------------------------------
   19. Forms
   -------------------------------------------------------------------------- */

.field { position: relative; padding-top: 1.6rem; }
.field__input {
  width: 100%;
  padding: 0.55rem 0 0.75rem;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule-strong);
  font-family: var(--sans);
  font-size: 1rem;
  font-weight: 300;
  color: var(--fg);
  transition: border-color 0.45s var(--ease);
}
textarea.field__input { min-height: 150px; resize: vertical; line-height: 1.7; }
.field__input:focus { outline: none; border-color: var(--fg); }
.field__input::placeholder { color: transparent; }

.field__label {
  position: absolute;
  top: 2.15rem; left: 0;
  font-size: 1rem;
  font-weight: 300;
  color: var(--fg-muted);
  pointer-events: none;
  transform-origin: left top;
  transition: transform 0.45s var(--ease), color 0.45s var(--ease);
}
.field__input:focus + .field__label,
.field__input:not(:placeholder-shown) + .field__label {
  transform: translateY(-1.65rem) scale(0.68);
  color: var(--fg-muted);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
}
.field__req { color: var(--bronze); }

/* Boxed variant — for large free-text areas where a single underline reads as
   an empty region rather than a field. */
.field--box .field__input {
  border: 1px solid var(--rule-strong);
  padding: 1.1rem 1.15rem;
}
.field--box .field__label { top: 2.65rem; left: 1.15rem; }
.field--box .field__input:focus + .field__label,
.field--box .field__input:not(:placeholder-shown) + .field__label {
  transform: translateY(-2.15rem) translateX(-1.15rem) scale(0.68);
}

.field--select select {
  width: 100%;
  padding: 0.55rem 0 0.75rem;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule-strong);
  font-family: var(--sans); font-size: 1rem; font-weight: 300;
  appearance: none;
  cursor: pointer;
}
.field--select { position: relative; }
.field--select::after {
  content: "";
  position: absolute; right: 2px; bottom: 1.15rem;
  width: 7px; height: 7px;
  border-right: 1px solid var(--fg-muted);
  border-bottom: 1px solid var(--fg-muted);
  transform: rotate(45deg);
  pointer-events: none;
}

.form-note { font-size: 0.75rem; color: var(--fg-muted); }
/* A validation message, not a disclaimer — bronze rather than muted grey so
   it reads as something to act on, not more small print. */
.form-note--warn { color: var(--bronze); font-weight: 500; }

/* Choice grid (item type, time windows).
   Deliberately not built on .grid--3 — these tiles must stay multi-column on a
   phone, where a single column would make each one a full-width square. */
.choices {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.75rem;
}
@media (max-width: 400px) {
  .choices { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Careers sector row */
.sectors {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(0.75rem, 2vw, 2rem);
}
@media (max-width: 900px) { .sectors { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 520px) { .sectors { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.choice {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.85rem;
  aspect-ratio: 1 / 1;
  padding: 1rem;
  border: 1px solid var(--rule);
  text-align: center;
  transition: border-color 0.45s var(--ease), background 0.45s var(--ease), color 0.45s var(--ease);
}
.choice input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.choice svg { width: 34px; height: 34px; stroke: currentColor; fill: none; stroke-width: 1; }
.choice span {
  font-size: 0.625rem; text-transform: uppercase; letter-spacing: var(--track-caps);
  color: var(--fg-muted); transition: color 0.45s var(--ease);
}
.choice:hover { border-color: var(--rule-strong); }
.choice:has(input:checked) { border-color: var(--fg); background: var(--fg); color: var(--bg); }
.choice:has(input:checked) span { color: var(--bg); }
.choice:has(input:focus-visible) { outline: 1px solid var(--bronze); outline-offset: 3px; }

.slot {
  position: relative;
  padding: 0.7rem 1rem;
  border: 1px solid var(--rule);
  font-size: 0.75rem;
  letter-spacing: var(--track-wide);
  text-align: center;
  transition: border-color 0.4s var(--ease), background 0.4s var(--ease), color 0.4s var(--ease);
}
.slot input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.slot:hover { border-color: var(--rule-strong); }
.slot:has(input:checked) { background: var(--fg); color: var(--bg); border-color: var(--fg); }

.dropzone {
  display: grid; place-items: center; gap: 0.6rem;
  padding: clamp(2rem, 4vw, 3rem);
  border: 1px dashed var(--rule-strong);
  text-align: center;
  color: var(--fg-muted);
  transition: border-color 0.45s var(--ease), background 0.45s var(--ease);
  cursor: pointer;
}
.dropzone:hover, .dropzone.is-over { border-color: var(--fg); background: rgba(20,18,13,0.03); }
.dropzone input { display: none; }

/* Summary panel */
.summary {
  padding: clamp(1.75rem, 3vw, 2.5rem);
  background: var(--paper-warm);
  border: 1px solid var(--rule);
}
.is-dark .summary { background: var(--ink-lift); }
.summary__row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding-block: 0.55rem;
  font-size: 0.875rem;
}
.summary__row--total {
  margin-top: 0.75rem; padding-top: 1.25rem;
  border-top: 1px solid var(--rule-strong);
  font-size: 1rem;
}
.summary__total {
  font-family: var(--serif);
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  font-weight: 300;
  line-height: 1;
}
.summary__total sup { font-family: var(--sans); font-size: 0.6875rem; letter-spacing: var(--track-caps); top: -1.1em; margin-left: 0.35em; }

/* Steps */
.steps { display: flex; gap: 2.5rem; flex-wrap: wrap; }
.step { display: flex; align-items: baseline; gap: 0.75rem; }
.step__n { font-family: var(--serif); font-size: 1.15rem; }
.step__label { font-size: 0.625rem; text-transform: uppercase; letter-spacing: var(--track-label); color: var(--fg-muted); }
.step.is-active .step__label { color: var(--fg); }

/* --------------------------------------------------------------------------
   20. Table (careers / windows)
   -------------------------------------------------------------------------- */

.rows { border-top: 1px solid var(--rule); }
.row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr)) auto;
  gap: 1.5rem;
  align-items: center;
  padding-block: clamp(1.35rem, 2.4vw, 1.9rem);
  border-bottom: 1px solid var(--rule);
  transition: background 0.5s var(--ease), padding-inline 0.5s var(--ease);
}
.row:hover { background: rgba(20,18,13,0.028); padding-inline: 1rem; }
.is-dark .row:hover { background: rgba(246, 245, 237,0.04); }
.row__title { font-family: var(--serif); font-size: 1.15rem; font-weight: 500; }
.row__cell { font-size: 0.8125rem; color: var(--fg-muted); }

@media (max-width: 800px) {
  .row { grid-template-columns: 1fr 1fr; gap: 0.5rem 1.5rem; }
  .row__title { grid-column: 1 / -1; }
  .row__action { grid-column: 1 / -1; margin-top: 0.75rem; }
}

.windows { display: grid; gap: 0.5rem; }
.window-row {
  display: grid;
  grid-template-columns: minmax(90px, 1fr) repeat(2, minmax(0, 1.2fr));
  gap: 0.5rem;
  align-items: center;
}
.window-row__day { font-size: 0.8125rem; color: var(--fg-muted); }

/* --------------------------------------------------------------------------
   21. Footer
   The 31 Aug note moves the footer out of ink and into the brand cream, so
   everything here reads from the semantic tokens rather than hardcoding paper
   on ink. Nothing else needs to know.
   -------------------------------------------------------------------------- */

.footer {
  position: relative;
  background: var(--paper);
  color: var(--fg);
  padding-block: clamp(4rem, 8vw, 7rem) clamp(2rem, 4vw, 3rem);
  border-top: 1px solid var(--rule);
  overflow: hidden;
}
.footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) repeat(2, minmax(0, 1fr));
  gap: clamp(2.5rem, 5vw, 4rem);
  padding-bottom: clamp(3rem, 5vw, 4.5rem);
  border-bottom: 1px solid var(--rule);
}
.footer h2 {
  margin-bottom: clamp(1.25rem, 2.5vw, 1.75rem);
  font-family: var(--sans);
  font-size: var(--fs-label);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--fg-muted);
}
.footer__links li + li { margin-top: 0.8rem; }
.footer__links a {
  position: relative;
  display: inline-block;
  font-size: 0.875rem;
  color: var(--fg-muted);
  transition: color 0.4s var(--ease);
}
.footer__links a::after {
  content: "";
  position: absolute; left: 0; bottom: -2px;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.5s var(--ease);
}
.footer__links a:hover { color: var(--fg); }
.footer__links a:hover::after { transform: scaleX(1); transform-origin: left; }

.social { display: flex; gap: 0.9rem; margin-top: 1.75rem; }
.social a {
  display: grid; place-items: center;
  /* 44px minimum tap target (Part E), same as every other icon control. */
  width: 44px; height: 44px;
  border: 1px solid var(--rule-strong);
  border-radius: 50%;
  transition: background 0.5s var(--ease), color 0.5s var(--ease), border-color 0.5s var(--ease);
}
.social svg { width: 15px; height: 15px; fill: currentColor; }
.social a:hover { background: var(--fg); color: var(--bg); border-color: var(--fg); }

.footer__base {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; flex-wrap: wrap;
  padding-top: clamp(1.75rem, 3vw, 2.5rem);
  font-size: 0.6875rem;
  letter-spacing: var(--track-wide);
  color: var(--fg-muted);
}

@media (max-width: 780px) {
  .footer__grid { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   22. Page intro (interior pages)
   -------------------------------------------------------------------------- */

.pintro {
  padding-top: calc(var(--header-h) + clamp(4rem, 9vw, 9rem));
  padding-bottom: clamp(3rem, 6vw, 5.5rem);
}
.pintro__label { margin-bottom: clamp(1.25rem, 2.5vw, 2rem); }
.pintro__title { margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }

/* --------------------------------------------------------------------------
   23. Cursor & curtain
   -------------------------------------------------------------------------- */

.cursor {
  position: fixed;
  top: 0; left: 0;
  z-index: 400;
  width: 34px; height: 34px;
  margin: -17px 0 0 -17px;
  border: 1px solid rgba(20, 18, 13, 0.45);
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: difference;
  transition: opacity 0.4s var(--ease), transform 0.35s var(--ease), background 0.4s var(--ease);
  will-change: transform;
}
.cursor.is-visible { opacity: 1; }
.cursor.is-hot { transform: scale(1.7); background: rgba(246, 245, 237, 0.12); }
.cursor.is-drag { transform: scale(2.1); }
.cursor__label {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--sans); font-size: 6px;
  text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--paper);
  opacity: 0;
  transition: opacity 0.3s var(--ease);
}
.cursor.is-drag .cursor__label { opacity: 1; }

@media (hover: none), (pointer: coarse) { .cursor { display: none; } }

.curtain {
  position: fixed; inset: 0;
  z-index: 500;
  display: grid; place-items: center;
  background: var(--ink);
  transition: transform 1.15s var(--ease) 0.15s;
}
.curtain__mark {
  font-family: var(--serif);
  font-size: clamp(1.75rem, 5vw, 3rem);
  letter-spacing: 0.3em;
  text-indent: 0.3em;
  color: var(--paper);
  opacity: 0;
  animation: markIn 0.9s var(--ease) 0.1s forwards;
}
.curtain__bar {
  position: absolute;
  left: 50%; bottom: 22%;
  width: min(180px, 40vw); height: 1px;
  transform: translateX(-50%);
  background: rgba(246, 245, 237, 0.2);
  overflow: hidden;
}
.curtain__bar::after {
  content: "";
  position: absolute; inset: 0;
  background: var(--paper);
  transform: scaleX(0);
  transform-origin: left;
  animation: barIn 1s var(--ease-io) 0.15s forwards;
}
.curtain.is-done { transform: translateY(-100%); }

@keyframes markIn { to { opacity: 1; } }
@keyframes barIn  { to { transform: scaleX(1); } }

@media (prefers-reduced-motion: reduce) {
  .curtain { display: none; }
}

/* Scroll progress hairline */
.progress {
  position: fixed;
  top: 0; left: 0;
  z-index: 121;
  height: 1px;
  width: 100%;
  background: var(--bronze);
  transform: scaleX(var(--p, 0));
  transform-origin: left;
}

/* --------------------------------------------------------------------------
   24. Utilities
   -------------------------------------------------------------------------- */

.mt-0  { margin-top: 0 !important; }
.mt-1  { margin-top: 0.5rem; }
.mt-2  { margin-top: 1rem; }
.mt-3  { margin-top: 1.75rem; }
.mt-4  { margin-top: 2.5rem; }
.mt-5  { margin-top: clamp(3rem, 6vw, 5rem); }
.mb-3  { margin-bottom: 1.75rem; }
.mb-4  { margin-bottom: 2.5rem; }
.mb-5  { margin-bottom: clamp(3rem, 6vw, 5rem); }

.muted { color: var(--fg-muted); }
.bronze { color: var(--bronze); }
.upper { text-transform: uppercase; letter-spacing: var(--track-caps); }
.nowrap { white-space: nowrap; }
.full { width: 100%; }
.flex { display: flex; }
.between { justify-content: space-between; }
.items-center { align-items: center; }
.items-end { align-items: flex-end; }
.gap-1 { gap: 0.5rem; }
.gap-2 { gap: 1rem; }
.gap-3 { gap: 1.75rem; }
.wrap { flex-wrap: wrap; }
.hide-sm { }

@media (max-width: 700px) { .hide-sm { display: none !important; } }

/* --------------------------------------------------------------------------
   25. Print
   -------------------------------------------------------------------------- */

@media print {
  /* Never print a page whose content is still waiting on an observer. */
  [data-reveal], .rv-i, .acc__a {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
  }
  .rule, .spec__title::after { transform: scaleX(1) !important; }
  .acc__panel { grid-template-rows: 1fr !important; }

  .curtain, .cursor, .progress, .skip-link,
  .scroll-cue, .drawer, .drawer__scrim, .marquee { display: none !important; }

  .header { position: static; color: var(--ink); }
  .header::before { opacity: 1; }

  .hero { min-height: 60vh; }
  .carousel__track { overflow: visible; flex-wrap: wrap; }
  .carousel__nav { display: none; }

  body { background: #fff; color: #000; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.7em; }
}

/* ==========================================================================
   26. Handoff build — new components
   Added for the ECLYPSEO audit rebuild. Everything below uses the same tokens
   as the original system; no new colours were introduced.
   ========================================================================== */

/* --- Desktop navigation (audit #9) ------------------------------------- */

.nav { display: none; justify-self: center; }
.nav__list { display: flex; align-items: center; gap: clamp(1rem, 2vw, 2.25rem); }
.nav__item { position: relative; }

.nav__link {
  display: inline-flex; align-items: center; gap: 0.45rem;
  /* 44px minimum tap height (Part E) */
  min-height: 44px; padding-inline: 0.15rem;
  font-family: var(--sans);
  font-size: 0.75rem; font-weight: 400;
  text-transform: uppercase; letter-spacing: var(--track-caps);
  white-space: nowrap;
  transition: opacity 0.4s var(--ease);
}
.nav__link::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 8px;
  height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: right;
  transition: transform 0.5s var(--ease);
}
.nav__item:hover > .nav__link::after,
.nav__link:focus-visible::after,
.nav__link[aria-current="page"]::after { transform: scaleX(1); transform-origin: left; }


.nav__panel {
  position: absolute; top: 100%; left: 50%;
  transform: translate(-50%, -6px);
  min-width: 260px; padding: 0.75rem 0;
  background: var(--paper);
  border: 1px solid rgba(20, 18, 13, 0.14);
  color: var(--ink);
  opacity: 0; visibility: hidden;
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease), visibility 0.35s;
  z-index: 5;
}
.nav__item:hover .nav__panel,
.nav__item:focus-within .nav__panel {
  opacity: 1; visibility: visible; transform: translate(-50%, 0);
}
.nav__panel a {
  display: block; min-height: 44px;
  padding: 0.7rem 1.4rem;
  font-size: 0.8125rem; line-height: 1.4;
  transition: background 0.3s var(--ease), padding-left 0.3s var(--ease);
}
.nav__panel a:hover { background: var(--paper-warm); padding-left: 1.7rem; }

@media (min-width: 1180px) {
  .nav { display: block; }
  .header__inner { grid-template-columns: auto 1fr auto; }
  .burger { display: none; }
}

.btn--sm { padding: 0.85rem 1.5rem; min-height: 44px; }
@media (max-width: 1179px) { .hide-md { display: none !important; } }

/* --- Breadcrumbs -------------------------------------------------------- */

.crumbs { padding-block: 1.5rem; background: var(--bg); }
.crumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.crumbs li { display: flex; align-items: center; gap: 0.5rem; }
.crumbs a, .crumbs span {
  font-family: var(--sans); font-size: 0.6875rem;
  text-transform: uppercase; letter-spacing: var(--track-caps);
  color: var(--fg-muted);
}
.crumbs a { transition: color 0.35s var(--ease); }
.crumbs a:hover { color: var(--fg); }
.crumbs [aria-current] { color: var(--fg); }
.crumbs__sep { opacity: 0.4; }

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

.hero__display {
  margin-top: clamp(0.75rem, 1.6vw, 1.25rem);
  font-size: var(--fs-sub);
  color: rgba(246, 245, 237, 0.88);
}

/* --- Stats (Part E: real values, SSR'd, never a zero) ------------------- */

.stats { list-style: none; }
.stat__value {
  font-size: clamp(2.25rem, 4.6vw, 4rem);
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
}

/* --- Process step list --------------------------------------------------- */

.steps-list { counter-reset: none; border-top: 1px solid var(--rule); }
.step-row {
  display: grid;
  grid-template-columns: auto minmax(0, 15rem) minmax(0, 1fr);
  gap: clamp(1rem, 3vw, 3rem);
  align-items: baseline;
  padding-block: clamp(1.5rem, 2.6vw, 2.25rem);
  border-bottom: 1px solid var(--rule);
}
.step-row__n { font-size: 1.5rem; opacity: 0.5; min-width: 2.5ch; }
.step-row__t {
  font-family: var(--serif); font-weight: 500;
  font-size: clamp(1.0625rem, 1.5vw, 1.3rem);
  text-transform: uppercase; letter-spacing: var(--track-caps);
  line-height: 1.3;
}
.step-row__b { font-size: 0.9375rem; line-height: 1.75; color: var(--fg-muted); }

@media (max-width: 820px) {
  .step-row { grid-template-columns: auto minmax(0, 1fr); gap: 0.5rem 1.25rem; }
  .step-row__b { grid-column: 2; }
}

/* --- Content blocks ------------------------------------------------------ */

.block-grid { gap: clamp(2rem, 6vw, 6rem); align-items: center; }
.block-grid--flip .block-grid__text  { order: 2; }
.block-grid--flip .block-grid__media { order: 1; }
@media (max-width: 620px) {
  .block-grid--flip .block-grid__text  { order: 1; }
  .block-grid--flip .block-grid__media { order: 2; }
}

.prose--wide { max-width: 74ch; }

.ulink-inline {
  color: inherit;
  border-bottom: 1px solid var(--rule-strong);
  transition: border-color 0.4s var(--ease);
}
.ulink-inline:hover { border-color: currentColor; }

/* --- White-Glove pillars (handoff B6) ------------------------------------ */

.pillars {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.5rem, 3.5vw, 3.25rem);
  list-style: none;
}
.pillar__media { margin-bottom: clamp(1.25rem, 2.5vw, 1.85rem); }
.pillar__n {
  display: block; font-size: 0.875rem;
  letter-spacing: 0.2em; color: var(--fg-muted);
}
.pillar__t {
  margin-top: 0.6rem;
  font-family: var(--serif); font-weight: 500;
  font-size: clamp(1.125rem, 1.8vw, 1.5rem);
  line-height: 1.25;
}
.pillar__b { margin-top: 0.9rem; font-size: 0.9375rem; line-height: 1.75; color: var(--fg-muted); }

@media (max-width: 860px) { .pillars { grid-template-columns: 1fr; } }

/* --- Coverage map -------------------------------------------------------- */

.coverage {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: clamp(1.75rem, 4vw, 4rem);
  align-items: start;
  padding-top: clamp(2rem, 4vw, 3.5rem);
  border-top: 1px solid var(--rule);
}
.coverage__h { font-size: 1rem; }
.coverage__zones {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.65rem 1.5rem;
}
.coverage__zones li {
  position: relative;
  padding-left: 1.2rem;
  font-size: 0.9375rem;
  color: var(--fg);
}
.coverage__zones li::before {
  content: ""; position: absolute; left: 0; top: 0.65em;
  width: 6px; height: 1px; background: var(--bronze-lift);
}
.coverage__zones a { color: inherit; }
.coverage__note { color: var(--fg-muted); font-style: italic; }
.coverage__note::before { display: none; }

@media (max-width: 780px) {
  .coverage { grid-template-columns: 1fr; }
  .coverage__zones { grid-template-columns: 1fr 1fr; }
}

/* --- Track your piece ---------------------------------------------------- */

.track {
  padding-top: clamp(2rem, 4vw, 3.5rem);
  border-top: 1px solid var(--rule);
  max-width: 62ch;
}

/* --- Reviews (editorial, no stars or cards) ------------------------------ */

.quotes { display: grid; gap: clamp(2rem, 4vw, 3.5rem); }
.quote { max-width: 60ch; }
.quote__body {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.25rem, 2.2vw, 1.875rem);
  line-height: 1.4;
  text-wrap: pretty;
}
.quote__by {
  margin-top: 1rem;
  font-family: var(--sans); font-size: 0.75rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
  color: var(--fg-muted);
}
.quote--ghost .quote__body {
  color: var(--fg-muted); opacity: 0.32;
  border-bottom: 1px dashed var(--rule);
  padding-bottom: 0.6rem;
}
.quote--ghost .quote__by { opacity: 0.5; }

/* --- Honest placeholder flag --------------------------------------------- */

.note-flag {
  padding: 1rem 1.25rem;
  border-left: 2px solid var(--bronze);
  background: rgba(156, 124, 78, 0.07);
  font-size: 0.8125rem; line-height: 1.7;
  color: var(--fg-muted);
  max-width: 64ch;
}
.note-flag strong { color: var(--fg); font-weight: 400; }

/* --- Case-study ghost frame ---------------------------------------------- */

.case-ghost__frame {
  position: relative;
  border: 1px dashed var(--rule-strong);
  background:
    repeating-linear-gradient(135deg,
      transparent 0 12px, rgba(20,18,13,0.025) 12px 24px);
}
.is-dark .case-ghost__frame {
  background:
    repeating-linear-gradient(135deg,
      transparent 0 12px, rgba(246, 245, 237,0.035) 12px 24px);
}
.case-ghost__line {
  position: absolute; top: 0; bottom: 0; left: 50%;
  width: 1px; background: var(--rule-strong);
}

/* --- Article cards ------------------------------------------------------- */

.article-card { display: block; }
.article-card__t {
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(1.0625rem, 1.5vw, 1.35rem);
  line-height: 1.3;
  transition: color 0.4s var(--ease);
}
.article-card:hover .article-card__t { color: var(--bronze); }
.article-card__x { font-size: 0.875rem; line-height: 1.7; color: var(--fg-muted); }

.planned li {
  position: relative; padding-left: 1.1rem;
  font-size: 0.875rem; line-height: 1.6; color: var(--fg-muted);
}
.planned li + li { margin-top: 0.7rem; }
.planned li::before {
  content: ""; position: absolute; left: 0; top: 0.6em;
  width: 5px; height: 1px; background: var(--bronze-lift);
}

/* --- Article body -------------------------------------------------------- */

.article { max-width: 68ch; margin-inline: auto; }
.article__meta {
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem;
  padding-block: 1.25rem;
  border-block: 1px solid var(--rule);
  font-size: 0.75rem; text-transform: uppercase;
  letter-spacing: var(--track-caps); color: var(--fg-muted);
}
.article__lede {
  font-family: var(--serif);
  font-size: clamp(1.25rem, 2vw, 1.6rem);
  line-height: 1.5; font-weight: 300;
}
.article h2 {
  margin-top: clamp(2.5rem, 5vw, 4rem);
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(1.375rem, 2.4vw, 2rem);
  line-height: 1.2;
}
.article h2 + p { margin-top: 1.25rem; }
.article p + p { margin-top: 1.25rem; }
.article p { line-height: 1.85; }

/* --- Author card (E-E-A-T) ----------------------------------------------- */

.author {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: 1.5rem; align-items: center;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border: 1px solid var(--rule);
}
.author__avatar {
  width: 72px; height: 72px; border-radius: 50%;
  overflow: hidden; background: var(--paper-deep);
}
.author__avatar img { width: 100%; height: 100%; object-fit: cover; }

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

.footer__grid { grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr)); }
.footer__brand { max-width: 34ch; }
.footer__address {
  font-style: normal; font-size: 0.875rem; line-height: 1.9;
  color: var(--fg-muted);
}
.footer__address a { transition: color 0.35s var(--ease); }
.footer__address a:hover { color: var(--fg); }

.footer__zones {
  padding-block: clamp(2rem, 4vw, 3rem);
  border-bottom: 1px solid var(--rule);
}
.footer__zonelist {
  margin-top: 1rem; font-size: 0.875rem; line-height: 2;
  color: var(--fg-muted);
}
.footer__zonelist a { transition: color 0.35s var(--ease); }
.footer__zonelist a:hover { color: var(--fg); text-decoration: underline; }

.footer__disclaimer { max-width: 52ch; }

@media (max-width: 980px) { .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) { .footer__grid { grid-template-columns: 1fr; } }

/* --- Accordion heading wrapper ------------------------------------------- */

.acc__h { margin: 0; font: inherit; }

/* ==========================================================================
   27. Part E — mobile pass
   Cap full-viewport sections, bring display type down, guarantee tap targets.
   ========================================================================== */

@media (max-width: 860px) {
  /* A 100svh hero on a phone pushes all content below the fold and reads as
     an empty screen. Cap it and let the next section peek. */
  .hero          { min-height: min(88svh, 660px); }
  .hero--mid     { min-height: min(76svh, 560px); }
  .hero--short   { min-height: min(64svh, 480px); }
  .split__panel  { min-height: 64vw; }
  .band          { min-height: 42vw; }

  :root {
    --fs-hero:    clamp(2.5rem, 13vw, 4rem);
    --fs-display: clamp(1.875rem, 8.5vw, 2.75rem);
    --fs-title:   clamp(1.5rem, 6.5vw, 2rem);
    --fs-sub:     clamp(1.125rem, 5vw, 1.5rem);
  }

  /* Tap targets — 44px minimum on everything interactive. */
  .ulink, .footer__links a, .lang__list a, .crumbs a {
    display: inline-flex; align-items: center; min-height: 44px;
  }
  .pill { min-height: 44px; display: inline-flex; align-items: center; }
  .icon-btn { min-width: 44px; min-height: 44px; justify-content: center; }
  .burger { width: 44px; height: 44px; justify-content: center; }
  /* Missed in the original pass — every other header control got this. */
  .lang__toggle { min-width: 44px; min-height: 44px; justify-content: center; }
  .acc__btn { min-height: 56px; }
  /* Address suggestion rows — same 44px floor, needed most on the checkout
     address field this sizes for. */
  .ac__item { min-height: 44px; display: flex; align-items: center; }
  .carousel__btn { width: 44px; height: 44px; }
}

@media (max-width: 620px) {
  .hero__inner { padding-inline: 1.25rem; }
  .split__title { letter-spacing: 0.12em; text-indent: 0.12em; }
  .quote__body { font-size: 1.25rem; }
}

/* iOS: a fixed-height hero plus a full-bleed video needs an explicit
   background or the gap flashes white during rubber-band scrolling. */
@supports (-webkit-touch-callout: none) {
  .hero { background: var(--ink); }
  .bg-video { will-change: opacity; }
}

/* Ghost reviews need to read as a designed empty state, not a render failure. */
.quote--ghost .quote__body {
  display: grid; gap: 0.55rem;
  opacity: 1; color: transparent;
  border-bottom: 0; padding-bottom: 0;
}
.quote--ghost .quote__body::before,
.quote--ghost .quote__body::after {
  content: ""; display: block; height: 1px;
  background: var(--rule-strong); opacity: 0.55;
}
.quote--ghost .quote__body::before { width: 100%; }
.quote--ghost .quote__body::after  { width: 62%; }
.quote--ghost .quote__by { opacity: 0.55; }

/* The scroll cue collides with the hero CTAs once the hero is capped. */
@media (max-width: 860px) {
  .scroll-cue { display: none; }
}

/* ==========================================================================
   28. Pre-show cut-back — new components
   The homepage lists; the service pages explain. These carry the names and the
   links (the SEO work) without the sentences.
   ========================================================================== */

/* --- Hero: display line carries the soul, H1 carries the keywords -------- */

.hero__display-xl{
  font-family:var(--serif);font-weight:300;
  font-size:var(--fs-hero);line-height:.94;letter-spacing:.02em;
  text-wrap:balance;
}
.hero__h1{
  margin-top:clamp(.75rem,1.6vw,1.15rem);
  font-family:var(--serif);font-weight:400;font-style:italic;
  font-size:clamp(1.0625rem,1.9vw,1.5rem);line-height:1.3;
  letter-spacing:.01em;
  color:rgba(246,245,237,.88);
}

/* --- Services index ------------------------------------------------------ */

.svc-index{border-top:1px solid var(--rule)}
.svc-index__row{position:relative;border-bottom:1px solid var(--rule)}

.svc-index__link{
  display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  gap:clamp(1rem,3vw,2.5rem);align-items:baseline;
  padding-block:clamp(1.1rem,2.4vw,1.75rem);
  transition:padding-inline .55s var(--ease),color .45s var(--ease);
}
.svc-index__row:hover .svc-index__link{padding-inline:clamp(.5rem,1.5vw,1.25rem)}

.svc-index__n{
  font-family:var(--sans);font-size:.6875rem;letter-spacing:var(--track-label);
  color:var(--fg-muted);
}
.svc-index__name{
  font-family:var(--serif);font-weight:300;
  font-size:clamp(1.5rem,4.2vw,3rem);line-height:1;
  letter-spacing:.01em;
}
.svc-index__go{
  font-size:1rem;color:var(--fg-muted);
  transition:transform .55s var(--ease),color .45s var(--ease);
}
.svc-index__row:hover .svc-index__go{transform:translateX(.4rem);color:var(--fg)}

/* Hover thumbnail — keeps the imagery without a stack of full-bleed bands. */
.svc-index__thumb{
  position:absolute;top:50%;right:14%;
  width:min(240px,22vw);aspect-ratio:3/2;
  overflow:hidden;pointer-events:none;
  opacity:0;transform:translateY(-50%) scale(.94);
  transition:opacity .5s var(--ease),transform .7s var(--ease);
  z-index:2;
}
.svc-index__thumb img{width:100%;height:100%;object-fit:cover}
.svc-index__row:hover .svc-index__thumb{opacity:1;transform:translateY(-50%) scale(1)}

@media(hover:none),(max-width:900px){
  .svc-index__thumb{display:none}
  .svc-index__link{grid-template-columns:auto minmax(0,1fr) auto}
}

/* --- Bench trio ---------------------------------------------------------- */

@media(max-width:820px){
  .bench-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .bench-grid figure:last-child{display:none}
}
@media(max-width:520px){
  .bench-grid{grid-template-columns:minmax(0,1fr)}
  .bench-grid figure:last-child{display:block}
}

/* --- Maison card, quiet variant (name only, no quote) -------------------- */

.maison-card--quiet .maison-card__body{
  padding-block:clamp(1rem,2vw,1.5rem);
  background:linear-gradient(180deg,transparent,rgba(12,11,8,.66));
}
.maison-card--quiet .maison-card__name{letter-spacing:.18em}

/* ==========================================================================
   29. 18 Aug 2026 revision — new components
   The client could not reproduce our scrims and gradients in Canva but asked
   for them to stay, so everything below inherits the existing dark treatments.
   ========================================================================== */

/* --- Hero price row (cleaning services) --------------------------------- */

.price-row{
  display:flex;flex-wrap:wrap;justify-content:center;
  gap:clamp(1.5rem,4vw,3.5rem);
}
.price-row__item{text-align:center}
.price-row__amount{
  margin-top:.5rem;font-size:clamp(1.75rem,3.4vw,2.75rem);line-height:1;
  color:var(--paper);
}

/* --- Hotspot diagram ----------------------------------------------------- */

.hotspot{
  /* 1.4fr gave the image 58% of the row; 1.88fr gives it 65%, about 12% more
     presence, which is what the 1 Sep note asked for. */
  display:grid;grid-template-columns:minmax(0,1.88fr) minmax(0,1fr);
  gap:clamp(1.5rem,4vw,4rem);align-items:center;
}
/* The product shots are studio cut-outs on a pure white plane with a soft
   contact shadow. Multiplying them into the cream page ground drops the white
   to exactly the page colour and leaves the shadow reading as a real shadow —
   the piece sits on the page rather than in a box, without retouching the
   photograph. Needs a painted ground to multiply against. */
.hotspot__stage{position:relative;background:var(--bg)}
.hotspot__stage img{width:100%;height:auto;display:block;mix-blend-mode:multiply}

.hotspot__pin{
  position:absolute;transform:translate(-50%,-50%);
  width:44px;height:44px;display:grid;place-items:center;
  border-radius:50%;cursor:pointer;
}
.hotspot__pin span[aria-hidden]{
  width:15px;height:15px;border-radius:50%;
  background:var(--ink);
  box-shadow:0 0 0 2px var(--paper), 0 0 0 3px rgba(20,18,13,.35), 0 0 0 9px rgba(20,18,13,.10);
  transition:transform .45s var(--ease),box-shadow .45s var(--ease),background .45s var(--ease);
}
.hotspot__pin:hover span[aria-hidden]{transform:scale(1.25)}
.hotspot__pin[aria-expanded="true"] span[aria-hidden]{
  background:var(--bronze);
  box-shadow:0 0 0 2px var(--paper), 0 0 0 3px var(--bronze), 0 0 0 11px rgba(156,124,78,.22);
  transform:scale(1.15);
}
/* A quiet pulse so the points read as interactive without shouting. */
@media(prefers-reduced-motion:no-preference){
  .hotspot__pin span[aria-hidden]{animation:pinPulse 3.2s var(--ease-io) infinite}
  .hotspot__pin[aria-expanded="true"] span[aria-hidden]{animation:none}
}
@keyframes pinPulse{
  0%,100%{box-shadow:0 0 0 2px var(--paper), 0 0 0 3px rgba(20,18,13,.35), 0 0 0 7px rgba(20,18,13,.12)}
  50%    {box-shadow:0 0 0 2px var(--paper), 0 0 0 3px rgba(20,18,13,.35), 0 0 0 14px rgba(20,18,13,0)}
}

.hotspot__panel{max-width:46ch}
.hotspot__t{
  font-family:var(--serif);font-weight:500;
  font-size:clamp(1.15rem,2.2vw,1.6rem);line-height:1.2;
  text-transform:uppercase;letter-spacing:var(--track-caps);
}
.hotspot__b{margin-top:1rem;line-height:1.8;color:var(--fg-muted)}
.hotspot__price{
  margin-top:1.1rem;font-size:1.25rem;letter-spacing:.04em;color:var(--fg);
}
.hotspot__panel[hidden]{display:none}

@media(max-width:860px){
  .hotspot{grid-template-columns:1fr}
  .hotspot__panels{border-top:1px solid var(--rule);padding-top:1.5rem}
  .hotspot__panel{max-width:none}
}

/* --- Price grid (accessories) ------------------------------------------- */

.pricegrid{
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:1px;background:var(--rule);border:1px solid var(--rule);
}
.pricegrid__item{background:var(--bg);padding:clamp(1.25rem,2.5vw,2rem)}
.pricegrid__t{
  font-family:var(--serif);font-weight:500;font-size:1rem;
  text-transform:uppercase;letter-spacing:var(--track-caps);
}
.pricegrid__p{margin-top:.75rem;font-size:1.25rem;line-height:1}
@media(max-width:860px){.pricegrid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:480px){.pricegrid{grid-template-columns:1fr}}

/* --- Authentication tiers ------------------------------------------------ */

.tier__time{font-size:clamp(1.5rem,3vw,2.25rem);line-height:1}
.tier__price{
  font-size:.8125rem;text-transform:uppercase;letter-spacing:var(--track-caps);
  color:var(--bronze-lift);
}

/* --- Maison specialist service cards ------------------------------------- */

.spec-card{
  display:flex;flex-direction:column;
  padding-top:1.5rem;border-top:1px solid var(--rule);
}
.spec-card__t{
  font-family:var(--serif);font-weight:500;font-size:1rem;line-height:1.25;
  text-transform:uppercase;letter-spacing:var(--track-caps);
  min-height:2.5em;
}
.spec-card__b{margin-top:.9rem;font-size:.875rem;line-height:1.75;color:var(--fg-muted);flex:1}
.spec-card__p{margin-top:1.1rem;font-size:1.0625rem;letter-spacing:.03em}
.spec-card__cta{margin-top:1rem;align-self:flex-start}
.spec-card__note{
  margin-top:1rem;font-size:.6875rem;text-transform:uppercase;
  letter-spacing:var(--track-label);color:var(--fg-muted);
}

/* --- Products & techniques / Time frame ---------------------------------- */

.twocol{gap:1px;background:var(--rule);border:1px solid var(--rule)}
.twocol__col{background:var(--bg);padding:clamp(1.5rem,3vw,2.5rem)}
.twocol__t{font-size:.9375rem}
.twocol__b{margin-top:1rem;font-size:.9375rem;line-height:1.8;color:var(--fg-muted)}
@media(max-width:620px){.twocol{grid-template-columns:1fr}}

/* --- The Archive --------------------------------------------------------- */

.archive__filters{
  display:flex;flex-wrap:wrap;align-items:center;gap:.75rem 1.25rem;
  padding-block:1.5rem;border-block:1px solid var(--rule);
}
.archive__flabel{flex:0 0 auto}
.archive__fgroup{display:flex;flex-wrap:wrap;gap:.5rem}

.chip{
  min-height:44px;padding:.6rem 1.1rem;
  border:1px solid var(--rule);border-radius:999px;
  font-family:var(--sans);font-size:.6875rem;
  text-transform:uppercase;letter-spacing:var(--track-caps);
  color:var(--fg-muted);cursor:pointer;
  transition:color .4s var(--ease),border-color .4s var(--ease),background .4s var(--ease);
}
.chip:hover{color:var(--fg);border-color:var(--rule-strong)}
.chip.is-active{background:var(--fg);color:var(--bg);border-color:var(--fg)}

.archive__card[hidden]{display:none}
.archive__t{
  font-family:var(--serif);font-weight:400;
  font-size:clamp(1.125rem,2vw,1.5rem);line-height:1.25;
}
.archive__b{font-size:.9375rem;line-height:1.8;color:var(--fg-muted);max-width:52ch}

/* --- Founder letter ------------------------------------------------------ */

.letter{max-width:62ch}
.letter p+p{margin-top:1.25rem}
/* One size throughout, matching .lede — the opening paragraph used to be set
   larger and the rest stepped down beneath it. */
.letter p{font-size:var(--fs-lede);line-height:1.7;font-weight:300;color:var(--fg-muted)}
.letter__lede{color:var(--fg)!important}
.letter__sign{margin-top:2.25rem;display:grid;gap:.35rem}
.letter__name{
  font-family:var(--serif);font-style:italic;font-size:1.375rem;color:var(--fg);
}

/* --- Turnaround blocks (Your Experience) --------------------------------- */
.turn{padding-top:1.5rem;border-top:1px solid var(--rule)}
.turn__label{font-size:.9375rem}
.turn__time{
  margin-top:.75rem;font-size:clamp(1.75rem,3.4vw,2.5rem);line-height:1;
  color:var(--bronze-lift);
}
.turn__body{margin-top:1rem;font-size:.9375rem;line-height:1.8;color:var(--fg-muted)}

/* ==========================================================================
   29. 31 Aug homepage pass
   Hero stripped to two lines, both CTAs in cream, the page held in the brand
   cream (#F6F5ED, sampled from the brand document) with no ink sections, and
   Your Experience turned into a slider that moves on its own.
   ========================================================================== */

/* --- Buttons: one cream treatment, no arrows ---------------------------- */

.btn--paper {
  --btn-bg: var(--paper);
  --btn-fg: var(--ink);
  border-color: transparent;
}
.btn--paper:hover,
.btn--paper:focus-visible { color: var(--paper); border-color: var(--paper); }
.btn--paper:hover::before,
.btn--paper:focus-visible::before { transform: translateY(-101%); }
/* The generic .is-dark override would flip these back; cream is the point. */
.is-dark .btn--paper { --btn-bg: var(--paper); --btn-fg: var(--ink); }

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

.hero--bare .hero__inner { padding-block: calc(var(--header-h) + 5rem) clamp(6rem, 12vw, 10rem); }

.hero--bare .hero__kicker {
  font-size: 0.75rem;
  letter-spacing: 0.42em;
  text-indent: 0.42em;
  text-transform: uppercase;
  color: rgba(246, 245, 237, 0.86);
  margin-bottom: clamp(1rem, 2.2vw, 1.75rem);
}
.hero--bare .hero__display-xl {
  text-transform: uppercase;
  font-weight: 300;
  letter-spacing: 0.06em;
  /* text-indent is the usual trick for optically centring letter-spaced text,
     but the reveal() word spans are inline-blocks that already absorb the
     trailing space, so here it only reads as a left indent. */
  text-indent: 0;
  /* Measured, not estimated: "LUXURY MAINTAINED" set in Cormorant Garamond 300
     advances 10.274em, plus 0.06em of letter-spacing after each of its 17
     characters — 11.294em in total. The narrowest case is a 320px viewport,
     where the gutter leaves 280px, so the line has to stay under 280/11.294 =
     7.75vw. 7.2vw keeps clear of that at every width, including the fallback
     serif, and the cap sets the desktop line at 104px. */
  font-size: min(7.2vw, 6.5rem);
  white-space: nowrap;
}

.hero__actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: clamp(0.75rem, 1.4vw, 1rem);
  max-width: 340px;
  margin: clamp(2.25rem, 5vw, 3.5rem) auto 0;
}
.hero__actions .btn { min-width: clamp(240px, 26vw, 320px); }

@media (min-width: 861px) {
  .hero__actions {
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    max-width: none;
  }
}

/* --- Clean / Restore ---------------------------------------------------- */
/* The panels carry their own booking button now, so they are divs, not links.
   The image still lifts on hover for the whole panel. */

.split__panel:hover img { transform: scale(1.1); filter: grayscale(0) brightness(0.95); }
.split__panel:hover::after { background: linear-gradient(180deg, rgba(12,11,8,0.18), rgba(12,11,8,0.5)); }
.split__inner { display: flex; flex-direction: column; align-items: center; }

/* --- Language selector -------------------------------------------------- */

.lang__toggle {
  display: inline-flex; align-items: center;
  padding: 0.4rem 0.2rem;
  font-family: var(--sans);
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: currentColor;
  background: none; border: 0; cursor: pointer;
}
.lang__short { display: none; }

@media (max-width: 720px) {
  .lang__full  { display: none; }
  .lang__short { display: inline; }
}

/* Languages that are configured but not yet translated are listed, so the
   control matches the design, but they are not links — see includes/header.php. */
.lang__soon {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: 0.5rem 1.25rem;
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--stone-dim);
  opacity: 0.62;
  cursor: default;
}
.lang__soon em {
  font-family: var(--sans);
  font-style: normal;
  font-size: 0.5625rem;
  letter-spacing: var(--track-wide);
}

/* --- Your Experience: self-scrolling slider ----------------------------- */

.carousel--auto .carousel__track {
  scroll-snap-type: none;      /* snapping fights a continuous scroll */
  scroll-behavior: auto;
}
.carousel--auto .carousel__track.is-stepping { scroll-behavior: smooth; }

.carousel__note {
  margin-top: clamp(2rem, 3.5vw, 3rem);
  font-family: var(--serif);
  /* Sized to hold "Complimentary collection and delivery" on one line at every
     width, which also lifts The FRSHR Standard up behind it. */
  font-size: clamp(0.625rem, 3.2vw, 1.5rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg);
}
.carousel__note .rule { display: block; width: clamp(80px, 12vw, 150px); }
.carousel__note p { margin: 0; white-space: nowrap; }

/* --- At Your Service ---------------------------------------------------- */

.advisor {
  position: relative;
  display: grid;
  place-items: center;
  min-height: clamp(420px, 52vw, 640px);
  padding-block: clamp(4rem, 9vw, 7rem);
  color: var(--paper);
  overflow: hidden;
  isolation: isolate;
  background: var(--ink);
}
.advisor__bg {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(1.03);
  /* Same grade as .split__panel and .band, so every image-led section on the
     homepage sits at one contrast — the 31 Aug note. */
  filter: grayscale(0.16) brightness(0.82);
}
.advisor::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgba(12, 11, 8, 0.28), rgba(12, 11, 8, 0.62));
}
.advisor__inner { position: relative; z-index: 1; }
.advisor__h {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.75rem, 4vw, 3.25rem);
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-indent: 0.08em;
}
.advisor__body {
  max-width: 62ch;
  margin-inline: auto;
  font-size: var(--fs-body);
  line-height: 1.85;
  color: rgba(246, 245, 237, 0.92);
}
.advisor .rule--center { background: rgba(246, 245, 237, 0.45); }

@media (prefers-reduced-motion: reduce) {
  .advisor__bg { transform: none; }
}

/* --------------------------------------------------------------------------
   30. Book Now — the Canva p.32–39 booking journey
   -------------------------------------------------------------------------- */

.bk__stage[hidden] { display: none; }

/* --- Choose a service (p.32) --------------------------------------------- */

.svc-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1rem, 2.5vw, 2rem);
}
@media (max-width: 720px) { .svc-grid { grid-template-columns: 1fr; } }

.svc-card {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 0.85rem;
  padding: clamp(2rem, 4vw, 3.5rem);
  min-height: clamp(17rem, 26vw, 24rem);
  background: var(--paper-warm);
  border: 1px solid var(--rule);
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  transition: border-color 0.5s var(--ease), background 0.5s var(--ease), color 0.5s var(--ease);
}
/* The wipe used on .btn, at panel scale. */
.svc-card::before {
  content: "";
  position: absolute; inset: 0; z-index: 0;
  background: var(--fg);
  transform: translateY(101%);
  transition: transform 0.6s var(--ease);
}
.svc-card > * { position: relative; z-index: 1; }
.svc-card:hover::before,
.svc-card:focus-visible::before { transform: translateY(0); }
.svc-card:hover, .svc-card:focus-visible { color: var(--bg); border-color: var(--fg); }
.svc-card:focus-visible { outline: 1px solid var(--bronze); outline-offset: 3px; }

.svc-card__n {
  font-size: 0.6875rem;
  letter-spacing: var(--track-label);
  color: var(--fg-muted);
  transition: color 0.5s var(--ease);
}
.svc-card:hover .svc-card__n,
.svc-card:focus-visible .svc-card__n { color: rgba(246, 245, 237, 0.6); }

.svc-card__title {
  font-family: var(--serif);
  font-size: clamp(2rem, 4.5vw, 3.5rem);
  font-weight: 300;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.svc-card__rule { width: 3.5rem; }
.svc-card:hover .svc-card__rule,
.svc-card:focus-visible .svc-card__rule { background: rgba(246, 245, 237, 0.5); }

.svc-card__body {
  max-width: 36ch;
  font-size: var(--fs-body);
  line-height: 1.8;
  color: var(--fg-muted);
  transition: color 0.5s var(--ease);
}
.svc-card:hover .svc-card__body,
.svc-card:focus-visible .svc-card__body { color: rgba(246, 245, 237, 0.82); }

.svc-card__go {
  margin-top: auto;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: var(--track-label);
}

/* --- Build stage --------------------------------------------------------- */

.bk__bar {
  display: flex; align-items: baseline; justify-content: flex-end;
  gap: 1rem; flex-wrap: wrap;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--rule);
}
.bk__back { font-size: 0.75rem; letter-spacing: var(--track-wide); }

.bk__layout {
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: start;
}
/* minmax(0, 1fr), not bare 1fr: a bare 1fr track's automatic minimum size is
   "auto", which resolves to the largest min-content width among everything
   sharing the track. The non-wrapping item-select carousel below the picker
   (.items-rail, deliberately non-shrinking so it can scroll horizontally)
   was inflating that minimum to its full unscrolled width — over 1100px —
   and dragging the order summary out past the viewport with it. minmax(0, ...)
   gives the track an explicit 0 floor so it can no longer be sized by
   content, without touching .items-rail's own intentional internal scroll. */
@media (max-width: 900px) { .bk__layout { grid-template-columns: minmax(0, 1fr); } }

/* Sticky summary on desktop only — on a phone it belongs after the form. */
@media (min-width: 901px) {
  .bk__summary { position: sticky; top: calc(var(--header-h) + 2rem); }
}

/* --- Item rail (p.33) ----------------------------------------------------
   A grid on desktop; on a phone it becomes a snapping horizontal rail so the
   icons swipe Bag → Shoe → Hat → Duffel Bag, per the client's red note. */
.items-rail {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.75rem;
}
@media (max-width: 1180px) { .items-rail { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.items-rail__hint { display: none; margin-top: 0.75rem; }

@media (max-width: 720px) {
  .items-rail {
    display: flex;
    gap: 0.75rem;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* Bleed to the gutter so the rail reads as continuing off-screen. */
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
    padding-bottom: 0.25rem;
  }
  .items-rail::-webkit-scrollbar { display: none; }
  .items-rail .choice--item {
    flex: 0 0 clamp(7.5rem, 34vw, 9.5rem);
    scroll-snap-align: center;
  }
  .items-rail__hint { display: block; }
}

.choice--item { gap: 1rem; }
.choice--item svg { width: 40px; height: 40px; }

/* --- Boxed select (p.34 field treatment) --------------------------------- */

.field--boxed { padding-top: 0; position: relative; }
.field--boxed .field__cap {
  display: block;
  margin-bottom: 0.6rem;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--fg-muted);
}
.field--boxed select {
  width: 100%;
  padding: 1rem 2.5rem 1rem 1.15rem;
  background: transparent;
  border: 1px solid var(--rule-strong);
  border-radius: 0;
  font-family: var(--sans); font-size: 0.9375rem; font-weight: 300;
  color: var(--fg);
  appearance: none;
  cursor: pointer;
  transition: border-color 0.45s var(--ease);
}
.field--boxed select:hover { border-color: var(--fg); }
.field--boxed select:focus { outline: none; border-color: var(--fg); }
/* A required field flagged by validation — cleared the moment it's filled. */
.field--boxed.is-invalid select { border-color: var(--bronze); }
.field--boxed::after {
  content: "";
  position: absolute; right: 1.2rem; bottom: 1.35rem;
  width: 7px; height: 7px;
  border-right: 1px solid var(--fg-muted);
  border-bottom: 1px solid var(--fg-muted);
  transform: rotate(45deg);
  pointer-events: none;
}

/* --- Service / tier rows (p.39) ------------------------------------------ */

.svc-list { display: flex; flex-direction: column; }

.svc-row {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 1rem;
  padding: 1rem 0.25rem;
  border-bottom: 1px solid var(--rule);
  cursor: pointer;
  transition: color 0.4s var(--ease);
}
.svc-row:first-child { border-top: 1px solid var(--rule); }
.svc-row input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }

.svc-row__mark {
  width: 15px; height: 15px;
  border: 1px solid var(--rule-strong);
  border-radius: 50%;
  transition: border-color 0.4s var(--ease), background 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.svc-row__mark--box { border-radius: 0; }
.svc-row:has(input:checked) .svc-row__mark {
  background: var(--fg);
  border-color: var(--fg);
  box-shadow: inset 0 0 0 3px var(--bg);
}
.svc-row:has(input:focus-visible) { outline: 1px solid var(--bronze); outline-offset: 2px; }
.svc-row:hover .svc-row__mark { border-color: var(--fg); }

.svc-row__label { font-size: 0.9375rem; font-weight: 300; }
.svc-row__note {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--fg-muted);
}
.svc-row__price { font-size: 0.8125rem; letter-spacing: var(--track-wide); white-space: nowrap; }

/* --- Custom quote panel (p.36) ------------------------------------------- */

.quote-panel {
  padding: clamp(1.75rem, 3vw, 2.5rem);
  background: var(--ink);
  color: var(--paper);
  border: 1px solid var(--ink);
}
.quote-panel .label { color: rgba(246, 245, 237, 0.72); }
.quote-panel .rule { background: rgba(246, 245, 237, 0.3); width: 3.5rem; }
.quote-panel__body {
  max-width: 46ch;
  font-size: var(--fs-body);
  line-height: 1.85;
  color: rgba(246, 245, 237, 0.92);
}
.quote-panel .btn { --btn-fg: var(--ink); --btn-bg: var(--paper); }

/* --- Order lines --------------------------------------------------------- */

.order-lines { border-top: 1px solid var(--rule); }
.order-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: start;
  gap: 0.75rem;
  padding-block: 0.85rem;
  border-bottom: 1px solid var(--rule);
  font-size: 0.8125rem;
}
.order-line__title { font-size: 0.875rem; font-weight: 300; }
.order-line__meta {
  margin-top: 0.25rem;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--fg-muted);
}
.order-line__price { white-space: nowrap; }
.order-line__remove {
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--fg-muted);
  background: none; border: 0; cursor: pointer;
  transition: color 0.4s var(--ease);
}
.order-line__remove:hover { color: var(--bronze); }

.summary__total.is-quote { font-size: clamp(1.125rem, 1.8vw, 1.5rem); }

/* --------------------------------------------------------------------------
   31. 31 Aug final pass — homepage tightening, footer alignment
   -------------------------------------------------------------------------- */

/* The wordmark carries a text-indent that cancels its own letter-spacing, so
   it optically centres. In the footer it is ranged left against the labels and
   links beneath it, where that indent reads as a few pixels of drift. */
.footer__brand .wordmark { text-indent: 0; }
/* The Archive cards themselves take the Your Experience proportions via
   .media--3x4 in index.php, so every card on the homepage shares one
   silhouette. .compare sets no ratio of its own, so nothing fights it. */

/* --- Book Now: plain note, and the Add More re-entry ---------------------- */

/* The disclaimer is a note, not a callout — no bronze rule, no tinted box. */
.bk__note {
  max-width: 70ch;
  font-size: 0.8125rem;
  line-height: 1.85;
  color: var(--fg-muted);
}
.bk__note strong { color: var(--fg); font-weight: 400; }

/* Add More re-opens the picker for a new piece. The rail lifts and captions
   itself so it is obvious the next action is choosing another item, and that
   nothing already in the order has been disturbed. */
.bk__pick {
  margin-inline: calc(clamp(0.75rem, 2vw, 1.5rem) * -1);
  padding: clamp(0.75rem, 2vw, 1.5rem);
  border: 1px solid transparent;
  transition: border-color 0.5s var(--ease), background 0.5s var(--ease);
}
.bk__pick.is-adding {
  border-color: var(--rule-strong);
  background: var(--paper-warm);
}
.bk__prompt {
  margin-top: 0.85rem;
  font-size: 0.8125rem;
  letter-spacing: var(--track-wide);
  color: var(--fg);
}
.bk__prompt[hidden] { display: none; }

/* Below 720px the item rail bleeds to the gutter itself, so the picker cannot
   also pull left — that would push the rail past the edge of the page. */
@media (max-width: 720px) {
  .bk__pick { margin-inline: 0; padding-inline: 0; }
  .bk__pick.is-adding { background: transparent; border-inline-color: transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .bk__pick { transition: none; }
}

/* --------------------------------------------------------------------------
   32. 1 Sep pass — one closing CTA, service-page consistency
   -------------------------------------------------------------------------- */

/* --- Closing CTA ---------------------------------------------------------
   Deliberately shallower than .advisor and set at the same overlay grade as
   .split__panel, .band and .advisor, so every image-led block on the site
   reads as one component. */
.endcta {
  position: relative;
  display: grid;
  place-items: center;
  min-height: clamp(340px, 38vw, 460px);
  padding-block: clamp(3.5rem, 7vw, 5.5rem);
  color: var(--paper);
  overflow: hidden;
  isolation: isolate;
  background: var(--ink);
}
.endcta__bg {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(0.16) brightness(0.82);
}
.endcta::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgba(12, 11, 8, 0.28), rgba(12, 11, 8, 0.62));
}
.endcta__inner { position: relative; z-index: 1; }
.endcta__h {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.75rem, 4vw, 3.25rem);
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-indent: 0.08em;
  text-wrap: balance;
}
.endcta__body {
  max-width: 56ch;
  margin-inline: auto;
  font-size: var(--fs-body);
  line-height: 1.85;
  color: rgba(246, 245, 237, 0.9);
}
.endcta .rule--center { background: rgba(246, 245, 237, 0.45); }

/* --- Descenders ----------------------------------------------------------
   .rv clips its own overflow so the word can slide up from nothing. At display
   sizes 0.06em was not enough room for the tail of a "g", which is how "Bag
   Cleaning" and "Bag Restoration & Repair" came to be shaved off at the
   baseline. The negative margin cancels the padding, so nothing moves. */
.rv { padding-bottom: 0.2em; margin-bottom: -0.2em; }

/* --- Leather Accessories: icon selector (Canva p.31) ---------------------- */

.itempick__panels {
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  padding-top: clamp(1.5rem, 3vw, 2.25rem);
  border-top: 1px solid var(--rule);
}
.itempick__panel[hidden] { display: none; }
.itempick__t {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.15rem, 2.2vw, 1.6rem);
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
}
.itempick__p {
  margin-top: 0.75rem;
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  line-height: 1;
  letter-spacing: 0.04em;
}
.itempick__p.muted { font-size: clamp(1.05rem, 1.6vw, 1.25rem); color: var(--fg-muted); }

/* --- Hero price labels ----------------------------------------------------
   These sit over the hero photograph, where the muted ink of .label had almost
   no contrast. Shoe Cleaning shows two of them, so they have to read. */
.price-row__item .label {
  color: rgba(246, 245, 237, 0.92);
  text-shadow: 0 1px 12px rgba(12, 11, 8, 0.55);
}

/* --- Archive: grouped, expanding filters --------------------------------- */

/* The grid section runs .section--flush so it sits tight under the filters,
   which also stripped its bottom padding — leaving the last caption resting
   straight on the closing CTA's photograph. This restores the same gap every
   other page leaves before that band (.section--tight, as used by Related
   services on the service pages). */
[data-archive] { padding-bottom: clamp(3rem, 6vw, 6rem); }

.archive__groups { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; }

.fgroup__btn {
  display: inline-flex; align-items: center; gap: 0.6rem;
  padding: 0.5rem 1rem;
  background: transparent;
  border: 1px solid var(--rule-strong);
  font-family: var(--sans);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--fg-muted);
  cursor: pointer;
  transition: color 0.4s var(--ease), border-color 0.4s var(--ease), background 0.4s var(--ease);
}
.fgroup__btn:hover { color: var(--fg); border-color: var(--fg); }
.fgroup__btn.is-open,
.fgroup__btn.has-choice { background: var(--fg); color: var(--bg); border-color: var(--fg); }

.fgroup__caret {
  width: 6px; height: 6px;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.4s var(--ease);
}
.fgroup__btn.is-open .fgroup__caret { transform: translateY(1px) rotate(-135deg); }

/* Flows inline below the row rather than floating over the grid, so opening a
   group pushes the cards down instead of covering them. */
.fgroup__options {
  display: flex; flex-wrap: wrap; gap: 0.5rem;
  margin-top: 0.6rem;
  padding: 0.85rem;
  border: 1px solid var(--rule);
  background: var(--paper-warm);
}
.is-dark .fgroup__options { background: var(--ink-lift); }
.fgroup__options[hidden] { display: none; }

/* --- Footer lockup -------------------------------------------------------
   FRSHR and LUXURY MAINTAINED are one piece of supplied artwork now, so the
   centring the two separate lines used to need is built into the file. */

/* --- Centred tracked text in the hero ------------------------------------
   letter-spacing adds its gap after the last character too, so centred capitals
   sit half a track to the left of true centre. Matching the indent puts the
   glyphs back on the middle of the screen. */
.hero__kicker,
.price-row__item .label { text-indent: var(--track-label); }

/* --- Cart line editor ----------------------------------------------------- */

.cart-row { align-items: start; }
.cart-edit { max-width: 44ch; }
.cart-edit .svc-list { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   33. Complete your care — the optional add-on stage
   -------------------------------------------------------------------------- */

.upsell {
  position: fixed; inset: 0;
  z-index: 140;
  display: grid;
  place-items: center;
}
.upsell[hidden] { display: none; }

.upsell__scrim {
  position: absolute; inset: 0;
  background: rgba(12, 11, 8, 0.55);
  backdrop-filter: blur(3px);
  animation: upsellFade 0.4s var(--ease) both;
}

.upsell__panel {
  position: relative;
  width: min(560px, calc(100vw - 2rem));
  max-height: min(86vh, 780px);
  overflow-y: auto;
  padding: clamp(1.75rem, 4vw, 2.75rem);
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--rule);
  animation: upsellRise 0.5s var(--ease) both;
}
.upsell__x { position: absolute; top: 0.9rem; right: 0.9rem; }

.upsell__h {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.6rem, 3.4vw, 2.4rem);
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.upsell__body { font-size: var(--fs-body); line-height: 1.75; color: var(--fg-muted); }

/* One card per add-on: name, price, and a state that reads as chosen. */
.upsell__grid { display: grid; gap: 0.6rem; }
.upsell__card {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.35rem 1rem;
  padding: 1rem 1.15rem;
  border: 1px solid var(--rule-strong);
  cursor: pointer;
  transition: border-color 0.4s var(--ease), background 0.4s var(--ease), color 0.4s var(--ease);
}
.upsell__card input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.upsell__card:hover { border-color: var(--fg); }
.upsell__card:has(input:checked) { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.upsell__card:has(input:focus-visible) { outline: 1px solid var(--bronze); outline-offset: 3px; }

.upsell__card__t { font-size: 0.9375rem; font-weight: 300; }
.upsell__card__p { font-size: 0.9375rem; letter-spacing: 0.04em; white-space: nowrap; }
.upsell__card__go {
  grid-column: 1 / -1;
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--fg-muted);
  transition: color 0.4s var(--ease);
}
.upsell__card:has(input:checked) .upsell__card__go { color: rgba(246, 245, 237, 0.75); }
.upsell__card:has(input:checked) .upsell__card__go::after { content: "ed"; }

/* On a phone it is a sheet that rises from the bottom, not a small box in the
   middle — easier to reach one-handed. */
@media (max-width: 620px) {
  .upsell { align-items: end; }
  .upsell__panel {
    width: 100%;
    max-height: 88vh;
    border-inline: 0; border-bottom: 0;
    animation-name: upsellSheet;
  }
}

@keyframes upsellFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes upsellRise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
@keyframes upsellSheet { from { transform: translateY(100%); } to { transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .upsell__scrim, .upsell__panel { animation: none; }
}

/* Services and add-ons, listed against the item they belong to. */
.cart-parts { margin: 0; padding: 0; list-style: none; max-width: 34rem; }
.cart-parts li {
  display: flex; justify-content: space-between; gap: 1rem;
  padding-block: 0.3rem;
  font-size: 0.8125rem;
  color: var(--fg-muted);
}
.cart-parts li + li { border-top: 1px solid var(--rule); }
.cart-parts__addon::before { content: "+ "; color: var(--bronze); }

/* An add-on a chosen service already covers: still listed, so the customer can
   see the cleaning is included, but not selectable. */
.upsell__card.is-blocked {
  cursor: default;
  border-style: dashed;
  border-color: var(--rule);
  color: var(--fg-muted);
}
.upsell__card.is-blocked:hover { border-color: var(--rule); }
.upsell__card.is-blocked .upsell__card__p { text-decoration: line-through; }
.upsell__card.is-blocked .upsell__card__go { color: var(--bronze); }

/* Standing order, shown on the service-selection screen. */
.bk__resume {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  padding: 0.9rem 1.15rem;
  border-left: 2px solid var(--bronze);
  background: var(--paper-warm);
}
.bk__resume[hidden] { display: none; }
.bk__resume__t { font-size: 0.875rem; color: var(--fg); }

/* --------------------------------------------------------------------------
   34. Client reviews — Google reviews, set as FRSHR editorial
   -------------------------------------------------------------------------- */

/* No card, no border, no shadow: a quote panel on the cream ground, sharing
   .carousel__item's width so it lines up with Your Experience exactly. */
.rev {
  display: flex;
  flex-direction: column;
  padding: clamp(1.5rem, 2.5vw, 2rem) 0 0;
  border-top: 1px solid var(--rule);
}

.rev__stars {
  font-size: 0.8125rem;
  letter-spacing: 0.32em;
  line-height: 1;
  color: var(--bronze);
}

/* The review is the section. Set as an editorial quote, not review-card copy. */
.rev__body {
  margin: clamp(1.1rem, 2vw, 1.5rem) 0 0;
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.0625rem, 1.35vw, 1.25rem);
  line-height: 1.6;
  color: var(--fg);
}
.rev__body p { margin: 0; }
.rev__body p::before { content: "“"; }
.rev__body p::after  { content: "”"; }

/* Every panel keeps one height whatever the review's length. A longer one
   clamps and offers Read more rather than stretching its neighbours. */
.rev__body[data-clamp] p {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 9;
  overflow: hidden;
}
.rev__body.is-open p { -webkit-line-clamp: unset; overflow: visible; }

.rev__more {
  align-self: flex-start;
  margin-top: 0.85rem;
  padding: 0;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--rule-strong);
  font-family: var(--sans);
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--fg-muted);
  cursor: pointer;
  transition: color 0.4s var(--ease), border-color 0.4s var(--ease);
}
.rev__more:hover { color: var(--fg); border-color: var(--fg); }
.rev__more[hidden] { display: none; }

/* Name and source sit at the foot of every panel, aligned across the row. */
.rev__meta { margin-top: auto; padding-top: clamp(1.25rem, 2vw, 1.75rem); }
.rev__name {
  display: block;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--fg);
}
.rev__src {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.6875rem;
  letter-spacing: var(--track-wide);
  color: var(--fg-muted);
}
.rev__src a { color: inherit; border-bottom: 1px solid var(--rule); }
.rev__src a:hover { color: var(--fg); border-color: var(--fg); }

/* --------------------------------------------------------------------------
   35. 6 Sep pass — booking immediacy, footer icons, discount field
   -------------------------------------------------------------------------- */

/* Book Now has to show CLEAN / RESTORE on landing rather than an intro, and
   most of all on a phone. Roughly half the usual page-intro height. */
.pintro--tight {
  padding-top: calc(var(--header-h) + clamp(1.5rem, 4vw, 3.5rem));
  padding-bottom: clamp(1rem, 2vw, 1.5rem);
}
.pintro--tight .pintro__title { margin-bottom: clamp(0.75rem, 1.5vw, 1.25rem); }
@media (max-width: 720px) {
  .pintro--tight .pintro__title { font-size: clamp(2rem, 9vw, 2.75rem); }
  /* The "please note" paragraph is long; it can sit below the fold. */
  .bk__note { margin-top: clamp(1.5rem, 4vw, 2.5rem); }
}

/* Privacy and the other information pages open at one height. */
.pintro--info { padding-top: calc(var(--header-h) + clamp(2rem, 5vw, 4rem)); }

/* Discount code, beside the total. */
.discount__row { display: flex; gap: 0.5rem; align-items: flex-end; }
.discount__row .field__input { flex: 1 1 auto; }
.discount__row .btn { flex: 0 0 auto; }
.discount__on {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem;
  font-size: 0.8125rem;
  color: var(--fg);
}

/* Address suggestions — styled as an FRSHR control, not Google's widget. */
[data-autocomplete] { position: relative; }
.ac__list {
  position: absolute; left: 0; right: 0; top: 100%;
  /* Above .whatsapp-float (110, §43) — on a short mobile viewport the address
     field can sit low enough that the floating button would otherwise
     overlap the suggestion list and block a tap. Still below the drawers
     (125/130) and the upsell sheet (140), which should keep covering it. */
  z-index: 115;
  margin: 0; padding: 0.35rem 0;
  list-style: none;
  max-height: 15rem; overflow-y: auto;
  background: var(--paper);
  border: 1px solid var(--rule-strong);
}
.ac__list[hidden] { display: none; }
.ac__item {
  padding: 0.7rem 1rem;
  font-size: 0.875rem;
  line-height: 1.4;
  cursor: pointer;
}
.ac__item:hover, .ac__item.is-on { background: var(--paper-warm); }

/* ==========================================================================
   36. 10 Sep pass — mobile menu parity, full-screen homepage hero
   ========================================================================== */

/* The Part E mobile cap (§27) is right for a content hero — "let the next
   section peek" — but reads as a desktop section shrunk into a phone
   viewport on the homepage's full-bleed video intro. This is the one hero
   the client wants completely immersive. Scoped to .hero--bare (the homepage
   only) so service, maison and 404 heroes keep the Part E behaviour. Equal
   specificity to the §27 rule, so source order — this comes later — is what
   makes it win.

   14 Sep: dvh became lvh. iOS 26 Safari floats a translucent URL bar over the
   bottom of the screen and expects the page to paint underneath it. dvh tracks
   that bar, so the hero stopped above it and the next section showed through
   the transparent surround as a bright strip. lvh is the largest viewport —
   the full screen, bar included — so the hero now fills it. lvh is also static
   where dvh re-measures as the bar collapses, which removes a reflow of the
   video mid-scroll. Keep lvh here: dvh is for things that must stay wholly
   visible (drawers, sheets, modals), not for a hero designed to bleed. */
@media (max-width: 860px) {
  .hero--bare {
    min-height: 100vh;   /* fallback: browsers that do not parse lvh */
    min-height: 100lvh;
  }
}

/* Menu drawer: keep the CTA and contact line clear of the iPhone home
   indicator / Android gesture bar. */
.drawer__foot {
  padding-bottom: calc(clamp(1.5rem, 3vw, 2.25rem) + env(safe-area-inset-bottom));
}

/* ==========================================================================
   37. 10 Sep pass — mobile header rebalance
   Below 1180px there is no primary nav to fill the header's middle grid
   track (§26 turns it on only at 1180px+), so the wordmark — grouped with
   the burger in .header__left — reads as flush-left rather than centred,
   and .header__right's narrower content leaves the appearance of dead space
   on the right. The 1fr/auto/1fr split only centres a group whose own
   width matches its mirror; ours don't, so the fix is to take the wordmark
   out of that flow and centre it on .header__inner directly, independent of
   how wide the burger or basket/language group are on either side.

   That alone isn't enough: with .nav absent from the grid below 1180px,
   auto-placement drops .header__left into column 1 and .header__right into
   column 2 — the "auto" track built for .nav — leaving column 3 empty.
   Flanked by two equal 1fr tracks, .header__right lands dead centre too,
   directly under the now-centred wordmark. Below 1180px the header only
   ever has two groups, so it switches to a plain space-between flex row —
   .header__left pinned start, .header__right pinned end — leaving the
   wordmark's absolute centring as the only thing determining the middle. */
@media (max-width: 1179px) {
  .header__inner {
    display: flex;
    justify-content: space-between;
  }
  .header__left .wordmark {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
}

/* ==========================================================================
   38. 10 Sep pass — cart page mobile reflow
   The cart's content/summary split and each line's info/price/remove row were
   both hardcoded via inline grid-template-columns, which — unlike .bk__layout
   on the booking journey, or .row's own built-in collapse — has no mobile
   breakpoint. Inline styles beat any external media query regardless of
   specificity tricks, so on a phone both grids stayed side-by-side, forcing
   the summary panel and the price/remove columns to overflow the viewport
   instead of dropping below the copy the way the booking journey already
   does. Moved both to real classes with the same collapse .bk__layout uses.
   -------------------------------------------------------------------------- */
.cart__layout {
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: start;
}
/* minmax(0, 1fr), not bare 1fr — see the .bk__layout fix in §30 above for
   why a bare 1fr's automatic minimum can inflate to a child's min-content
   width. Nothing in this column happens to force a blowout today, but a
   bare 1fr leaves the same trap for the next thing added to it. */
@media (max-width: 900px) { .cart__layout { grid-template-columns: minmax(0, 1fr); } }

.cart-row { grid-template-columns: minmax(0, 1fr) auto auto; }
@media (max-width: 800px) {
  .cart-row { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   39. 10 Sep pass — Book Now: trim further so both service cards clear
   the fold on a phone
   §35's .pintro--tight already halved this page's intro height so CLEAN /
   RESTORE would show on landing, but that was tuned against a --header-h of
   68px — §37 later folded env(safe-area-inset-top) into --header-h for the
   notch/Dynamic Island, which on a real notched phone adds height nothing
   here accounted for. Scoped to the booking page's own elements rather than
   the shared .section--snug-top / .mt-3 / .mt-4 utility classes those
   sections also use, so nothing outside Book Now is affected.
   -------------------------------------------------------------------------- */
@media (max-width: 720px) {
  .pintro--tight { padding-top: calc(var(--header-h) + clamp(0.75rem, 2vw, 1.5rem)); }
  [data-booking].section--snug-top { padding-top: clamp(1rem, 3vw, 1.5rem); }
  [data-booking] [data-stage="service"] .lede { margin-top: 0.75rem; }
  [data-booking] .svc-grid { margin-top: clamp(1.25rem, 3vw, 1.75rem); }
}

/* ==========================================================================
   40. Arabic localisation — RTL foundation
   Most of the site mirrors for free: flexbox row layouts (header, buttons,
   .flex/.between) are direction-aware by spec, and quite a lot of this file
   already used logical properties (margin-inline, padding-inline,
   inset-inline-start) rather than left/right, which is why .drawer--menu
   and .band already had a [dir="rtl"] override before this section existed
   — see §26 and the "Mirror the directional scrims" rule above. This
   section is for what's left: text-align:left used as a "start-aligned"
   design choice rather than a literal side, and anything with an explicit
   left/right rather than a logical property. Extended page by page as each
   template is translated and checked in a real RTL render, rather than
   guessed at up front. -------------------------------------------------- */

/* "Ranged left is the default" (§4) means start-aligned, not literally the
   left edge — in RTL that's the right edge. */
[dir="rtl"] .hero__inner--left { text-align: right; }

/* Genuinely directional icons only — checked each one's actual shape rather
   than assuming. The accordion's +/- indicator (.acc__sign) and the drawer's
   X close icon are both symmetric under a horizontal flip, so they're
   deliberately not listed here; breadcrumbs use a plain "/" separator, also
   symmetric. The carousel's prev/next chevrons are real arrows and do need
   to point the other way. Whether the carousel's own scroll direction also
   needs to reverse in RTL (not just its icons) is a JS behaviour to verify
   against main.js once a carousel-bearing page is actually built and
   checked live, not something to guess here. */
[dir="rtl"] .carousel__btn svg {
  transform: scaleX(-1);
}

/* The word-reveal stagger (reveal() in config.php) animates each word's own
   slide-up — vertical, not horizontal — so it already works correctly for
   Arabic with no change here. Listed for anyone auditing this section
   looking for a rule that turned out not to be needed. */

/* The FAQ accordion answer indents under the question's number + icon with a
   literal left padding (.acc__a), which is the wrong side once the question
   itself is right-aligned — used on every page with an FAQ block (FAQ,
   service, maison, /services, /maisons). */
[dir="rtl"] .acc__a { padding-left: 0; padding-right: calc(0.625rem + 1.5rem + 2ch); }
@media (max-width: 620px) {
  [dir="rtl"] .acc__a { padding-right: 0; }
}

/* Booking journey's Clean/Restore selection cards range their copy left by
   default; in RTL that reads as ragged-left Arabic, so range it to the
   trailing edge instead. */
[dir="rtl"] .svc-card { text-align: right; }

/* The bullet dash before each collection zone (Your Experience) and each
   planned Journal title (article "More from the Journal" list) sits at the
   literal left edge — move it to the trailing edge in RTL, which also means
   swapping which side carries the indent. */
[dir="rtl"] .coverage__zones li,
[dir="rtl"] .planned li {
  padding-left: 0;
  padding-right: 1.2rem;
}
[dir="rtl"] .coverage__zones li::before,
[dir="rtl"] .planned li::before {
  left: auto;
  right: 0;
}

/* A left accent bar reads as "trailing" once the text beside it is RTL —
   used on checkout's prototype-checkout notice and the booking journey's
   "order already started" resume banner. */
[dir="rtl"] .note-flag,
[dir="rtl"] .bk__resume {
  border-left: none;
  border-right: 2px solid var(--bronze);
}

/* The custom dropdown chevron on boxed selects (.field--boxed — Brand/Colour
   on the booking journey) and the plain select underline (.field--select —
   checkout's collection area) sits at the field's literal right edge, which
   in RTL is the *leading* edge — the same place typed/selected text starts
   from once dir="rtl" flips the field's own text alignment. Moving it to the
   left keeps it at the field's trailing edge in both directions. */
[dir="rtl"] .field--boxed::after,
[dir="rtl"] .field--select::after {
  right: auto;
}
[dir="rtl"] .field--boxed::after { left: 1.2rem; }
[dir="rtl"] .field--select::after { left: 2px; }

/* Collection time slots ("10 am – 12 pm") are plain text with no bidi
   isolation, unlike prices, which already get this via .numeral. Inside an
   RTL run the bidi algorithm visibly reorders them (renders as
   "am — 12 pm 10"), even though the DOM text is correct — used on Contact
   Us's Collection Hours (.row__cell) and checkout's collection window
   picker (.slot). */
[dir="rtl"] .row__cell,
[dir="rtl"] .slot {
  direction: ltr;
  unicode-bidi: isolate;
}

/* ==========================================================================
   41. Arabic typeface — Amiri + Cairo (approved 10 Sep 2026)
   Amiri for display/heading elements, pairing with Cormorant Garamond's
   editorial weight; Cairo for interface/functional text, pairing with
   Jost's geometric clarity — the client's own framing of the two roles.
   One override each for --serif/--sans, scoped to [dir="rtl"], is enough to
   reach every component: every heading, body paragraph, nav link, button,
   form field, validation message and cart/checkout line already reads its
   font from these two tokens (§1), never a literal font-family. See
   fonts.css for the self-hosted, Arabic-unicode-range-only files — Latin
   characters mixed into Arabic copy (brand names, "AED", "FRSHR") fall
   through past Amiri/Cairo's own Latin glyphs to Cormorant Garamond/Jost,
   because those two files carry no Latin coverage at all, keeping both
   scripts visually consistent with the rest of the site. font-display:swap
   on every face (fonts.css) means no invisible-text block period; the
   layout-shift risk that remains is the swap itself, addressed by the
   preload of the two most-used files (Cairo variable, Amiri 400) in
   head.php so they start downloading before body content, rather than
   competing with everything else the page requests. */
[dir="rtl"] {
  --serif: 'Amiri', "Cormorant Garamond", "Times New Roman", serif;
  --sans:  'Cairo', "Jost", "Helvetica Neue", Arial, sans-serif;
}

/* ==========================================================================
   42. Contact Us — mobile stack fix (10 Sep 2026 pass)
   The form/details split was an inline grid-template-columns with no
   breakpoint at all, so it never collapsed like every other .grid--N does —
   on a phone it squeezed the form fields and the contact details into two
   narrow columns instead of stacking. Same asymmetric ratio on desktop,
   single column below 620px to match the rest of the grid system. */
.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: clamp(2.5rem, 6vw, 6rem);
  align-items: start;
}
@media (max-width: 620px) {
  .contact-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   43. Floating WhatsApp button (11 Sep 2026 pass) — every page
   Deliberately hardcoded ink/paper rather than the --bg/--fg semantic pair:
   this button floats independently of whatever section is scrolled beneath
   it, dark or light, and needs to read the same either way rather than
   flipping with .is-dark like an in-flow component would.

   Positioned with physical right/bottom, not inset-inline-end. Every other
   fixed control on the site (drawers) is allowed to mirror under
   [dir="rtl"] because it slides in from the edge the reading direction
   implies. This one is a "find it in the same corner every time" control,
   so the brief asked for the opposite: it stays bottom-right in Arabic too.

   z-index 110 sits below the drawer scrim (125), drawers (130) and the
   upsell sheet (140), so opening any of those correctly covers it, and below
   nothing else fixed on the page — it is always the topmost thing over
   ordinary content. Sized and inset generously enough to clear the iPhone
   home indicator / Android gesture bar via env(safe-area-inset-*), same
   approach as .drawer__foot in §36.
   ========================================================================== */
.whatsapp-float {
  position: fixed;
  right: max(1.5rem, env(safe-area-inset-right, 0px));
  bottom: max(1.5rem, env(safe-area-inset-bottom, 0px));
  z-index: 110;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper);
  box-shadow: 0 6px 24px rgba(12, 11, 8, 0.28);
  transition: background 0.4s var(--ease), transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.whatsapp-float svg { width: 27px; height: 27px; fill: currentColor; }
.whatsapp-float:hover,
.whatsapp-float:focus-visible {
  background: var(--bronze);
  transform: translateY(-2px);
  box-shadow: 0 10px 28px rgba(12, 11, 8, 0.34);
}

@media (max-width: 640px) {
  .whatsapp-float {
    width: 50px;
    height: 50px;
    right: max(1rem, env(safe-area-inset-right, 0px));
    bottom: max(1rem, env(safe-area-inset-bottom, 0px));
  }
  .whatsapp-float svg { width: 24px; height: 24px; }
}

/* ==========================================================================
   44. The FRSHR Standard — mobile-only collapsible tiles (11 Sep pass),
   numeral + top rule removed (11 Sep pass)
   Baseline (every viewport, JS or not): .std-item__head and .std-item__panel
   are display:contents, so the <button> and the panel wrapper this markup
   needs for the mobile accordion contribute no box of their own — the
   heading and body sit in exactly the same plain block flow as the original
   unwrapped markup, at every width. This is what keeps desktop and tablet
   pixel-identical to before with zero extra CSS, and what keeps a mobile
   visitor with JS disabled reading the full text exactly as today, rather
   than stuck on a heading with no way to open it.

   #standard .feature turns off the shared .feature component's numeral-row
   hairline (border-top + padding-top) — scoped to this section only, so
   Partnerships' own .feature cards (§33) keep their number and rule exactly
   as built. The "01/02/03/04" numeral markup itself was removed from the
   PHP loop in index.php; there is no CSS hook for it left to hide.

   standardAccordion() in main.js adds .std--collapsible to #standard only
   when it confirms (via matchMedia) the viewport is at or below 620px — the
   same breakpoint .grid--4 already collapses to one column at, so the
   accordion behaviour only ever appears once the tiles are already stacked
   single-file. Only .std--collapsible turns the panel into the actual
   accordion; nothing below this comment does anything at 621px and up.
   ========================================================================== */
#standard .feature { border-top: none; padding-top: 0; }

.std-item__head { display: contents; }
.std-item__sign { display: none; }
.std-item__panel { display: contents; }

@media (max-width: 620px) {
  .std--collapsible .std-item__head {
    display: flex;
    align-items: center;
    gap: 1rem;
    width: 100%;
    text-align: start;
    cursor: pointer;
    transition: color 0.4s var(--ease);
  }
  .std--collapsible .std-item__head:hover,
  .std--collapsible .std-item__head:focus-visible { color: var(--bronze); }

  .std--collapsible .std-item__q { flex: 1 1 auto; }
  .std--collapsible .h-caps.feature__title { margin-bottom: 0; }

  .std--collapsible .std-item__sign {
    display: block;
    flex: 0 0 auto;
    position: relative;
    width: 13px; height: 13px;
  }
  .std--collapsible .std-item__sign::before,
  .std--collapsible .std-item__sign::after {
    content: "";
    position: absolute; top: 50%; left: 0;
    width: 100%; height: 1px;
    background: currentColor;
    transition: transform 0.5s var(--ease);
  }
  .std--collapsible .std-item__sign::after { transform: rotate(90deg); }
  .std--collapsible .std-item.is-open .std-item__sign::after { transform: rotate(0deg); }

  .std--collapsible .std-item__panel {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.6s var(--ease);
  }
  .std--collapsible .std-item.is-open .std-item__panel { grid-template-rows: 1fr; }
  /* The grid-rows trick needs a single block child to clip during the
     animation — overflow-wrap guards against the price/measure-free .feature
     column ever letting a long unbroken word push the tile wider than its
     grid track. */
  .std--collapsible .std-item__panel > div { overflow: hidden; }
  .std--collapsible .std-item__panel .feature__body { padding-top: 0.85rem; overflow-wrap: break-word; }
}

@media print {
  .std-item__panel { grid-template-rows: 1fr !important; }
}

/* ==========================================================================
   45. Maison pages — Materials as an accordion (11 Sep pass)
   Same numeral + heading + body markup and typography as before
   (.feature/.feature__n/.h-caps.feature__title/.feature__body — untouched),
   made collapsible with the same technique as §44's homepage tiles: a
   <button> inside the <h3> wrapping the numeral and title, a sign icon built
   from two crossing bars (a "+" that rotates one bar flat to read "−" when
   open) rather than a chevron, so there is no left/right-pointing glyph that
   would need mirroring under [dir="rtl"] — nothing here does.

   Unlike §44, this collapses at every width, not just mobile: .mat-acc
   materials sections are meant to save space full stop, on a maison page
   with four of them stacked one after another in two columns. JS-off still
   renders every material fully expanded — .mat-item__head/.mat-item__panel
   are display:contents until materialsAccordion() (main.js) adds
   .mat-acc--collapsible, which is the only thing any rule below actually
   does anything without.
   ========================================================================== */
.mat-item__head { display: contents; }
.mat-item__sign { display: none; }
.mat-item__panel { display: contents; }

.mat-acc--collapsible .mat-item__head {
  display: flex;
  align-items: center;
  gap: 1rem;
  width: 100%;
  text-align: start;
  cursor: pointer;
  transition: color 0.4s var(--ease);
}
.mat-acc--collapsible .mat-item__head:hover,
.mat-acc--collapsible .mat-item__head:focus-visible { color: var(--bronze); }

.mat-acc--collapsible .mat-item__q { flex: 1 1 auto; }
.mat-acc--collapsible .h-caps.feature__title { margin-bottom: 0; }

.mat-acc--collapsible .mat-item__sign {
  display: block;
  flex: 0 0 auto;
  position: relative;
  width: 13px; height: 13px;
}
.mat-acc--collapsible .mat-item__sign::before,
.mat-acc--collapsible .mat-item__sign::after {
  content: "";
  position: absolute; top: 50%; left: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transition: transform 0.5s var(--ease);
}
.mat-acc--collapsible .mat-item__sign::after { transform: rotate(90deg); }
.mat-acc--collapsible .mat-item.is-open .mat-item__sign::after { transform: rotate(0deg); }

.mat-acc--collapsible .mat-item__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.6s var(--ease);
}
.mat-acc--collapsible .mat-item.is-open .mat-item__panel { grid-template-rows: 1fr; }
.mat-acc--collapsible .mat-item__panel > div { overflow: hidden; }
.mat-acc--collapsible .mat-item__panel .feature__body { padding-top: 0.85rem; overflow-wrap: break-word; }

@media print {
  .mat-item__panel { grid-template-rows: 1fr !important; }
}

/* ==========================================================================
   46. Footer — Services/Maisons as mobile accordions (11 Sep pass)
   Same technique as §44 (mobile-only, matchMedia-gated) applied to the
   Services and Maisons link lists, which were the two the client flagged as
   making the footer "scroll for ages" on mobile. FRSHR and Customers Care
   stay plain, always-expanded lists — left alone at the client's request.
   Desktop/tablet keep the current four/two-column footer__grid exactly as
   built: .footer-acc__head/__panel is display:contents without
   .footer__grid--collapsible, so the heading, then its list, sit in the
   same plain flow as the original unwrapped markup.

   footerAccordion() (main.js) adds .footer__grid--collapsible only once it
   confirms (via matchMedia) the viewport is at or below 620px — the same
   width .footer__grid already collapses to one column at (§ Footer
   additions, above). Services and Maisons open/close independently.
   ========================================================================== */
.footer-acc__head { display: contents; }
.footer-acc__sign { display: none; }
.footer-acc__panel { display: contents; }

.footer__grid--collapsible .footer-acc h2 { margin-bottom: 0; }

.footer__grid--collapsible .footer-acc__head {
  display: flex;
  align-items: center;
  gap: 1rem;
  width: 100%;
  text-align: start;
  cursor: pointer;
  padding-block: 0.4rem;
  transition: color 0.4s var(--ease);
}
.footer__grid--collapsible .footer-acc__head:hover,
.footer__grid--collapsible .footer-acc__head:focus-visible { color: var(--fg); }

.footer__grid--collapsible .footer-acc__q { flex: 1 1 auto; }

.footer__grid--collapsible .footer-acc__sign {
  display: block;
  flex: 0 0 auto;
  position: relative;
  width: 13px; height: 13px;
}
.footer__grid--collapsible .footer-acc__sign::before,
.footer__grid--collapsible .footer-acc__sign::after {
  content: "";
  position: absolute; top: 50%; left: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transition: transform 0.5s var(--ease);
}
.footer__grid--collapsible .footer-acc__sign::after { transform: rotate(90deg); }
.footer__grid--collapsible .footer-acc.is-open .footer-acc__sign::after { transform: rotate(0deg); }

.footer__grid--collapsible .footer-acc__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.6s var(--ease);
}
.footer__grid--collapsible .footer-acc.is-open .footer-acc__panel { grid-template-rows: 1fr; }
.footer__grid--collapsible .footer-acc__panel > div { overflow: hidden; }
.footer__grid--collapsible .footer-acc__panel .footer__links { padding-top: 0.6rem; }

@media print {
  .footer-acc__panel { grid-template-rows: 1fr !important; }
}

.footer__sitemap {
  margin-inline-start: 0.75em;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 0.35s var(--ease);
}
.footer__sitemap:hover { color: var(--fg); }

/* ==========================================================================
   47. 14 Sep pass — iOS 26 floating URL bar, homepage hero
   ========================================================================== */

/* iOS 26 floats a translucent URL bar over the bottom of the screen and paints
   page content behind it. Measured on iPhone 17 Pro / iOS 26.2:

     screen.height 874   page paints 59 -> 874 (815 visible)
     100lvh        754   100svh / 100dvh 714   safe-area insets 0

   So the largest viewport unit stops 61px above the bottom of the screen, and
   at scroll top the section after the hero shows through the bar as a bright
   strip. Nothing exposes that 61px: env(safe-area-inset-bottom) is 0 in Safari
   outside standalone mode, with or without viewport-fit=cover, and lvh is
   already the tallest unit. §36 moved this hero from dvh to lvh, which closed
   most of the gap; this closes the rest.

   The hero is therefore deliberately overshot past the largest viewport. The
   overshoot costs a little scroll before the next section and cannot leave a
   strip, where a value measured from the bar would have to be exact. Scoped to
   WebKit on iOS with the same -webkit-touch-callout query used in §27, so
   desktop, Android and iPadOS keep a hero of exactly 100lvh. */
@supports (-webkit-touch-callout: none) {
  @media (max-width: 860px) {
    .hero--bare { min-height: calc(100lvh + 5rem); }

    /* The load curtain needs the same overshoot. It is position: fixed with
       inset: 0, which on iOS resolves to the SMALL viewport (714px measured),
       so it stopped at the same 773px line and left an ink panel across the
       strip behind the URL bar after it had visually slid away: the curtain
       is what Safari had cached for a region it repaints late. Matching the
       hero's height lets it cover that strip and clear it completely on the
       way out. bottom: auto releases the height from inset: 0.

       Side benefit: the FRSHR mark is centred in the same box as the hero's
       headline, so the two line up through the transition instead of the
       mark sitting ~60px high. */
    .curtain {
      bottom: auto;
      height: calc(100lvh + 5rem);
    }
  }
}

/* ==========================================================================
   48. 14 Sep pass — status bar tint on hero pages
   ========================================================================== */

/* iOS fills the area behind the status bar with the CANVAS background, which
   body propagates. body is --paper, so on a page opening with a dark hero the
   bar read as a cream strip with black icons sitting above the video, and it
   flipped from the curtain's ink to cream as the curtain lifted.

   theme-color does not drive this: it is already #14120D and had no effect,
   measured. Nor can a gradient: outside the body's box a background IMAGE is
   not painted at all, only background-color is, so a two-stop gradient leaves
   the bar at the default white. It has to be a solid colour.

   iOS picks the icon colour from that background's luminance on its own, so
   ink gives white icons with no further work.

   Scoped to .has-hero, which is exactly the pages that open on a dark hero:
   home, 404, the 6 service and 7 maison pages, about and careers. Privacy,
   cart, contact and the rest keep the cream bar, which is right for them.

   TRADE-OFF, deliberate: the canvas is ONE colour, so this also makes the
   bottom rubber-band ink on these pages, under a --paper footer. There is no
   way to colour the two overscroll edges separately. */
body.has-hero { background: var(--ink); }
