/* ============================================================================
   Sarit Glickman · BodyTalk — "Consulting Room Editorial"
   Hand-written, zero dependencies.
   The defensive spine (redesign/references/defensive-spine.md §1–§24) is baked
   into the base layer below — do not remove without reading that file.
   ========================================================================== */

/* ---------- Fonts (self-hosted variable, build-standards §8) -------------- */
/* Heading face changed 2026-08-11: Bodoni Moda -> Fraunces.
   Sarit: "the heading font throughout the site is disappearing." Measured, not
   taste: Bodoni Moda's optical-size axis runs 6-96, and on a didone a HIGHER
   optical size is a DISPLAY cut with THINNER hairlines. The rules below used to
   pin that axis to 96/72/40 while .d3 renders as small as 17.6px, so the
   hairline of an "o" was 8/2000 em = 0.07 CSS px, roughly 7% ink coverage of a
   single pixel at 1x. The stroke was physically below the display's resolution.
   🔑 THE PINS WERE THE BUG, NOT THE FACE. Swapping the family and leaving them
   in place would have kept most of the defect, so every pin below is deleted and
   font-optical-sizing:auto (the default) is allowed to track the rendered size.
   Fraunces carries its own axis, 9 to 144, and is 13.4 KB SMALLER than the
   Bodoni it replaces. Evidence + specimen: _font-lab/RECOMMENDATION.md. */
@font-face{
  font-family:'Fraunces';
  src:url('/fonts/fraunces-latin.woff2') format('woff2-variations');
  font-weight:400 700; font-stretch:normal; font-style:normal; font-display:swap;
}
/* A REAL italic. Bodoni shipped none, so .quote__t, .tried li:last-child,
   .thesis .d2 em and .d-it were all FAUX obliques: the browser mechanically
   shearing the roman, which on a didone throws the hairlines further off-axis.
   Four rules stop lying the moment this file exists. */
@font-face{
  font-family:'Fraunces';
  src:url('/fonts/fraunces-latin-italic.woff2') format('woff2-variations');
  font-weight:400 700; font-stretch:normal; font-style:italic; font-display:swap;
}
@font-face{
  font-family:'Archivo';
  src:url('/fonts/archivo-latin.woff2') format('woff2-variations');
  font-weight:100 900; font-stretch:62% 125%; font-style:normal; font-display:swap;
}

/* ---------- Tokens -------------------------------------------------------- */
:root{
  /* Brand — measured off Sarit's own social tiles, not invented */
  --rose:#C48A96;          /* decorative fills + LARGE display only          */
  --rose-text:#8E4A5A;     /* SPINE §16 — AA-safe: 5.02:1 on FLAT bone, white-on-it 6.41:1
                              ⚠ 5.02 is the ratio on the bone SWATCH. Over the
                              translucent banner panel the real backdrop is the
                              photo showing through, and this drops to 4.14:1 —
                              measured, not calculated. See .pbanner__panel. */
  --rose-deep:#7E4050;     /* hover / pressed · 4.96:1 on the worst panel backdrop */
  --rose-deeper:#6E3444;   /* hover for small rose text ON the banner panel   */
  --marker:#D6B6B9;        /* her highlight-marker device                    */
  --bone:#E8E3DD;          /* warm oatmeal canvas                            */
  --bone-dim:#DED8D1;
  --sage:#B4B9A5;          /* decorative only — 1.58:1, never text           */
  --gold:#C6A866;          /* hairline rules only — 1.79:1, never text       */
  --ink:#241F1D;           /* 12.77:1 on bone (AAA)                          */
  --ink-soft:#4F4744;      /* secondary text — passes AA on bone             */
  --paper:#FFFFFF;         /* pure white cards (build-standards crisp recipe) */

  --wrap:1180px;
  --gut:clamp(20px,5vw,64px);
  --sp-1:4px; --sp-2:8px; --sp-3:16px; --sp-4:24px; --sp-5:32px;
  --sp-6:48px; --sp-7:72px; --sp-8:104px; --sp-9:140px;

  --serif:'Fraunces',Georgia,'Times New Roman',serif;
  --sans:'Archivo',-apple-system,'Segoe UI',Helvetica,sans-serif;

  --r-sm:4px; --r-md:10px; --r-lg:20px;
  --shadow-1:0 1px 2px rgba(36,31,29,.05), 0 6px 18px -8px rgba(36,31,29,.14);
  --shadow-2:0 2px 6px rgba(36,31,29,.07), 0 24px 48px -20px rgba(36,31,29,.22);
  --ease:cubic-bezier(.22,.61,.36,1);

  /* z-index scale */
  --z-head:200; --z-drawer:400; --z-scrim:380; --z-modal:600; --z-toast:800;
}

/* ---------- Reset / base -------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
/* The header is position:sticky, so anything scrolled to y=0 sits UNDERNEATH it
   and stops taking clicks. Measured at 800x600: a calendar day landed at y=8 and
   the hit target was .hdr__in, not the button. Header measures 61-72px; 120px
   keeps every
   programmatic scroll — in-page anchors, skip link, scrollIntoView — clear of it. */
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:120px}
/* scroll-padding-top above covers the browser's own scrolling (anchors, focus).
   It does NOT cover a programmatic scrollIntoView, which can leave an element
   under the sticky header — where a tap lands on the NAV instead of the target.
   scroll-margin-top belongs to the element and is honoured by both, so the
   booking controls carry it explicitly. */
.slot,.cal__d,.sess__opt,[data-next]{scroll-margin-top:120px}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{
  margin:0;background:var(--bone);color:var(--ink);
  font-family:var(--sans);font-size:17px;line-height:1.65;
  font-variation-settings:'wght' 400,'wdth' 100;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-wrap:break-word;
}
/* SPINE §14 — never html,body{overflow-x:hidden}: it kills every sticky header
   and hides real overflow from QC. Clip at the offending element instead. */

img,svg,video{display:block;max-width:100%}
/* SPINE §11 — contained media needs the FULL sizing set or it overflows its box */
.media img,.media video,.fit img{
  max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;
}
.cover img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}

/* SPINE §1 — every inline SVG is born small even if a component forgets a size */
svg{width:1.1em;height:1.1em;flex:none;vertical-align:-.15em}
.btn svg,.icon-btn svg{width:18px;height:18px}
.drawer svg,.chat svg,.sp-top svg{width:20px;height:20px}

a{color:var(--rose-text);text-underline-offset:.22em;text-decoration-thickness:1px}
a:hover{color:var(--rose-deep)}
button,input,select,textarea{font:inherit;color:inherit}
:focus-visible{outline:2px solid var(--rose-text);outline-offset:3px;border-radius:2px}
::selection{background:var(--marker);color:var(--ink)}

/* SPINE §14 — grid/flex children must be allowed to shrink */
.grid>*,.row>*,.card>*,.split>*{min-width:0}

/* ---------- Layout -------------------------------------------------------- */
.wrap{width:min(var(--wrap),100% - var(--gut)*2);margin-inline:auto}
.wrap-wide{width:min(1420px,100% - var(--gut)*2);margin-inline:auto}
.sec{padding-block:var(--sp-8)}
.sec-sm{padding-block:var(--sp-7)}
@media(max-width:700px){.sec{padding-block:var(--sp-7)}.sec-sm{padding-block:var(--sp-6)}}

/* SPINE §18 — any rule declaring grid tracks declares display:grid too */
.grid{display:grid;gap:var(--sp-5)}
.g-2{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--sp-5)}
.g-3{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-5)}
.split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(32px,6vw,88px);align-items:center}
.split-60{display:grid;grid-template-columns:1.35fr 1fr;gap:clamp(32px,6vw,80px);align-items:center}
.split-40{display:grid;grid-template-columns:1fr 1.35fr;gap:clamp(32px,6vw,80px);align-items:center}
@media(max-width:900px){
  .g-3{grid-template-columns:repeat(2,1fr)}
  .split,.split-60,.split-40{grid-template-columns:1fr;gap:var(--sp-6)}
}
@media(max-width:620px){.g-2,.g-3{grid-template-columns:1fr}}

/* ---------- Typography ---------------------------------------------------- */
.d1,.d2,.d3,h1,h2,h3{
  font-family:var(--serif);font-weight:500;line-height:1.04;
  letter-spacing:-.012em;margin:0;text-wrap:balance;
}
.d1{font-size:clamp(2.7rem,6.4vw,5.1rem);font-variation-settings:'wght' 500}
.d2{font-size:clamp(2.1rem,4.4vw,3.5rem);font-variation-settings:'wght' 500}
.d3{font-size:clamp(1.5rem,2.6vw,2.15rem);line-height:1.16;font-variation-settings:'wght' 500}
.d-it{font-style:italic}

/* Punch — the bold condensed grotesque from her tiles */
.punch{
  font-family:var(--sans);font-variation-settings:'wght' 800,'wdth' 68;
  text-transform:uppercase;letter-spacing:.02em;line-height:1.02;
  font-size:clamp(2rem,4.6vw,3.6rem);
}
.kicker{
  font-family:var(--sans);font-variation-settings:'wght' 600,'wdth' 92;
  text-transform:uppercase;letter-spacing:.17em;font-size:.72rem;
  color:var(--rose-text);margin:0 0 var(--sp-3);
}
.lede{font-size:clamp(1.06rem,1.5vw,1.28rem);line-height:1.6;color:var(--ink-soft);max-width:54ch}
.small{font-size:.86rem;color:var(--ink-soft)}
.tiny{font-size:.76rem;color:var(--ink-soft)}
p{margin:0 0 1.05em;max-width:68ch}
p:last-child{margin-bottom:0}

/* Gold hairline rule — decorative only, never carries meaning */
.rule{height:0;border:0;border-top:1.5px solid var(--gold);width:64px;margin:var(--sp-4) 0;opacity:.9}
.rule-c{margin-inline:auto}

/* ===== THE SIGNATURE: Sarit's marker swipe ================================ */
/* THE SWIPE IS A BACKGROUND ON THE INLINE BOX ITSELF, NOT AN ABSOLUTE PSEUDO.
   ---------------------------------------------------------------------------
   It used to be a position:absolute ::before spanning the whole inline element.
   One absolute rectangle cannot follow text onto a second line, so it needed
   white-space:nowrap to stay coherent — and THAT is what broke the layout:
   measured 2026-08-04 at every width >= 1280, the unbreakable phrase ran past
   its panel's painted edge onto the photograph behind it. index +39px,
   stories +63px, book +73px, constant at 1280/1440/1920/2560 because both the
   panel max-width and the 81.6px display size are fixed above 1280. Clean at
   390/820/1024 only because the type is smaller there.
   Fixing it by shrinking the display type would have cost ~17% off the hero on
   all 10 pages to correct 3, so the phrase is allowed to WRAP instead and the
   swipe wraps with it: box-decoration-break:clone gives every line fragment its
   own bleed, radii and reveal. This is also why it now survives Sarit rewriting
   the copy — nowrap silently re-breaks the moment a marked phrase gets longer.
   ⛔ Do not reintroduce white-space:nowrap here.

   GEOMETRY IS MATCHED TO THE OLD PSEUDO, NOT GUESSED — measured at 1440/81.6px:
   bar top .30em, bottom .11em (92px tall), side bleed .08em, same uneven radii.
   The only deliberate loss is the old rotate(-.7deg) tilt: a background box
   cannot be rotated independently of its text. A per-line swipe reads more like
   real highlighter than one tilted bar spanning a wrapped phrase.

   🔑 The old z-index:-1 hazard is GONE BY CONSTRUCTION. A pseudo at z-index:-1
   paints in the ROOT stacking context unless the parent makes its own, so on
   .band-ink the marked word used to vanish entirely and isolation:isolate was
   load-bearing. An element's own background always paints behind its own text,
   in its own box — so there is no negative z-index and nothing to isolate. */
.mk{
  display:inline;
  -webkit-box-decoration-break:clone; box-decoration-break:clone;
  padding-inline:.08em; margin-inline:-.08em;   /* bleed, without moving the glyphs */
  background-image:linear-gradient(var(--marker),var(--marker));
  background-repeat:no-repeat;
  /* THE BAR MUST BE SHORTER THAN THE LINE BOX. The old pseudo was 1.12em tall
     against a 1.04em line-height — fine when nowrap guaranteed one line, but once
     the phrase can wrap, two bars that each overflow the line box merge into a
     single pink slab with a step in it. Sized to leave a visible gap so a wrapped
     phrase reads as two marker strokes. Measured at 1440/81.6px: bar 68px, line
     box 84.9px, gap ~17px. */
  background-position:0 .38em;
  background-size:var(--mk-x,100%) calc(100% - .70em);
  /* uneven, shallow radii = a swipe of marker, not a rounded pill */
  border-radius:.18em .06em .12em .04em/.10em .16em .06em .14em;
  transition:background-size .68s var(--ease);
}
.reveal .mk{--mk-x:0%}
.reveal.in .mk{--mk-x:100%}
@media(prefers-reduced-motion:reduce){
  .mk{transition:none}
  .reveal .mk{--mk-x:100%}
}

/* ---------- Buttons ------------------------------------------------------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.55em;
  font-family:var(--sans);font-variation-settings:'wght' 600,'wdth' 100;
  font-size:.95rem;letter-spacing:.01em;
  padding:15px 30px;min-height:48px;border:1.5px solid transparent;border-radius:var(--r-sm);
  cursor:pointer;text-decoration:none;text-align:center;
  transition:background .2s var(--ease),color .2s var(--ease),border-color .2s var(--ease),transform .12s var(--ease);
}
.btn:active{transform:translateY(1px)}
.btn-primary{background:var(--rose-text);color:#fff;border-color:var(--rose-text)}
.btn-primary:hover{background:var(--rose-deep);border-color:var(--rose-deep);color:#fff}
.btn-ghost{background:transparent;color:var(--ink);border-color:rgba(36,31,29,.32)}
.btn-ghost:hover{border-color:var(--ink);background:rgba(36,31,29,.04);color:var(--ink)}
/* SPINE §16b — dark-surface variants so shared buttons never go invisible */
.on-dark .btn-ghost{color:#fff;border-color:rgba(255,255,255,.45)}
.on-dark .btn-ghost:hover{background:rgba(255,255,255,.12);border-color:#fff;color:#fff}
.btn[disabled],.btn[aria-disabled=true]{opacity:.45;cursor:not-allowed;pointer-events:none}
/* SPINE §12 — a stretch child with margin must be width:auto, never 100% */
.btn-block{display:flex;width:auto}

/* ---------- Cards / surfaces ---------------------------------------------- */
.card{background:var(--paper);border-radius:var(--r-md);padding:var(--sp-5);box-shadow:var(--shadow-1)}
.panel{background:var(--paper);border-radius:var(--r-lg);box-shadow:var(--shadow-2)}
.band-bone{background:var(--bone)}
.band-paper{background:var(--paper)}
.band-rose{background:var(--rose);color:#fff}
.band-ink{background:var(--ink);color:#fff}
.band-rose .lede,.band-ink .lede,.band-rose .small,.band-ink .small{color:rgba(255,255,255,.86)}
.band-rose .kicker,.band-ink .kicker{color:rgba(255,255,255,.8)}
.band-rose .rule,.band-ink .rule{border-top-color:rgba(255,255,255,.5)}

/* ---------- Header (build-standards §6 three-zone) ------------------------- */
/* SPINE §4 — the JS mount wrapper must be display:contents or sticky dies */
#hdr-mount{display:contents}
.hdr{
  position:sticky;top:0;z-index:var(--z-head);
  background:rgba(232,227,221,.92);backdrop-filter:saturate(140%) blur(10px);
  border-bottom:1px solid rgba(36,31,29,.09);
  transition:padding .22s var(--ease),background .22s var(--ease);
}
.hdr__in{display:flex;align-items:center;gap:var(--sp-4);padding:14px 0;
  width:min(var(--wrap),100% - var(--gut)*2);margin-inline:auto}
.hdr.scrolled .hdr__in{padding:8px 0}
.hdr__logo{display:flex;align-items:center;flex:none;margin-right:auto}
.hdr__logo img{height:38px;width:auto;transition:height .22s var(--ease)}
.hdr.scrolled .hdr__logo img{height:30px}
.nav{display:flex;align-items:center;gap:clamp(12px,1.7vw,26px);flex-wrap:nowrap}
.nav a{
  font-size:.88rem;font-variation-settings:'wght' 500;color:var(--ink);
  text-decoration:none;white-space:nowrap;padding:6px 0;position:relative;
}
.nav a::after{content:"";position:absolute;left:0;right:100%;bottom:0;height:1.5px;
  background:var(--rose-text);transition:right .26s var(--ease)}
.nav a:hover::after,.nav a[aria-current=page]::after{right:0}
.nav a[aria-current=page]{font-variation-settings:'wght' 700}
.hdr__actions{display:flex;align-items:center;gap:var(--sp-2);flex:none}
.icon-btn{
  display:grid;place-items:center;width:44px;height:44px;flex:none;
  background:transparent;border:0;border-radius:var(--r-sm);cursor:pointer;color:var(--ink);
}
.icon-btn:hover{background:rgba(36,31,29,.07)}

/* SPINE §5 — visibility utilities are DOUBLED so they beat any bare component
   class declared later in the cascade (the Sorbet miss). Never !important. */
.hide-mob.hide-mob{}
.only-mob.only-mob{display:none}
@media(max-width:980px){
  .hide-mob.hide-mob{display:none}
  .only-mob.only-mob{display:revert}
  .icon-btn.only-mob.only-mob{display:grid}
  .btn.only-mob.only-mob{display:inline-flex}
}

/* Mobile nav drawer */
.scrim{position:fixed;inset:0;background:rgba(36,31,29,.55);opacity:0;visibility:hidden;
  transition:opacity .28s var(--ease),visibility .28s;z-index:var(--z-scrim)}
.scrim.open{opacity:1;visibility:visible}
.drawer{
  position:fixed;top:0;right:0;height:100dvh;width:min(400px,86vw);
  background:var(--paper);z-index:var(--z-drawer);
  transform:translateX(101%);transition:transform .34s var(--ease);
  display:flex;flex-direction:column;overflow-y:auto;overscroll-behavior:contain;
}
.drawer.open{transform:translateX(0)}
.drawer__top{display:flex;align-items:center;justify-content:space-between;
  padding:var(--sp-4);border-bottom:1px solid rgba(36,31,29,.1)}
.drawer__nav{display:flex;flex-direction:column;padding:var(--sp-3) var(--sp-4)}
.drawer__nav a{
  /* 'wght' restated: body's inherited font-variation-settings:'wght' 400 beats
     font-weight, so a serif element that stays silent renders LIGHTER than the
     rule next to it claims. Same fix on .tried li and .quote__t. */
  font-family:var(--serif);font-variation-settings:'wght' 500;
  font-size:1.4rem;color:var(--ink);text-decoration:none;
  padding:13px 0;border-bottom:1px solid rgba(36,31,29,.08);
}
.drawer__nav a:hover{color:var(--rose-text)}
.drawer__foot{margin-top:auto;padding:var(--sp-4);display:grid;gap:var(--sp-2)}

/* Skip link */
.skip{position:absolute;left:-9999px;top:0;z-index:calc(var(--z-toast) + 1);
  background:var(--ink);color:#fff;padding:12px 20px;border-radius:0 0 var(--r-sm) 0}
.skip:focus{left:0}

/* ---------- Hero (SPINE §7 — sized band, media absolutely positioned) ------ */
.hero{position:relative;overflow:hidden;background:var(--bone)}
.hero__band{position:relative;min-height:clamp(560px,74vh,760px);display:flex;align-items:center}
.hero__bg{position:absolute;inset:0;overflow:hidden}
.hero__bg img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 42%}
/* Directional veil, not a flat scrim (build-standards §7) */
.hero__veil{position:absolute;inset:0;
  background:linear-gradient(96deg,rgba(232,227,221,.97) 0%,rgba(232,227,221,.93) 38%,rgba(232,227,221,.55) 62%,rgba(232,227,221,.18) 100%)}
.hero__in{position:relative;z-index:2;width:min(var(--wrap),100% - var(--gut)*2);margin-inline:auto;padding-block:var(--sp-7)}
.hero__copy{max-width:37rem}
.hero__cta{display:flex;flex-wrap:wrap;gap:var(--sp-3);margin-top:var(--sp-6)}
.hero__note{margin-top:var(--sp-4);font-size:.82rem;color:var(--ink-soft)}
@media(max-width:820px){
  .hero__band{min-height:0;padding-block:var(--sp-6)}
  .hero__veil{background:linear-gradient(180deg,rgba(232,227,221,.95) 0%,rgba(232,227,221,.88) 60%,rgba(232,227,221,.94) 100%)}
}

/* ---------- Page banner (SPINE §7) — every page opens on an image ---------
   Legibility is carried by a LOCAL backing panel, never by drowning the
   photograph in a full-width scrim. The old hero veil sat at 97% opacity on
   the copy side, which made the image effectively invisible — you paid the
   bytes for a picture nobody could see. Here the wash only unifies tone; the
   panel does the contrast work, so the photograph survives at full strength.
   The panel reads as a caption card laid on a print: bone, gold hairline,
   soft lift. That holds over a dark frame AND over the near-white pricing
   frame, which a translucent scrim would not.
   ⚠ Contrast here must be MEASURED on rendered pixels (qc/banner-contrast.mjs),
   never calculated hex-vs-hex — the copy sits over photography. */
.pbanner{position:relative;overflow:hidden;background:var(--bone)}
/* The band's height used to be a clamp() while its width was the viewport, so
   its ASPECT grew with the screen: 1.94 at 1440 up to 4.22 at 2560. Every band
   image is 21:9, so object-fit:cover threw away a DIFFERENT amount of the
   artwork at every width - measured by qc/slot-geometry.mjs at 42%..77% kept,
   worst at the wide end where there is most room to show it. Tying the height
   to the WIDTH makes the crop deterministic instead.
   ⚠ Do NOT do this with `aspect-ratio` + `max-height`: that pair makes the box
   satisfy the ratio by SHRINKING ITS WIDTH, so the full-bleed band silently
   became a centred 1680px box at 2560. Measured, then replaced with a
   min-height, which width can never be traded against. 900px is the cap, and
   qc/plate-to-banner.py keeps the artwork inside that same 900px safe band. */
.pbanner__band{position:relative;
  min-height:clamp(300px,calc(100vw / 2.3333),900px);
  display:flex;align-items:center}
.pbanner--hero .pbanner__band{min-height:clamp(560px,74vh,760px)}
.pbanner__bg{position:absolute;inset:0;overflow:hidden}
.pbanner__bg img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:var(--pb-pos,center 45%)}
/* The Recognition plate is a THREE-PANEL triptych at 4.76:1 - distress, easing,
   open. Any horizontal crop amputates a panel and the sequence stops meaning
   anything, so this one band contains instead of covering. It sits on a ground
   sampled from the plate's own edge wash, so the letterbox reads as paper. */
.pbanner--contain{background:var(--pb-ground,var(--bone))}
.pbanner--contain .pbanner__bg img{object-fit:contain;object-position:center}
/* Tone unifier only — deliberately light. Not load-bearing for contrast. */
.pbanner__wash{position:absolute;inset:0;
  background:linear-gradient(96deg,rgba(232,227,221,.55) 0%,rgba(232,227,221,.30) 42%,
    rgba(232,227,221,.06) 70%,rgba(232,227,221,0) 100%)}
.pbanner__in{position:relative;z-index:2;
  width:min(var(--wrap),100% - var(--gut)*2);margin-inline:auto;
  padding-block:var(--sp-6)}
.pbanner__panel{max-width:35rem;background:rgba(232,227,221,.94);
  border-top:2px solid var(--gold);padding:var(--sp-5) var(--sp-5) var(--sp-5);
  box-shadow:var(--shadow-2)}
@supports (backdrop-filter:blur(3px)){
  .pbanner__panel{background:rgba(232,227,221,.88);backdrop-filter:blur(3px)}
}
.pbanner--hero .pbanner__panel{max-width:38rem;padding:var(--sp-6)}
/* Small rose text ON the panel steps one tone deeper. The panel is translucent
   bone over a PHOTOGRAPH, so --rose-text — which is genuinely AA-safe on the
   flat bone canvas — measures 4.14:1 here on the darkest frames. That is the
   whole reason this component's contrast is gated on rendered pixels.
   Buttons deliberately keep --rose-text: their fill is opaque, so they never had
   the problem, and two different maroons on one page would read as a mistake.
   Numbers verified by qc/banner-contrast.mjs, not by hex arithmetic. */
.pbanner__panel .kicker,
.pbanner__panel a:not(.btn){color:var(--rose-deep)}
.pbanner__panel a:not(.btn):hover{color:var(--rose-deeper)}
.pbanner__cta{display:flex;flex-wrap:wrap;gap:var(--sp-3);margin-top:var(--sp-5)}
.pbanner__note{margin-top:var(--sp-4);font-size:.82rem;color:var(--ink-soft)}
@media(max-width:820px){
  .pbanner__band{min-height:0;padding-block:var(--sp-5)}
  .pbanner--hero .pbanner__band{min-height:0}
  .pbanner__panel{max-width:none;padding:var(--sp-4)}
  .pbanner--hero .pbanner__panel{padding:var(--sp-5)}
  /* On a narrow screen the panel covers most of the frame anyway, so lift the
     wash to keep the exposed strip from fighting the panel edge. */
  .pbanner__wash{background:linear-gradient(180deg,rgba(232,227,221,.42) 0%,
    rgba(232,227,221,.18) 55%,rgba(232,227,221,.46) 100%)}
}

/* ---------- Mid-page composition — SPINE §7 applied BELOW the fold --------
   Allen, 2026-08-01: the page banners were fixed but the sections under them
   still read as "type on a beige slab". The approved band (Not only migraines)
   sets the grammar the rest now follow — kicker, display line, gold hairline,
   lede, one outlined CTA on ONE side; real image mass on the other. A text-only
   band is now the exception that has to earn itself, not the default. */

/* --- The pivot diptych.
   This section's CONTENT is a contrast ("the goal is not… / but instead…"), so
   it gets a layout that is one. Left column = the state being left behind,
   right = the state being moved toward. The argument is carried by ink weight
   and image temperature, not by an icon or a colour swatch — the structure
   encodes the meaning instead of decorating it. */
.pivot{display:grid;grid-template-columns:1fr 1fr;align-items:start}
.pivot__col{padding-right:clamp(20px,3.5vw,48px)}
.pivot__col+.pivot__col{border-left:1px solid var(--gold);
  padding-left:clamp(20px,3.5vw,48px);padding-right:0}
.pivot__fig{margin:0 0 var(--sp-5)}
.pivot__t{margin:0}
/* The state being left behind is deliberately the quieter of the two. */
.pivot--from .pivot__t{color:var(--ink-soft)}
.pivot--from .pivot__fig{filter:saturate(.82)}
.pivot--to .pivot__t{color:var(--ink)}
@media(max-width:820px){
  .pivot{grid-template-columns:1fr;gap:var(--sp-6)}
  .pivot__col{padding-right:0}
  .pivot__col+.pivot__col{border-left:0;border-top:1px solid var(--gold);
    padding-left:0;padding-top:var(--sp-6)}
}

/* --- Process step card with a real image.
   The 01/02/03 numbering stays because this genuinely IS a sequence — it is the
   order the three things happen in, which is information the reader needs. The
   numeral moves onto the image as a bone chip with a gold top rule, which is the
   same caption-card device the banners use, so the page reads as one system. */
.step{background:var(--paper);border-radius:var(--r-md);overflow:hidden;
  box-shadow:var(--shadow-1);display:flex;flex-direction:column}
.step__fig{position:relative;margin:0}
.step__n{position:absolute;left:0;bottom:0;margin:0;
  font-family:var(--serif);font-variation-settings:'wght' 500;
  font-size:1.5rem;line-height:1;color:var(--ink);background:var(--bone);
  border-top:2px solid var(--gold);padding:.42em .62em .34em}
.step__body{padding:var(--sp-5);display:flex;flex-direction:column;flex:1}

/* --- Stories: one image column, quotes stacked beside it.
   Three tall quote columns ragged out at different heights and read as a wall of
   italic. Stacking them gives every quote the same measure and lets a single
   photograph hold the left. ⛔ No portraits here, ever: these are real named
   people, and a generated face under a real name invents a person. */
.stories{display:grid;grid-template-columns:.8fr 1.2fr;
  gap:clamp(28px,4.5vw,64px);align-items:start}
/* SPINE §14. A grid item defaults to min-width:auto, so the column refuses to go
   below its content's min-content and the whole document scrolls sideways —
   measured 400.3px of column inside a 350px container at 390 wide. Every new
   grid needs this; the rule existing elsewhere in the sheet does not apply it here. */
.stories>*{min-width:0}
.stories__fig{position:sticky;top:96px}   /* header measures 61-72px */
.stories__list{display:grid;gap:var(--sp-4)}
/* Keep the quote's own column layout. Overriding it to `row` floated the name
   to the top-right and squeezed the quote to a ~360px measure inside a 590px
   card — the attribution belongs UNDER the words it belongs to, and the words
   should have the full card width. */
@media(max-width:820px){
  .stories{grid-template-columns:1fr}
  .stories__fig{position:static}
}
@media(prefers-reduced-motion:reduce){.stories__fig{position:static}}

/* --- Closing band over photography.
   ⚠ The copy here sits on an IMAGE, so its contrast is measured on rendered
   pixels by qc/banner-contrast.mjs (which covers this section, not just the
   banners) — never calculated hex-vs-hex. The scrim is load-bearing here, unlike
   the banner wash, because there is no local panel behind the type. */
/* 2026-08-11, brief v2: this band was INK — the artwork sat at opacity:.55 under
   a .72→.96 near-opaque dark scrim, so the picture was all but invisible and
   whatever it showed was dragged dark. Sarit's hard rule 01 is "pastel only,
   never dark, moody or harsh", and the new closing art carries two of the
   concepts she confirmed herself (the pink horizon, the two overlapping
   circles). Both were being thrown away by the treatment.
   Now: warm paper ground, artwork at full strength, and a LIGHT radial scrim
   that lifts the centre so ink type reads over it.
   ⚠ Type here is over artwork — contrast is measured on rendered pixels by
   qc/contrast.mjs, never calculated hex-vs-hex. */
.closing{position:relative;overflow:hidden;background:var(--bone)}
.closing__bg{position:absolute;inset:0}
.closing__bg img{width:100%;height:100%;object-fit:cover;opacity:1}
.closing__scrim{position:absolute;inset:0;
  background:radial-gradient(120% 90% at 50% 45%,rgba(248,245,240,.86) 0%,
    rgba(248,245,240,.72) 55%,rgba(248,245,240,.52) 100%)}
.closing__in{position:relative;z-index:2}

/* --- Thesis band — a page's one full-bleed statement.
   Deliberately NOT .closing, though both are type over a photograph. A closing
   band is a CTA moment: nothing in the picture has to survive, so it can afford
   a heavy radial scrim. A thesis band is the opposite — the photograph is
   carrying half the argument, so legibility comes from a DIRECTIONAL wash under
   the copy side only and the far side of the frame stays a photograph you can
   actually see. Same lesson as .pbanner's local panel, and the opposite of the
   .hero__veil at 97% that had us paying for a picture nobody could look at.

   🔴 The section carries `band-ink on-dark` too, so every colour here comes from
   the existing on-dark rules — kicker, lede and hairline are NOT restated. An
   override list is what drifts; the semantic class is what holds.

   🔴 z-index is load-bearing, not decoration. .thesis__bg is absolutely
   positioned, so with no stacking context it would paint OVER static content
   below it (spine §29). isolation:isolate + an explicit z-index on the content
   is what stops that; do not drop either. */
.thesis{position:relative;overflow:hidden;isolation:isolate;
  display:grid;align-items:center;min-height:clamp(400px,54vh,620px)}
.thesis__bg{position:absolute;inset:0;z-index:0}
.thesis__bg img{width:100%;height:100%;object-fit:cover}
/* 🔴 The stops are DERIVED FROM THE COPY MEASURE, not chosen by eye.
   .thesis__in is 46rem (736px) and starts at the .wrap inset, so at 1440 the
   text ends at x=866 — 60% across. The previous stops began falling at 34% and
   were down to .64 alpha by 60%, i.e. the wash thinned INSIDE the column it
   exists to protect. The italic pivot word lands at the end of line 1, exactly
   in that thin zone: measured 3.74:1 against a bright plaster hotspot, while
   its twin "why" on the dark left measured 8.07:1. Two words that are a matched
   rhetorical pair must not render at different strengths.
   Plateau now holds to 55% and the knee sits at 72% — PAST the text — so the
   falloff happens in the empty right margin. The far edge is .30 (was .34), so
   the photograph is MORE visible, not less: protect where the type is, reveal
   where it isn't. ⛔ Do not "fix" a thesis contrast finding by raising the
   global alpha — that rebuilds the 97% .hero__veil nobody could see through. */
.thesis__wash{position:absolute;inset:0;z-index:1;
  background:linear-gradient(100deg,
    rgba(28,23,22,.93) 0%, rgba(28,23,22,.88) 55%,
    rgba(28,23,22,.60) 72%, rgba(28,23,22,.30) 100%)}
.thesis > .wrap{position:relative;z-index:2}
.thesis__in{max-width:46rem}
.thesis .d2{text-wrap:balance}
/* The two pivot words carry the whole sentence. Rose at display size only —
   never at body size on this backdrop. */
.thesis .d2 em{font-style:italic;color:var(--marker)}
@media(max-width:760px){
  /* The copy spans the full width here, so a directional wash no longer has a
     "far side" to protect — it has to cover everything the type crosses. */
  .thesis__wash{background:linear-gradient(180deg,
    rgba(28,23,22,.86) 0%, rgba(28,23,22,.90) 45%, rgba(28,23,22,.94) 100%)}
  .thesis{min-height:0}
}

/* ---------- The struck-through "tried everything" list -------------------- */
.tried{list-style:none;margin:0;padding:0;display:grid;gap:2px}
.tried li{
  position:relative;font-family:var(--serif);font-variation-settings:'wght' 500;
  font-size:clamp(1.3rem,2.5vw,2rem);
  line-height:1.5;color:var(--ink-soft);width:fit-content;max-width:100%;
}
.tried li::after{
  content:"";position:absolute;left:-.06em;top:52%;height:2px;background:var(--rose);
  right:100%;transition:right .5s var(--ease);transition-delay:var(--d,0ms);
}
.reveal.in .tried li::after{right:-.06em}
@media(prefers-reduced-motion:reduce){.tried li::after{transition:none;right:-.06em}}
.tried li:last-child{color:var(--ink);font-style:italic}
.tried li:last-child::after{display:none}

/* ---------- Editorial numbered entries (symptoms / why) ------------------- */
.entry{display:grid;grid-template-columns:auto 1fr;gap:var(--sp-4);
  padding-block:var(--sp-5);border-top:1px solid rgba(36,31,29,.13)}
.entry:first-child{border-top:0}
.entry__n{font-family:var(--serif);font-size:1.05rem;color:var(--rose-text);
  font-variation-settings:'wght' 500;padding-top:.4em;font-variant-numeric:tabular-nums}
.entry__b h3{margin:0 0 .35em}
.entry__b p{color:var(--ink-soft);margin:0}
@media(max-width:560px){.entry{grid-template-columns:1fr;gap:var(--sp-2)}}

/* ---------- Quote / testimonial ------------------------------------------- */
.quote{background:var(--paper);border-radius:var(--r-md);padding:var(--sp-5);
  box-shadow:var(--shadow-1);display:flex;flex-direction:column;gap:var(--sp-3);height:100%}
.quote__mark{font-family:var(--serif);font-size:3rem;line-height:.6;color:var(--marker);height:.55em}
.quote__t{font-family:var(--serif);font-variation-settings:'wght' 500;
  font-size:1.08rem;line-height:1.55;font-style:italic;margin:0;flex:1}
.quote__who{font-variation-settings:'wght' 700,'wdth' 92;text-transform:uppercase;
  letter-spacing:.13em;font-size:.7rem;color:var(--ink-soft)}

/* ---------- Forms --------------------------------------------------------- */
.field{display:grid;gap:6px;margin-bottom:var(--sp-4)}
.field>label{font-size:.82rem;font-variation-settings:'wght' 600;letter-spacing:.02em}
.field .req{color:var(--rose-text)}
.field input,.field select,.field textarea{
  width:100%;padding:13px 14px;min-height:48px;background:var(--paper);
  border:1.5px solid rgba(36,31,29,.2);border-radius:var(--r-sm);
  transition:border-color .18s var(--ease),box-shadow .18s var(--ease);
}
.field textarea{min-height:120px;resize:vertical}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:none;border-color:var(--rose-text);box-shadow:0 0 0 3px rgba(142,74,90,.15)}
.field .help{font-size:.78rem;color:var(--ink-soft)}
.field .help[hidden]{display:none}   /* [hidden] loses to the rule above without this */
/* A real <button> so it is keyboard-reachable, styled as the link it reads as */
.linkish{background:none;border:0;padding:0;font:inherit;cursor:pointer;
  color:var(--rose-text);text-decoration:underline;text-underline-offset:.2em}
.linkish:hover{color:var(--rose-deep)}

/* Exit-intent slide-in — a corner card, never a full-screen interstitial, and
   never over the top of what someone is reading. Desktop only (see site.js). */
.exitn{
  position:fixed;right:clamp(16px,2.5vw,32px);bottom:clamp(16px,2.5vw,32px);
  width:min(384px,calc(100vw - 32px));z-index:var(--z-modal);
  background:var(--paper);border-radius:var(--r-lg);padding:var(--sp-5);
  box-shadow:var(--shadow-2);border-top:3px solid var(--rose-text);
  opacity:0;transform:translateY(14px);
  transition:opacity .26s var(--ease),transform .26s var(--ease);
}
.exitn.in{opacity:1;transform:none}
.exitn__x{
  position:absolute;top:10px;right:10px;width:36px;height:36px;      /* ≥ tap target */
  display:grid;place-items:center;border:0;border-radius:50%;
  background:transparent;color:var(--ink-soft);cursor:pointer;
}
.exitn__x:hover{background:var(--bone);color:var(--ink)}
.exitn .btn{padding:11px 18px;font-size:.88rem}
@media(prefers-reduced-motion:reduce){
  .exitn{transition:none;opacity:1;transform:none}
}
.field .err{font-size:.8rem;color:#A32B32;display:none}
.field.invalid input,.field.invalid select,.field.invalid textarea{border-color:#A32B32}
.field.invalid .err{display:block}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3)}
@media(max-width:560px){.field-row{grid-template-columns:1fr}}
.consent{display:flex;gap:10px;align-items:flex-start;font-size:.84rem;color:var(--ink-soft)}
.consent input{width:20px;height:20px;min-height:0;flex:none;margin-top:2px;accent-color:var(--rose-text)}

/* ---------- Booking flow -------------------------------------------------- */
.steps{display:flex;gap:var(--sp-2);margin-bottom:var(--sp-5);flex-wrap:wrap}
.steps li{display:flex;align-items:center;gap:8px;font-size:.78rem;color:var(--ink-soft);
  list-style:none;font-variation-settings:'wght' 600;letter-spacing:.06em;text-transform:uppercase}
.steps li+li::before{content:"";width:22px;height:1px;background:rgba(36,31,29,.25);display:block}
.steps li[aria-current=step]{color:var(--rose-text)}
.steps li .dot{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;
  background:rgba(36,31,29,.09);font-size:.72rem;font-variation-settings:'wght' 700}
.steps li[aria-current=step] .dot{background:var(--rose-text);color:#fff}
.steps li.done .dot{background:var(--sage);color:var(--ink)}

.cal{display:grid;grid-template-columns:repeat(7,1fr);gap:5px}
.cal__h{font-size:.68rem;text-transform:uppercase;letter-spacing:.1em;color:var(--ink-soft);
  text-align:center;padding-bottom:6px;font-variation-settings:'wght' 700}
.cal__d{
  aspect-ratio:1;min-height:44px;display:grid;place-items:center;border-radius:var(--r-sm);
  background:transparent;border:1.5px solid transparent;cursor:pointer;font-size:.92rem;
  font-variant-numeric:tabular-nums;transition:background .16s var(--ease),border-color .16s var(--ease);
}
.cal__d:hover:not(:disabled){background:rgba(196,138,150,.2)}
.cal__d[aria-pressed=true]{background:var(--rose-text);color:#fff;border-color:var(--rose-text)}
.cal__d:disabled{color:rgba(36,31,29,.26);cursor:not-allowed}
.cal__d.has{position:relative}
.cal__d.has::after{content:"";position:absolute;bottom:5px;width:4px;height:4px;border-radius:50%;background:var(--rose)}
.cal__d[aria-pressed=true].has::after{background:#fff}

/* Shown only to visitors ≥5h from SAST — explains why every slot is at night */
.tz-note{font-size:.78rem;line-height:1.55;color:var(--ink);background:rgba(196,138,150,.14);
  border-left:2px solid var(--rose-text);padding:10px 12px;border-radius:0 var(--r-sm) var(--r-sm) 0}

.slots{display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:var(--sp-2)}
.slot{padding:12px 8px;min-height:46px;border:1.5px solid rgba(36,31,29,.2);border-radius:var(--r-sm);
  background:var(--paper);cursor:pointer;font-size:.9rem;font-variant-numeric:tabular-nums;
  transition:border-color .16s var(--ease),background .16s var(--ease)}
.slot:hover{border-color:var(--rose-text)}
.slot[aria-pressed=true]{background:var(--rose-text);color:#fff;border-color:var(--rose-text)}

.sess{display:grid;gap:var(--sp-3)}
.sess__opt{display:grid;grid-template-columns:auto 1fr auto;gap:var(--sp-3);align-items:center;
  padding:var(--sp-4);background:var(--paper);border:1.5px solid rgba(36,31,29,.16);
  border-radius:var(--r-md);cursor:pointer;text-align:left;width:100%;
  transition:border-color .18s var(--ease),box-shadow .18s var(--ease)}
.sess__opt:hover{border-color:var(--rose)}
.sess__opt[aria-pressed=true]{border-color:var(--rose-text);box-shadow:0 0 0 3px rgba(142,74,90,.13)}
.sess__opt .tick{width:22px;height:22px;border-radius:50%;border:1.5px solid rgba(36,31,29,.3);
  display:grid;place-items:center;flex:none}
.sess__opt[aria-pressed=true] .tick{background:var(--rose-text);border-color:var(--rose-text);color:#fff}
@media(max-width:560px){.sess__opt{grid-template-columns:auto 1fr;gap:var(--sp-2)}}

/* ---------- Pricing / currency ------------------------------------------- */
.cur{display:inline-flex;background:rgba(36,31,29,.07);border-radius:999px;padding:3px;gap:2px}
.cur button{padding:8px 15px;min-height:38px;border:0;background:transparent;border-radius:999px;
  cursor:pointer;font-size:.82rem;font-variation-settings:'wght' 600;letter-spacing:.04em;color:var(--ink-soft)}
.cur button[aria-pressed=true]{background:var(--paper);color:var(--ink);box-shadow:var(--shadow-1)}
.price{font-family:var(--serif);font-size:clamp(2.4rem,5vw,3.6rem);line-height:1;
  font-variant-numeric:tabular-nums;font-variation-settings:'wght' 500}
.placeholder-flag{
  display:flex;gap:10px;align-items:flex-start;background:#FFF6E0;border:1.5px dashed var(--gold);
  border-radius:var(--r-sm);padding:12px 14px;font-size:.82rem;color:#5B4A1F;
}

/* ---------- Chat + search ------------------------------------------------- */
.chat{position:fixed;right:20px;bottom:20px;z-index:var(--z-modal);display:flex;flex-direction:column;align-items:flex-end;gap:10px}
.chat__fab{width:56px;height:56px;border-radius:50%;border:0;background:var(--rose-text);color:#fff;
  box-shadow:var(--shadow-2);cursor:pointer;display:grid;place-items:center}
.chat__fab:hover{background:var(--rose-deep)}
.chat__panel{
  width:min(370px,calc(100vw - 40px));max-height:min(560px,calc(100dvh - 120px));
  background:var(--paper);border-radius:var(--r-lg);box-shadow:var(--shadow-2);
  display:none;flex-direction:column;overflow:hidden;
}
.chat__panel.open{display:flex}
.chat__head{padding:14px 16px;background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:space-between;gap:10px}
.chat__body{padding:16px;overflow-y:auto;display:flex;flex-direction:column;gap:10px;flex:1;overscroll-behavior:contain}
.chat__msg{padding:10px 13px;border-radius:12px;font-size:.9rem;max-width:86%;line-height:1.5}
.chat__msg.bot{background:var(--bone);border-bottom-left-radius:3px;align-self:flex-start}
.chat__msg.me{background:var(--rose-text);color:#fff;border-bottom-right-radius:3px;align-self:flex-end}
.chat__chips{display:flex;flex-wrap:wrap;gap:6px;padding:0 16px 12px}
.chat__chips button{padding:7px 12px;min-height:36px;border:1.5px solid rgba(36,31,29,.2);background:var(--paper);
  border-radius:999px;font-size:.78rem;cursor:pointer}
.chat__chips button:hover{border-color:var(--rose-text);color:var(--rose-text)}
.chat__form{display:flex;gap:8px;padding:12px 16px;border-top:1px solid rgba(36,31,29,.1)}
.chat__form input{flex:1;min-width:0;padding:10px 12px;min-height:44px;border:1.5px solid rgba(36,31,29,.2);border-radius:var(--r-sm)}

.sp{position:fixed;inset:0;z-index:var(--z-modal);display:none;background:rgba(36,31,29,.5);
  backdrop-filter:blur(3px);padding:8vh var(--gut) var(--gut)}
.sp.open{display:block}
.sp__box{width:min(680px,100%);margin-inline:auto;background:var(--paper);border-radius:var(--r-lg);
  box-shadow:var(--shadow-2);overflow:hidden;max-height:76vh;display:flex;flex-direction:column}
.sp__top{display:flex;align-items:center;gap:10px;padding:14px 18px;border-bottom:1px solid rgba(36,31,29,.1)}
.sp__top input{flex:1;min-width:0;border:0;font-size:1.05rem;padding:8px 0}
.sp__top input:focus{outline:none}
.sp__res{overflow-y:auto;padding:8px;overscroll-behavior:contain}
.sp__r{display:block;padding:12px 14px;border-radius:var(--r-sm);text-decoration:none;color:var(--ink)}
.sp__r:hover,.sp__r:focus{background:var(--bone)}
.sp__r b{display:block;font-variation-settings:'wght' 600;margin-bottom:2px}
.sp__r span{font-size:.84rem;color:var(--ink-soft)}

/* ---------- Toast --------------------------------------------------------- */
.toast-wrap{position:fixed;left:50%;bottom:26px;transform:translateX(-50%);z-index:var(--z-toast);
  display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none}
.toast{background:var(--ink);color:#fff;padding:12px 20px;border-radius:999px;font-size:.88rem;
  box-shadow:var(--shadow-2);animation:toastIn .3s var(--ease)}
@keyframes toastIn{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}

/* ---------- Footer -------------------------------------------------------- */
.foot{background:var(--ink);color:rgba(255,255,255,.78);padding-block:var(--sp-7) var(--sp-5)}
.foot a{color:rgba(255,255,255,.78);text-decoration:none}
.foot a:hover{color:#fff;text-decoration:underline}
.foot__grid{display:grid;grid-template-columns:1.5fr 1fr 1fr;gap:var(--sp-6)}
@media(max-width:820px){.foot__grid{grid-template-columns:1fr 1fr}}
@media(max-width:520px){.foot__grid{grid-template-columns:1fr}}
.foot__logo{height:44px;width:auto;margin-bottom:var(--sp-3)}
.foot h4{font-family:var(--sans);font-variation-settings:'wght' 700,'wdth' 92;text-transform:uppercase;
  letter-spacing:.13em;font-size:.72rem;color:#fff;margin:0 0 var(--sp-3)}
.foot ul{list-style:none;margin:0;padding:0;display:grid;gap:9px;font-size:.9rem}
.foot__base{margin-top:var(--sp-6);padding-top:var(--sp-4);border-top:1px solid rgba(255,255,255,.16);
  display:flex;flex-wrap:wrap;gap:var(--sp-3);justify-content:space-between;font-size:.79rem}
.disclaimer{font-size:.79rem;color:rgba(255,255,255,.6);max-width:60ch;margin-top:var(--sp-3)}

/* ---------- Marquee (SPINE §21 — clipped at its OWN wrapper) -------------- */
.marq{overflow:hidden;position:relative;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent)}
.marq__t{display:flex;gap:var(--sp-6);width:max-content;animation:marq 42s linear infinite}
.marq:hover .marq__t{animation-play-state:paused}
@keyframes marq{to{transform:translateX(-50%)}}
@media(prefers-reduced-motion:reduce){.marq__t{animation:none;flex-wrap:wrap;width:auto;justify-content:center}}

/* ---------- Reveal (SPINE §15 — backstop lives in JS) --------------------- */
.reveal{opacity:0;transform:translateY(16px);transition:opacity .62s var(--ease),transform .62s var(--ease)}
.reveal.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){
  /* scoped to no-preference so a later equal-specificity rule can't beat the cancel */
  .reveal{opacity:1;transform:none;transition:none}
}

/* ---------- SPINE §20 — nothing may be hover-only on touch ---------------- */
@media(hover:none){
  .card .hover-only,.quote .hover-only{opacity:1}
}

/* ---------- Utilities ----------------------------------------------------- */
.center{text-align:center}
.mt-0{margin-top:0}.mt-3{margin-top:var(--sp-3)}.mt-4{margin-top:var(--sp-4)}
.mt-5{margin-top:var(--sp-5)}.mt-6{margin-top:var(--sp-6)}
.mb-4{margin-bottom:var(--sp-4)}.mb-5{margin-bottom:var(--sp-5)}.mb-6{margin-bottom:var(--sp-6)}
.stack{display:grid;gap:var(--sp-4)}
.flow>*+*{margin-top:var(--sp-4)}
.frame{position:relative;border-radius:var(--r-md);overflow:hidden;background:var(--bone-dim)}
.frame img{width:100%;height:100%;object-fit:cover;display:block}
/* Portrait: anchor on the face so any cover-crop is taken off the bottom,
   never off the top of her head. */
.frame--portrait{background:var(--bone)}
.frame--portrait img{object-position:center 22%}
.ratio-4x5{aspect-ratio:4/5}
.ratio-3x2{aspect-ratio:3/2}
.ratio-1x1{aspect-ratio:1/1}
.offset-up{margin-top:calc(var(--sp-7) * -1)}
@media(max-width:900px){.offset-up{margin-top:0}}
.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---------- Booking receipt ------------------------------------------------
   The old confirmation led with a sage tick in a circle. Two reasons it is
   gone: it is the answer every booking screen gives, and on this build it is
   the exact visual that told a visitor they were booked when nothing had been
   recorded. The proof now carries the weight instead — a reference the server
   only issues after it has read the record back, and the time it went down.

   Set like the appointment card a practitioner hands you on the way out:
   The heading face at display size between two gold hairlines, nothing else.
   Tabular figures so the code cannot shuffle its own width, and enough tracking
   that it can be read aloud over a phone without a repeat. */
.receipt{
  background:var(--paper);border-radius:var(--r-md);box-shadow:var(--shadow-1);
  padding:var(--sp-5) var(--sp-4);max-width:34rem;margin-inline:auto;text-align:center;
  border-top:1.5px solid var(--gold);border-bottom:1.5px solid var(--gold);
}
.receipt__lbl{
  font-family:var(--sans);font-variation-settings:'wght' 600,'wdth' 92;
  font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-soft);
  margin:0 0 var(--sp-2);
}
.receipt__ref{
  font-family:var(--serif);font-variation-settings:'wght' 500;
  font-size:clamp(1.9rem,5.2vw,2.6rem);line-height:1.1;color:var(--ink);
  font-variant-numeric:tabular-nums;letter-spacing:.06em;
  margin:0;overflow-wrap:anywhere;
}
.receipt__at{
  font-family:var(--sans);font-size:.8rem;color:var(--ink-soft);
  font-variant-numeric:tabular-nums;margin:var(--sp-2) 0 0;
}
/* 44px minimum, and it says what it does — "Copy reference", not an icon the
   visitor has to interpret at the one moment they most need certainty. */
.receipt__copy{
  margin-top:var(--sp-3);min-height:44px;padding:0 var(--sp-4);
  font-family:var(--sans);font-variation-settings:'wght' 600,'wdth' 100;font-size:.85rem;
  background:transparent;color:var(--rose-text);border:1.5px solid var(--rose-text);
  border-radius:999px;cursor:pointer;transition:background .18s ease,color .18s ease;
}
.receipt__copy:hover{background:var(--rose-text);color:var(--paper)}
.receipt__copy[data-copied]{background:var(--rose-text);color:var(--paper)}
@media(prefers-reduced-motion:reduce){.receipt__copy{transition:none}}

/* Recognition triptych — Sarit's approved three-panel plate, in flow.
   max-width is the plate's NATIVE width: it may shrink on a narrow screen but
   is never enlarged past what she supplied, so the panels stay clean.
   No border, no card: it is a painting on the page's own paper, and boxing it
   would make it the one framed object on the page. */
.triptych{margin:0;text-align:center}
.triptych img{width:100%;max-width:2084px;height:auto;display:block;margin-inline:auto}
