/* ============================================================
   CALDER — design system · Stage 2 (type, colour, spacing)
   No motion. Hover = colour/underline only, .35s.
   ============================================================ */

/* ---------- fonts · self-hosted ---------- */
/* The reference's exact faces, both OFL and self-hosted: Inter Tight (one
   variable file, 400-700) and Instrument Serif roman + italic. Switzer is
   retired but its files stay on disk. */
@font-face{font-family:'Inter Tight';src:url('../fonts/InterTight-Variable.woff2') format('woff2');font-weight:400 700;font-style:normal;font-display:swap}
@font-face{font-family:'Instrument Serif';src:url('../fonts/InstrumentSerif-Regular.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Instrument Serif';src:url('../fonts/InstrumentSerif-Italic.woff2') format('woff2');font-weight:400;font-style:italic;font-display:swap}

/* ---------- tokens ---------- */
:root{
  color-scheme:dark;
  --ink:#101216;
  --ink-2:#191C22;
  --line:#262B32;
  /* THE LIGHT GROUND AND THE DISPLAY INK ARE THE REFERENCE'S OWN, MEASURED
     (25 Aug). Its light sections are a NEUTRAL rgb(234,232,233) - the same
     value on its technology page, its contact panels and its button fill - and
     its display type on them is rgb(62,63,63), a grey, never near-black. Ours
     ran a warm cream #EDEAE4 with #101216 type, which is why the two sites read
     as different papers side by side (Jenil, 25 Aug). --ink stays the DARK
     GROUND; --ink-d is the type that sits on bone. */
  --bone:#EAE8E9;
  --bone-2:#D6D5D8;
  --ink-d:#3E3E3E;   /* rgb(62,62,62) - sampled on its panel names, its address,
                        its telephone and its display headline; all four agree */
  --muted:#7E848D;
  --calder:#B4402B;
  /* the footer's ground: the reference's own footer navy, sampled off its
     rendered pixels (1 Sep) - rgb(37,38,47), a clear step lighter than --ink.
     Home's and studio's dome + footer carry it; technology, contact and the
     laboratory still sit on --ink and are flagged for Jenil. */
  --ink-f:#25262F;

  --ui:'Inter Tight',system-ui,-apple-system,'Segoe UI',sans-serif;
  --serif:'Instrument Serif',Georgia,serif;

  --t-label:11px;
  --t-body:clamp(15px,1.05vw,17px);
  --t-lead:clamp(18px,1.5vw,22px);
  --t-sub:clamp(24px,2.4vw,34px);
  --t-sec:clamp(46px,8.4vw,132px);
  /* The reference's display scale, measured on the live site at 1440:
     153px = 10.625vw, weight 400, letter-spacing -3%, line-height .8,
     Instrument Serif roman with the accent word in the italic. One scale for
     the hero headline, both scrub lines and the mega - they are one voice. */
  --t-hero:clamp(38px,10.625vw,204px);
  --t-scrub:clamp(56px,10.625vw,204px);
  --t-promise:var(--t-scrub);
  --t-mega:clamp(34px,10.625vw,204px);  /* the reference's technology mega: 153px at 1440 */
  --t-index:clamp(30px,5.4vw,74px);

  --s-xs:8px; --s-sm:16px; --s-md:32px; --s-lg:64px; --s-xl:120px; --s-2xl:180px;

  --wrap:1240px; --wrap-wide:1600px; --gut:clamp(20px,4.4vw,72px);
  /* Header wordmark width; the aspect is the file's own 1600:520, so the height
     follows. Taken up from clamp(100px,6.5vw,124px) on Jenil's instruction
     (26 Aug) - 165 at 1920 and 126 at 1440, i.e. +33% and +26%. The ceiling is
     the BAND, not taste: the band is --nav-h tall with --nav-py top and bottom,
     which leaves 64px of content at 1920 and 48.4px at 1440, and 3.077x those is
     197 and 149. 165/126 sits inside both with room, and 43+165 is still clear of
     .head-primary's 23.26% (446 at 1920). */
  --wm-w:clamp(126px,8.6vw,165px);

  /* THE NAV BAND SCALES WITH THE VIEWPORT - the reference's does, and freezing
     ours at the 1440 set is why it read small and thin next to it at 1920.
     Measured off the reference recording at 1920 (layout width 1905, classic
     scrollbar): band 96, padding 16/43, every visible nav word 18px, the pill
     64 tall with 32 side padding, "Menu" ink starting at x=448. Each figure is
     exactly 1.333x the 1440 set already recorded (72 / 12+32 / 14 / 48), so
     these clamps land on the approved 1440 numbers and on the reference's
     1920 numbers, and hold still outside that range. */
  --nav-h:clamp(72px,5.04vw,96px);      /* band height, border-box */
  --nav-py:clamp(12px,.84vw,16px);      /* band height - 2x this = the pill */
  --nav-px:clamp(32px,2.26vw,43px);
  --nav-fs:clamp(13.5px,.945vw,18px);   /* every visible nav word, w500 */
  --nav-sub:clamp(10px,.68vw,13px);     /* the studio line under the phone */
  --nav-gap:clamp(32px,2.15vw,41px);    /* Menu -> Services */
  --nav-agap:clamp(24px,2.05vw,39px);   /* the right cluster */
  --nav-pill-px:clamp(24px,1.68vw,32px);
  --nav-pill-gap:clamp(44px,4.15vw,79px); /* label -> plus, measured 79 at 1920 */

  --ease:cubic-bezier(.16,1,.3,1);
  /* THE hover token. Every hover on the site uses this one duration; the only
     derivative is --hover-slow, the brief's x1.5 for the treatments hairline.
     No hover is a colour change alone; transform and clip-path only; an edge
     that travels in leaves by the far side; :focus-visible gets the identical
     treatment; hover-only rules live inside media (hover:hover). */
  --hover:.42s cubic-bezier(.22,1,.36,1);
  --hover-slow:.63s cubic-bezier(.22,1,.36,1);
}

/* ---------- reset & base ---------- */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
body{
  background:var(--ink);
  color:var(--bone-2);
  font-family:var(--ui);
  font-size:var(--t-body);
  font-weight:400;
  line-height:1.62;
  -webkit-font-smoothing:antialiased;
}
img,svg,video{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
p a{position:relative;text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--muted);transition:color .35s var(--ease),text-decoration-color .35s var(--ease)}
::selection{background:var(--bone);color:var(--ink-d)}
:focus-visible{outline:2px solid var(--calder);outline-offset:4px}
em{font-family:var(--serif);font-style:italic;font-weight:400;letter-spacing:0;font-size:1.04em}
strong{font-weight:600;color:var(--bone)}
h1,h2,h3{color:var(--bone);font-weight:500}

/* ---------- skip link ---------- */
.skip{position:absolute;left:var(--gut);top:-100px;z-index:200;background:var(--ink-2);color:var(--bone);padding:12px 20px;font-size:var(--t-label);font-weight:500;letter-spacing:.18em;text-transform:uppercase}
.skip:focus{top:16px}

/* ---------- header ---------- */
/* Fixed from 1000px so the menu trigger is reachable anywhere on the page and
   the wordmark can hand its colour over on the hero timeline; below 1000px it
   stays absolute and scrolls away, exactly as before. The header sits ABOVE
   the menu overlay (60 over 55) so the trigger stays clickable while open. */
.site-head{position:absolute;inset:0 0 auto 0;z-index:60;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:28px var(--gut)}
@media(min-width:1000px){.site-head{position:fixed}}
/* THE WORDMARK IS THE OPEN-RAIL SVG, AND ITS TWO SURFACE VARIANTS CROSSFADE ON
   ONE NUMBER. --wm-ink is the opacity of the GRAPHITE (on-light) asset; the
   soft-bone (on-dark) asset carries 1 - that. It is declared beside `color` in
   every single rule that already recolours .brand - the mobile ink rule, the
   menu-open rule, the head-ink/head-bone pair, the is-on-light/is-on-dark pair
   and the hero's scrubbed handover - so the swap inherits the cascade the
   wordmark already had, exactly, rather than a second set of states that could
   disagree with the Menu/Services words beside it.
   The box is sized in WIDTH only and the aspect comes from the file, so a
   colour change can never move the band: both images are absolutely positioned
   in the same box and only their opacity moves. */
.brand{display:block;position:relative;width:var(--wm-w);aspect-ratio:1600/520;flex:0 0 auto;
  font-weight:600;font-size:13px;letter-spacing:.26em;text-transform:uppercase;color:var(--bone);
  --wm-ink:0;transition:color .35s var(--ease)}
.brand__wm{position:absolute;inset:0;width:100%;height:100%;display:block;
  transition:opacity .35s var(--ease)}
.brand__wm--light{opacity:var(--wm-ink)}          /* graphite, for bone grounds */
.brand__wm--dark{opacity:calc(1 - var(--wm-ink))} /* soft bone, for ink/film/menu */
/* the same two-layer edge every other film-crossing element carries. It is a
   drop-shadow because the mark is no longer type, so text-shadow cannot reach
   it; it is NOT a recolour, and over ink grounds it is invisible by design. */
.brand__wm--dark{filter:drop-shadow(0 1px 2px rgba(16,18,22,.38)) drop-shadow(0 4px 30px rgba(16,18,22,.55))}
.site-head nav ul{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px 28px;list-style:none}
.site-head nav a{position:relative;font-size:var(--t-label);font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--bone-2);padding:6px 2px;transition:color .35s var(--ease)}
/* hover treatments live in the hover-system block at the end of the sheet */
.head-actions{display:flex;align-items:center;gap:8px 32px}
.head-link,.menu-toggle{font-size:var(--t-label);font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--bone);
  /* the two-layer edge shadow: invisible over ink, holds the labels when the
     fixed header crosses the film and planning media further down the page */
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.head-link{position:relative;padding:6px 2px;transition:color .35s var(--ease)}
.menu-toggle{background:none;border:0;cursor:pointer;padding:6px 2px;font-family:var(--ui)}
/* The hidden-twin pair, generalised from .menu-word: BOTH faces are reserved
   as invisible ghosts, so the italic swap moves nothing. In the header the
   words right-align inside their reserved box (the cluster hangs from the
   right edge); the menu list keeps its own start-aligned version. */
.it-word{display:inline-grid;justify-items:start}
.it-word>span,.it-word::before,.it-word::after{grid-area:1/1}
.it-word::before,.it-word::after{content:attr(data-text);visibility:hidden}
.it-word::after{font-family:var(--serif);font-style:italic;font-size:1.04em;letter-spacing:0}
.head-link .it-word,.menu-toggle .it-word{justify-items:end}
/* Menu/Close swap with the width reserved: both words occupy the same grid
   cell, the box sizes to the wider, and nothing shifts when the word changes. */
.menu-toggle__box{display:inline-grid;justify-items:end}
.menu-toggle__word{grid-area:1/1}
.menu-toggle__word--close{visibility:hidden}  /* roman at rest; italic is the hover, same as Menu */
.menu-open .menu-toggle__word--menu{visibility:hidden}
.menu-open .menu-toggle__word--close{visibility:visible}
body.menu-open:not(.legal) .brand{color:var(--bone);--wm-ink:0}  /* over the open menu's dark ground, whatever it
  was before - specificity has to clear the ink-on-bone hero rule further down */

/* ---------- section rhythm ---------- */
section{padding-block:var(--s-xl);padding-inline:var(--gut)}
@media(min-width:1200px){section{padding-block:var(--s-2xl)}}

.eyebrow{display:flex;align-items:center;gap:12px;font-size:var(--t-label);font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);margin-bottom:var(--s-md)}
/* the rule KEEPS its 26px layout box - scaling to 40px visually (x1.5385)
   instead of widening would shift the eyebrow text 14px at rest otherwise */
.eyebrow::before{content:"";width:26px;height:1px;background:var(--calder);flex:none;transform-origin:0 50%;transition:transform var(--hover)}

.t-sec{font-size:var(--t-sec);line-height:.94;letter-spacing:-.025em;max-width:var(--wrap-wide)}
.lead{font-size:var(--t-lead);line-height:1.4;color:var(--bone-2);max-width:44ch;margin-top:var(--s-md)}

/* ---------- 1 · hero · three states on one pinned timeline ----------
   The film sits at the bottom of the stack, full-bleed from the start, and is
   never animated - only the bone panel's clip edge moves over it. Below 1000px
   there is no panel and no pin: the bone card is a static block above the
   full-bleed film, and both headlines simply stand. */
/* overflow:hidden is load-bearing from 1000px up: the promise line is set
   WIDER than the viewport on purpose so it can scrub sideways, and .hero-stage
   (which used to do this clipping) is display:contents up there, so it clips
   nothing. Without this the page scrolls horizontally. */
#hero{min-height:100svh;position:relative;padding-block:0;padding-inline:0;overflow:hidden}
.hero-stage{position:relative;min-height:100svh;display:grid;place-items:center;
  /* align-content, because below 1000 the stage now has TWO in-flow children:
     .hero-promise and .hero-services, which used to be one. Left at the grid
     default the two rows stretch to fill 100svh and each item is centred in
     its own row - measured, that opened a 304px gap at 390 where the list's
     own --s-md is 32. Centring the CONTENT puts the pair back together and
     lands them exactly where the single item used to sit. */
  align-content:center;overflow:hidden}
.hero-film{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0}
.hero-line{font-family:var(--serif);font-size:var(--t-hero);line-height:.9;letter-spacing:-.03em;font-weight:400;text-align:center;padding-inline:2vw}
/* serif display blocks: the italic sits at 1:1 - the global 1.04em bump exists
   to match Switzer's x-height and is wrong inside an all-serif line */
.hero-line em,.hero-promise__h em,.filmline em,.mega em,.hero-mid em{font-size:1em}
/* Two lines, the second indented under the first. The pair is left-aligned
   inside an inline-block, so the indent is a real indent; the inline-block is
   what the parent's text-align centres, so the set-piece keeps its centring.
   nowrap moved off .hero-line and onto each line - left on the parent it would
   have forced both lines onto one. Below 1000px the lines may wrap and the
   indent is dropped, or 'Restorative Dentistry' overflows 390. */
.hero-line__set{display:inline-block;text-align:left}
.hero-line__a,.hero-line__b{display:block}
.hero-line__a{text-align:center}  /* 'Aesthetic &' centred over 'Restorative Dentistry', as the reference sets its first line */
@media(min-width:1000px){
  .hero-line__a,.hero-line__b{white-space:nowrap}
  /* THE SEAM FALLS IN THE WORD SPACE, AND THAT IS WHAT THIS NUMBER SOLVES FOR.
     Jenil, 26 Aug: 'Restorative' must sit ENTIRELY on the bone half, with
     'Dentistry' repositioned to follow. Measured at 1000/1280/1440/1920 (one
     figure, because both the type and this offset are vw-based, so the ratio is
     constant): with the old +2.8vw nudge, 'Restorative''s ink ran 2.348vw PAST
     the seam, and the space between the two words is 1.488vw. Landing the seam
     on the MIDPOINT of that space therefore needs 2.348 + 1.488/2 = 3.092vw of
     leftward travel, i.e. 2.8 - 3.092 = -0.292vw here, and it gives each word
     the same 0.744vw of clearance from the edge. Splitting the space evenly is
     the point: the boundary reads as deliberate when it sits between the words
     rather than grazing one of them. Do NOT chase a bigger clearance - the whole
     space is only 1.488vw, so anything more on one side is taken off the other.
     Above 1920 --t-hero clamps while this stays in vw, so the split drifts to
     0.652 / 0.538vw at 2400 - both still clear, which is what matters.
     'Aesthetic &' still crosses the seam, as 'Premium' did - the reference's own
     first line crosses onto its image too. */
  .hero-line__set{position:relative;left:-0.292vw}
}
.seam,.hero-line--dark{display:none}
/* below 1000px the light copy IS the bone card - a block above the film */
.hero-line--light{background:var(--bone);color:var(--ink-d);padding-block:clamp(110px,18vh,170px) clamp(48px,9vh,90px)}

/* state 3 - the promise over the full-bleed film. Centred: this is the hero
   set-piece's closing act, the same centred set-piece the category line opens -
   the planning mega-headline's two lines are the other two. */
.hero-promise{position:relative;z-index:1;text-align:center;padding-inline:var(--gut)}
.hero-promise__h{font-size:var(--t-hero);line-height:1.06;letter-spacing:-.025em;font-weight:500;color:var(--bone);
  /* three layers here, not two: this line holds still over 24s of changing
     film, and the serif italic's thin strokes went soft on the blown-out
     window at t~19s with the standard pair - judged by eye, per the brief */
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 2px 14px rgba(16,18,22,.42),0 4px 30px rgba(16,18,22,.55)}
.hero-services{list-style:none;margin:var(--s-md) auto 0;width:min(340px,78vw)}
.hero-services li + li{border-top:1px solid var(--line)}
.hero-services a{position:relative;display:block;padding:13px 0;font-size:var(--t-label);font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--bone);
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
/* hover: the rule-1 wipe, defined in the hover-system block */

.hero-foot{position:absolute;left:var(--gut);bottom:5vh;z-index:1;display:flex;flex-direction:column;line-height:1.15;color:var(--bone);
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
/* Reference scale: sentence case, no tracking, semibold cities at ~22px, not
   11px uppercase label type - the 11px setting is why the hero read empty. */
.hero-foot span:not(.hero-foot__label){font-family:var(--ui);font-weight:600;font-size:clamp(17px,1.55vw,23px);letter-spacing:-.005em;text-transform:none}
.hero-foot__label{font-family:var(--ui);font-weight:400;font-size:clamp(13px,1.05vw,16px);letter-spacing:0;text-transform:none;color:var(--bone-2);margin-bottom:.9em}
.hero-note{position:absolute;right:var(--gut);bottom:5vh;z-index:1;font-family:var(--ui);font-weight:600;font-size:clamp(17px,1.55vw,23px);letter-spacing:-.005em;line-height:1.15;text-align:right;max-width:22ch;text-transform:none;color:var(--bone);
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
/* The serif sentence in the film half. NOTE: --serif has no roman face on disk
   (only InstrumentSerif-Italic.woff2 is loaded), so a serif roman opening would
   fall back to Georgia - the first off-brand face on the page. The sentence
   therefore uses the construction every other headline here uses: Switzer
   roman opening, Instrument Serif italic payoff via em. Desktop-only; the
   composition it belongs to (the seam at 50%) exists only there. */
.hero-mid{display:none}

/* below 1000px the header sits over the bone card, so its three elements are
   ink there; the open menu flips them back to bone over its dark ground */
@media(max-width:999px){
  body:not(.legal) .brand{color:var(--ink-d);--wm-ink:1}
  .head-link,.menu-toggle{color:var(--ink-d);text-shadow:none}
  body.menu-open .head-link,body.menu-open .menu-toggle{color:var(--bone)}
}

@media(min-width:1000px){
  /* One value drives all three clip edges, so the panel and both copies of the
     headline are cut at the same column on every frame. The headline never moves:
     the seam travels across it and each glyph inverts as it passes.
     A percentage clip is only trustworthy when every element it drives shares one
     box: .seam resolves its inset() against the full-viewport padding box of #hero,
     so both headline copies must have that same box. Hence padding-inline:0 on
     #hero and width:100% on .hero-line below - a shrink-to-fit grid item resolves
     the same percentage against its own narrower box and the three edges land at
     different absolute x (measured: 48px apart at 1920, a glyph swallowed whole).
     clip-path cuts to the BORDER box, so that box has to contain the tallest
     ink on the line. The lab gets away with line-height:1.24 because every
     glyph there is one font; here only <em> is Instrument Serif, at 1.04em, and
     its inline box overruns the Switzer strut by 4px top and bottom at 1440.
     Hence padding-block as well: it grows the border box without touching the
     leading, and being symmetric it leaves the line optically where it was. */
  /* at rest the composition is exactly half bone, half film; the travel is
     one-way from here to 0 */
  /* grid-template-columns:100% pins the track to the viewport. Without it the
     track is auto-sized to the widest item, and the promise line - which is
     deliberately wider than the viewport for the scrub - would stretch it,
     making .hero-line{width:100%} wider than .seam's inset:0 box. That is
     exactly the clip-box mismatch the seam invariant exists to prevent. */
  #hero{--seam:50%;display:grid;grid-template-columns:100%;place-items:center}
  /* the stage dissolves: its children join #hero's grid, and its absolutes
     resolve against #hero - which keeps all three clip boxes one box */
  .hero-stage{display:contents}
  .hero-line,.hero-promise{grid-area:1/1}
  .seam{display:block;position:absolute;inset:0;background:var(--bone);clip-path:inset(0 calc(100% - var(--seam)) 0 0);z-index:0}
  /* lh .9 to sit near the reference's .8 while the padding keeps the border
     box (which clip-path cuts to) around the serif's ink - Instrument's ink
     is far more compact than Switzer's was, measured slack below */
  .hero-line{width:100%;line-height:.9;padding-block:44px;position:relative;z-index:1}
  /* NO per-copy padding-block: both copies must inherit .hero-line's, or the
     two clipped copies render their text at different y and the seam shows a
     vertically doubled headline */
  .hero-line--light{background:none;color:var(--bone);clip-path:inset(0 0 0 var(--seam));
    text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}  /* it sits over the film */
  .hero-line--dark{display:block;color:var(--ink-d);clip-path:inset(0 calc(100% - var(--seam)) 0 0)}
  /* On the bone panel at rest; the timeline tweens these to bone tones and
     raises the shadow alphas as the panel retreats past them in state 2. This
     block has to sit AFTER the base rules above: a media query carries no extra
     specificity of its own. */
  /* cities in ink on the panel; the label keeps #5F656D, the panel-side muted
     (4.90:1 on bone) - var(--muted) itself is 3.14:1 on bone and fails at 15px */
  .hero-foot{color:var(--ink-d)}
  .hero-foot__label{color:#5F656D}
  /* shadow starts transparent ON THE PARENT ONLY, so the tweened inline value
     inherits into the spans - a declaration on the label would block it */
  .hero-foot{text-shadow:0 1px 2px rgba(16,18,22,0),0 4px 30px rgba(16,18,22,0)}
  /* The wordmark's colour is routed through a custom property so the timeline
     can scrub it (ink on the panel -> bone over film) WITHOUT writing an inline
     color on .brand itself - an inline color would outrank every selector,
     including the menu-open rule above, and a scrolled-then-reopened menu would
     show an ink wordmark on the menu's ink ground. The tween writes --brand-c
     on body; this rule reads it; the menu-open rule ignores it and wins. */
  body:not(.legal) .brand{color:var(--brand-c,var(--ink-d));--wm-ink:var(--brand-wm,1)}  /* the wordmark was bone-on-bone: 1.00:1 */
  /* Seated where the reference seats its own film-half sentence, measured off
     the recording at 1920 (page 1920x940): ink starts 43px inside the film
     edge - the same 43px as the band's side padding, hence --nav-px - and the
     LAST BASELINE lands 68px off the viewport bottom, level with the studios
     block on the left and the note on the right. All three share one baseline
     there; ours was 96px higher than the note and floating mid-frame.
     Scale is the reference's too: Instrument Serif 44px at 1920 (its line 1
     measures 360px of ink; ours sets 346px on the same face), line pitch 40px
     = line-height .91. max-width is in em so the break after "with," holds at
     every size. bottom is the note's own 5vh: with .91 leading that lands the
     two last baselines within 0.4px of each other, which is the alignment the
     reference shows, and they stay level as both scale. */
  .hero-mid{display:block;position:absolute;left:calc(50% + var(--nav-px));bottom:5vh;max-width:8.2em;font-family:var(--serif);font-weight:400;font-size:clamp(23px,2.29vw,44px);line-height:.91;letter-spacing:-.01em;color:var(--bone);z-index:1;
    text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
}
/* At the narrowest desktop the film half is only ~500px and the reference's
   own 2.29vw would put the sentence's last glyph on the note's first. A
   steeper local ramp clears it - and it MEETS the main curve at 1120 (both
   read 25.65px there), so resizing through the boundary shows no step.
   Everything from 1120 up, 1440 and 1920 included, is untouched. */
@media(min-width:1000px) and (max-width:1120px){
  .hero-mid{font-size:calc(4.29vw - 22.4px)}
}

@media(min-width:1000px) and (prefers-reduced-motion:no-preference){
  .hero-promise,.hero-services{opacity:0;visibility:hidden}  /* the timeline raises them; without
                                                 JS the hero simply rests in state 1 */
  /* E2 - the promise line does not rise, it travels. Set at display scale on ONE
     line, wider than the viewport, and translated on x across state 3 by the same
     pinned timeline. Compositor only: x, never left or margin. #hero clips the
     overhang and grid-template-columns:100% keeps it out of the track sizing. */
  .hero-promise__h{font-family:var(--serif);font-weight:400;font-size:var(--t-promise);line-height:.9;letter-spacing:-.03em;white-space:nowrap;width:max-content;will-change:transform}
}

/* Reduced motion from 1000px: state 3 rendered statically. No panel, no
   inverting pair, no ScrollTriggers created; the film stands on its poster and
   the promise line holds still over it. The h1 stays in the document, clipped
   to a point, so the page keeps its heading for assistive tech. */
@media(min-width:1000px) and (prefers-reduced-motion:reduce){
  .seam,.hero-line--dark{display:none}
  .hero-line--light{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
  /* the poster's header band is bright sky, and this state never moves - the
     wordmark needs the same edge shadow every other film-crossing element gets */
  body:not(.legal) .brand{color:var(--bone);--wm-ink:0;text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  .hero-foot{color:var(--bone);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  .hero-foot__label{color:var(--bone-2)}
  .hero-mid{display:none}  /* state-1 furniture; this state renders state 3 */
}

/* THE THREE SERVICE ANCHORS ARE ONE ROW ACROSS THE FRAME FROM 1000px, NOT A
   CENTRED STACK. Measured on the reference's own hero row - it calls the
   element .bottom-tips - at 1920 / 1440 / 1280: display:flex with
   justify-content:space-between, running gutter to gutter at its --nav-px
   (43.0 / 32.0 / 28.5 measured), the three words set at 20 / 15 / 13.33px
   w700 Inter Tight with NO tracking and NO uppercase, in rgb(234,232,232) -
   our own --bone. One figure covers all three widths: 1.0417vw.
   Ours ran an 11px uppercase list on .18em of tracking inside a 340px centred
   box with a hairline rule between the rows: the same three names in a
   completely different grammar (Jenil, 29 Aug, with the two side by side).
   space-between, not a 1fr auto 1fr grid: the reference's own middle label is
   7.35px off the frame centre at 1920, so it is genuinely spread, not centred.
   (The film labels ARE centred - that element was measured separately and is
   the reference's own dead-centre set. Do not make these two one rule.)
   The gutter is reached by cancelling .hero-promise's own --gut padding, the
   same way .film-labels cancels --g. */
@media(min-width:1000px){
  /* absolutely positioned against #hero, so the row is measured against the
     FRAME. left/right in px, never 100vw: a classic scrollbar makes 100vw wider
     than the layout viewport and would throw the row 7.5px off the header's own
     gutter. top is the h2's own half-height (line-height .9) plus --s-md below
     the centre line, so the line stays centred and the row hangs under it. */
  .hero-services{position:absolute;z-index:1;
    left:var(--nav-px);right:var(--nav-px);width:auto;margin:0;
    top:calc(50% + var(--t-promise) * .45 + var(--s-md));
    display:flex;justify-content:space-between;align-items:baseline;gap:32px}
  .hero-services li + li{border-top:0}
  .hero-services li:last-child{text-align:right}
  .hero-services a{padding:0;font-size:clamp(13.3px,1.0417vw,20px);font-weight:700;
    letter-spacing:normal;text-transform:none;line-height:1.13}
  /* the underline wipe's desktop seat lives beside the shared base rule
     further down - a bottom:-8px here LOSES the cascade to that later
     equal-specificity base and never applies. Do not re-declare it here. */
}

/* ---------- legal page ---------- */
.legal main{max-width:calc(820px + 2*var(--gut));padding:var(--s-xl) var(--gut)}
.legal section{padding:0}
.legal .site-head{position:static;padding-block:28px}
.legal-eyebrow{display:flex;align-items:center;gap:12px;font-size:var(--t-label);font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);margin-bottom:var(--s-md)}
.legal-eyebrow::before{content:"";width:26px;height:1px;background:var(--calder);flex:none}
.legal h1{font-size:var(--t-sub);line-height:1.15}
.legal .legal-lede{margin-top:var(--s-md);max-width:56ch}
.legal article{border-top:1px solid var(--line);padding-block:var(--s-lg);margin-top:0}
.legal article:first-of-type{margin-top:var(--s-xl)}
.legal article h2{font-size:var(--t-lead);margin-bottom:var(--s-sm)}
.legal article p{max-width:62ch;color:var(--bone-2)}
.legal article p + p{margin-top:var(--s-sm)}
.legal .updated{border-top:1px solid var(--line);padding-top:var(--s-md);font-size:var(--t-label);font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
/* legal.html's footer is a plain three-part block, not the site grid - it takes
   main's own measure and gutter so the three rows line up with the articles
   above them. (The --wrapmax centring they used to inherit went with the
   footer rebuild on 24 Aug.) */
.legal footer{margin-top:var(--s-xl);max-width:calc(820px + 2*var(--gut));
  padding:var(--s-md) var(--gut) var(--s-xl);border-top:1px solid var(--line);
  display:grid;gap:var(--s-md);justify-items:start}
.legal footer .foot-disclosure{color:var(--bone-2);font-size:14px;line-height:1.5;max-width:52ch}
.legal footer .foot-copy{font-size:11px;font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);line-height:1.4}
.legal footer nav ul{list-style:none;display:flex;gap:var(--s-md);flex-wrap:wrap}
.legal footer nav a{font-size:14px;font-weight:600;color:var(--bone)}

/* ---------- mobile ---------- */
@media(max-width:760px){
  section{padding-block:72px}
  .hero-line{white-space:normal;padding-inline:var(--gut)}
  /* the studios block below is now three lines (~54px), not one - the note
     clears it by its full height plus a breath */
    /* 82px = the reference-scale foot's measured 65.7px + 16px of air; the old
     72px was tuned for the 11px three-line block and left only 6.2px */
  .hero-note{left:var(--gut);right:var(--gut);bottom:calc(5vh + 82px);text-align:left;max-width:34ch}
}

/* ============================================================
   THE HOVER SYSTEM - a travelling edge that reveals.

   Two families now, per the reference: small navigation and button moves
   run at --ui-dur (300ms); the large duplicated menu-text roll runs at
   --roll-dur (800ms); scroll scenes are scrubbed and have no duration of
   their own. The hero keeps its original --hover token untouched.
   An edge that wipes in from the left leaves by the right - the
   transform-origin flip does exactly that. Hover-only rules sit inside
   media (hover:hover) and (pointer:fine); :focus-visible carries the
   identical declarations unconditionally.
   ============================================================ */

/* --- rule 1 - the underline wipe: shared base --- */
p a::after,.hero-services a::after,.site-head nav ul a::after{
  content:"";position:absolute;left:0;right:0;bottom:-3px;height:1px;background:currentColor;
  transform:scaleX(0);transform-origin:100% 50%;transition:transform var(--hover)}
/* BOTH of the anchors' seats are declared HERE, after the shared base - the
   desktop one used to sit in the min-width:1000px block EARLIER in the sheet,
   where it lost the cascade to this base rule at equal specificity, so the
   bar kept the phone stack's +8px on the desktop row's padding:0 links and
   printed straight THROUGH the words (Jenil, 3 Sep, three crops). */
.hero-services a::after{bottom:8px}                    /* inside the phone row's 13px padding */
@media(min-width:1000px){ .hero-services a::after{bottom:-8px} }  /* hung under the bare desktop words */

/* --- the external-link arrow: out up-right, twin in from bottom-left --- */
/* THE ARROW IS DRAWN TOO. Measured off the reference's own list rows at 1920:
   a 12x12 box on a 2px stroke, and the head is NOT a small chevron - its two
   arms run the FULL width and height of the box (top arm x1861-1872, right arm
   y420-431) with the shaft on the box's own bottom-left-to-top-right diagonal,
   so the three strokes enclose a triangle. That is 0.585em of the row's type,
   and the stroke .167 of the box - both expressed as percentages here so the
   glyph underneath can still be zeroed with font-size:0. Inter Tight's U+2197
   renders a hairline math arrow at the wrong scale, the same reason the three
   nav marks are drawn. */
.ext{--arw:max(1.2px,.098em);display:inline-grid;overflow:hidden;margin-left:.55em;
  vertical-align:-.05em;line-height:1;width:.585em;height:.585em}
.ext>span{grid-area:1/1;position:relative;overflow:hidden;width:100%;height:100%;
  transition:transform var(--roll-mark) var(--ease-swap);
  background:linear-gradient(currentColor 0 0) 0 0/100% var(--arw) no-repeat,
             linear-gradient(currentColor 0 0) 100% 0/var(--arw) 100% no-repeat}
.ext>span::after{content:"";position:absolute;left:50%;top:50%;width:142%;height:var(--arw);
  background:currentColor;transform:translate(-50%,-50%) rotate(-45deg)}
.ext>span:last-child{transform:translate(-120%,120%)}

/* --- hover states (pointer devices only) --- */
/* THE ARROW ROLLS WHEREVER IT SITS. Measured frame by frame on hover.mp4 at
   1920: the reference's "Patient form" arrow leaves up-right and its twin
   arrives from down-left over 10 frames (0.33s) while the WORD beside it does
   not move at all - its bbox and ink count are identical in every frame. Ours
   wired the roll to `footer nav a` only and gave every other one an underline
   instead. One rule now: any link holding an .ext rolls it. */
@media(hover:hover) and (pointer:fine){
  p a:hover::after,.hero-services a:hover::after,.site-head nav ul a:hover::after{
    transform:scaleX(1);transform-origin:0 50%}
  /* colour accompanies the movement - never the whole response */
  p a:hover{color:var(--bone);text-decoration-color:var(--bone)}
  a:hover>.ext>span:first-child,button:hover>.ext>span:first-child{transform:translate(120%,-120%)}
  a:hover>.ext>span:last-child,button:hover>.ext>span:last-child{transform:translate(0,0)}
}

/* --- :focus-visible - the identical treatment, unconditionally --- */
p a:focus-visible::after,.site-head nav ul a:focus-visible::after,
.hero-services a:focus-visible::after{transform:scaleX(1);transform-origin:0 50%}
a:focus-visible>.ext>span:first-child,button:focus-visible>.ext>span:first-child{transform:translate(120%,-120%)}
a:focus-visible>.ext>span:last-child,button:focus-visible>.ext>span:last-child{transform:translate(0,0)}
p a:focus-visible{color:var(--bone);text-decoration-color:var(--bone)}

/* ============================================================
   THE REPLICA LAYER - the reference's page architecture on Calder's
   palette, faces and copy. Layout, scale, proportion and pacing follow
   the reference, measured at 1440x900; every line of code and copy here
   is Calder's own. The hero above is untouched and keeps its own tokens.
   ============================================================ */

:root{
  /* the reference's desktop grid: 32px outer gutter, 1376 content,
     two 688 halves meeting at x=720 */
  --g:clamp(16px,2.223vw,32px);
  --wrapmax:1376px;
  /* the footer's type set, measured off the reference at 1920 (24 Aug):
     column label 19.2 (a 14px cap), links and studio headings 28.9 (21),
     address and bottom bar 17.9 (13), telephone 20.6 (15) w700, the
     fine two-column row 16.5 (12). Each is that value / 19.20 in vw. */
  /* the footer set, re-read off the reference's live computed styles (1 Sep):
     links are 21.33px (1rem at their W/90 rem), NOT the 28.9 the 24 Aug pass
     derived from a cap-height reading - that mistake is why our wrapped
     service names looked cramped at 28.9 on the same pitch. Labels 18.67,
     phone 20. */
  --f-label:clamp(13px,.972vw,18.67px);
  --f-link:clamp(15px,1.111vw,21.33px);
  --f-body:clamp(14px,.932vw,17.9px);
  --f-tel:clamp(15px,1.042vw,20px);
  --f-fine:clamp(13px,.859vw,16.5px);
  /* the button, measured off the reference at 1920 (24 Aug): the pill is
     211 x 63 in FULL BONE with ink type - it is filled at rest, not outlined -
     its label is 18px w700 starting 31px inside the left edge, the mark is
     20 x 20 on a 2px stroke, and there are 35px between them and 33 to the
     right edge. Ours was frozen at the 1440 set (158 x 48, a 14px label) and
     drawn as an outline. */
  --btn-h:clamp(44px,3.28vw,63px);
  --btn-fs:clamp(13px,.9375vw,18px);
  --btn-px:clamp(18px,1.667vw,32px);
  --btn-gap:clamp(18px,1.82vw,35px);
  --btn-mk:clamp(14px,1.04vw,20px);
  /* the reference's display scale at 1440: giant 276, major 153, section 83,
     card 35, count 55. vw values grow them proportionally to 1920. */
  --t-giant:clamp(64px,19.17vw,276px);
  --t-d1:clamp(44px,10.625vw,204px);
  --t-d2:clamp(34px,5.764vw,110px);
  --t-card:clamp(24px,2.43vw,40px);
  --t-count:clamp(34px,3.82vw,60px);
  --radius-card:20px; --radius-tile:16px;
  /* THE GOAL'S DISSOLVE IS A WASH TO MID GREY, NOT TO INK - measured off the
     reference (av-sec2 at 1920x919). Its paragraph is NOT near-black to begin
     with: at rest its glyph cores read rgb(66,65,66) on a 233 ground, and as
     the services rise its ground falls 233 -> 127 while those cores RISE to 95.
     Solving displayed = orig*(1-w) + C*w at four sharp-phase samples gives
     C = 89/94/87 per channel and w_max = .746, i.e. the overlay is rgb(90,89,98)
     and it STOPS at .746 - the reference's goal never goes black, it plateaus
     at grey 127 and is covered by the section climbing over it. Ours washed all
     the way to #101216 over near-black type, which is why our glyphs stayed
     dark against a greying ground where the reference's converge into it. */
  --goal-ink:var(--ink-d);  /* the reference's own goal type value - now the site's display ink */
  --goal-wash:#5A5962;     /* L 91 - what the section washes toward */
  /* the services stage's corner index and the panel's link rows are one size:
     measured on the reference at 1920 both render a 15px CAP - 20.5px on Inter
     Tight's .7275 cap ratio - where ours ran 14px and 18px. */
  --svc-list:clamp(15.4px,1.068vw,20.5px);
  /* the motion tokens: small UI moves at 300ms, the big menu roll at 800ms;
     scroll scenes are scrubbed and own no duration. The hero keeps --hover. */
  --ease-out:cubic-bezier(.23,1,.32,1);
  --ease-io:cubic-bezier(.77,0,.175,1);
  --ease-roll:cubic-bezier(.22,1,.36,1);
  --ui-dur:.3s;
  --roll-dur:.8s;
  /* the two roll curves, fitted to the reference's own per-frame steps.
     A MARK swapping for its twin accelerates then decelerates (its arrow's
     left edge moves 1,1,3 on the way out and 2,2,1 on the way in, 11 frames =
     .37s), so it is a symmetric ease-in-out. A LABEL rolling in place is
     front-loaded but far gentler than --ease-out: the reference's footer link
     is 53% through at 66ms of 300, where --ease-out would already be at 73%. */
  --ease-swap:cubic-bezier(.65,0,.35,1);
  --ease-soft:cubic-bezier(.33,1,.68,1);
  --roll-mark:.4s;
  /* the reference's panel opens in about 0.6s (24 video frames at 30fps) */
  --loc-dur:.6s;
}
.visually-hidden{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
/* serif display blocks: the italic sits at 1:1 - the global 1.04em bump exists
   to match the sans x-height and is wrong inside an all-serif line */
.plan-mega em,.why__sent em,.footer__ready em,.lab-close__title em,
.bridge__h em,.eq__head h2 em,.lab-hero__left h1 em,.lab-hero__sub em,.pf__line em,
.tech-hero__title em,.pf__cta em,.contact-cta__mega em,.contact-cta__line em,.lab-faq__h em,
.goal__h em,.goal__reveal em,.lab-reveal em{font-size:1em}

/* ---------- header, the reference's band ---------- */
/* Geometry is all fluid now - see the --nav-* tokens. The band is 72/12+32/14/48
   at 1440 (the measured set) and 96/16+43/18/64 at 1920 (the reference's own),
   because the reference scales its header with the viewport. Menu sits at
   23.26% at every width; every visible nav word is Inter Tight 500 (pill 700). */
.site-head{display:flex;align-items:center;height:var(--nav-h);padding:var(--nav-py) var(--nav-px);gap:clamp(20px,4vw,72px);
  transition:transform var(--ui-dur) var(--ease-out);will-change:transform}
.site-head.is-hidden{transform:translateY(calc(-100% - 2px))}
.head-primary{display:flex;align-items:center;gap:var(--nav-gap)}
@media(min-width:1000px){
  .head-primary{position:absolute;left:23.26%;gap:var(--nav-gap)}
}
.menu-toggle,.svc-toggle{font-family:var(--ui);font-size:var(--nav-fs);font-weight:500;letter-spacing:-.01em;text-transform:none;
  background:none;border:0;cursor:pointer;padding:6px 2px;min-height:44px;display:inline-flex;align-items:center;gap:calc(var(--nav-fs)*.61);
  color:var(--bone);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
/* THE THREE NAV MARKS ARE DRAWN, NOT SET. Inter Tight's math characters are
   the wrong shape at this scale - U+2261 renders 8px wide against the
   reference's 14, and U+2304 renders 5px against its 13, because those glyphs
   are hairline symbols, not UI marks. Measured off the reference at 1920, all
   three centred on the band's mid-line (row 48 of 96):
     hamburger  14 x 10, three 2px bars on 2px gaps
     chevron    13 x 6, ~1.7px stroke
     pill plus  21 x 20, 2px strokes
   Sizes are calc()'d off --nav-fs rather than em so the character underneath
   can be zeroed out; strokes carry a 1.5px floor so they stay crisp at 1440. */
.menu-toggle__glyph{display:inline-grid;place-items:center;font-size:calc(var(--nav-fs)*.93);line-height:1}
.menu-toggle__glyph span{grid-area:1/1;transition:opacity var(--ui-dur) var(--ease-out),transform var(--ui-dur) var(--ease-out)}
/* THE HAMBURGER'S THREE BARS WIPE, ONE AFTER ANOTHER. Measured frame by frame
   on hover.mp4 at 1920 (x0 = the bar's left edge 502, its right edge 516):
   each bar's RIGHT edge retreats to its own left edge - 515, 514, 512, 510,
   507, 504, gone - and then a twin grows back from the RIGHT edge leftward -
   515, 513, 511, 509, 508, 507, 506, 505, 504, 503, 502. Left edge pinned on
   the way out, right edge pinned on the way in: that is one box translating
   -100% then +100% inside a window its own size, which is exactly what these
   keyframes do with a single element. The three start 5 and 4 frames apart
   (.15s) and each takes about .5s. The WORD "Menu" beside it never moves - its
   bbox and ink count are identical in all 75 frames. */
.g-bars{font-size:0;width:calc(var(--nav-fs)*.778);height:calc(var(--nav-fs)*.556);
  --bar:max(1.5px,calc(var(--nav-fs)*.111));
  display:flex;flex-direction:column;justify-content:space-between}
.g-bars i{flex:none;display:block;width:100%;height:var(--bar);position:relative;overflow:hidden}
.g-bars i::before{content:"";position:absolute;inset:0;background:currentColor}
/* the two halves are NOT equal: the reference's bar is gone in 6 frames (200ms)
   and takes the rest of the .6s coming back, and it ACCELERATES on the way out
   (edge deltas 1,2,2,3,3) and DECELERATES on the way in (2,2,2,1,1,1,.5). A
   per-keyframe timing function gives each half its own curve. */
@keyframes g-bar-wipe{
  0%{transform:translateX(0);animation-timing-function:ease-in}
  32.9%{transform:translateX(-101%)}
  33%{transform:translateX(101%);animation-timing-function:ease-out}
  100%{transform:translateX(0)}
}
@media(hover:hover) and (pointer:fine){
  .menu-toggle:hover .g-bars i::before{animation:g-bar-wipe .6s linear both}
  .menu-toggle:hover .g-bars i:nth-child(2)::before{animation-delay:.15s}
  .menu-toggle:hover .g-bars i:nth-child(3)::before{animation-delay:.3s}
}
.menu-toggle:focus-visible .g-bars i::before{animation:g-bar-wipe .6s linear both}
.menu-toggle:focus-visible .g-bars i:nth-child(2)::before{animation-delay:.15s}
.menu-toggle:focus-visible .g-bars i:nth-child(3)::before{animation-delay:.3s}
/* THE PLUS AND THE X ARE ONE MARK, AND THE MARK IS NOT A PLUS. Measured off
   the reference at 1920 (the header pill's, averaged over the 8 frames where
   it is static so the JPEG noise cancels): it is TWO ROUNDED L STROKES that
   cross without meeting - one runs down the top arm and turns right into the
   right arm, the other runs in along the left arm and turns down into the
   bottom arm, leaving the upper-left and lower-right quadrants open. Its four
   arm centrelines ARE coaxial (both verticals read x1818.1, both horizontals
   y168.5), which is why it still reads as a plus; the two open quadrants are
   what give it the pinwheel. Box 21x21, stroke 2, corner radius 5 at 1920 =
   1.167 / .111 / .278 of the type it sits with. Each half is one box with two
   borders and one rounded corner, inset by half a stroke so the strokes stay
   coaxial. The X is the SAME mark at 45deg - do not draw a separate glyph.
   It is SIX BACKGROUND LAYERS, not two bordered boxes: Chrome FLOORS
   border-width to whole device pixels, so a 2px stroke asked for as
   calc(18px*.111) = 1.998 rendered 1px and the two halves fell 1px out of line.
   Background sizes are not floored. --mkr is the stroke's CENTRELINE radius. */
.mk-cross{font-size:0;display:inline-block;flex:none;width:var(--mk);height:var(--mk);
  --mkc:calc(var(--mkr) + var(--mkw)/2);
  background:
    linear-gradient(currentColor 0 0)
      calc(var(--mk)/2 - var(--mkw)/2) 0/var(--mkw) calc(var(--mk)/2 - var(--mkr)) no-repeat,
    linear-gradient(currentColor 0 0)
      calc(var(--mk)/2 + var(--mkr)) calc(var(--mk)/2 - var(--mkw)/2)/calc(var(--mk)/2 - var(--mkr)) var(--mkw) no-repeat,
    radial-gradient(circle at 100% 0,transparent calc(var(--mkr) - var(--mkw)/2),
      currentColor 0 calc(var(--mkr) + var(--mkw)/2),transparent 0)
      calc(var(--mk)/2 - var(--mkw)/2) calc(var(--mk)/2 - var(--mkr))/var(--mkc) var(--mkc) no-repeat,
    linear-gradient(currentColor 0 0)
      0 calc(var(--mk)/2 - var(--mkw)/2)/calc(var(--mk)/2 - var(--mkr)) var(--mkw) no-repeat,
    linear-gradient(currentColor 0 0)
      calc(var(--mk)/2 - var(--mkw)/2) calc(var(--mk)/2 + var(--mkr))/var(--mkw) calc(var(--mk)/2 - var(--mkr)) no-repeat,
    radial-gradient(circle at 0 100%,transparent calc(var(--mkr) - var(--mkw)/2),
      currentColor 0 calc(var(--mkr) + var(--mkw)/2),transparent 0)
      calc(var(--mk)/2 - var(--mkr)) calc(var(--mk)/2 - var(--mkw)/2)/var(--mkc) var(--mkc) no-repeat}
.g-x{opacity:0;transform:rotate(0deg)}
.menu-open .g-bars{opacity:0;transform:rotate(45deg)}
.menu-open .g-x{opacity:1;transform:rotate(45deg)}
/* the open state's X half-turns on hover - the reference's own close rule
   (`.btn-close:hover .wrap-cross{rotate(180deg)}` over .3s), the same turn
   the services sheet's X carries since 1 Sep. From the X's resting 45deg the
   half turn lands on 225. The selector outweighs `.menu-toggle__glyph span`
   so the transform gets the swap curve while the opacity keeps the crossfade. */
.menu-toggle__glyph .g-x{transition:opacity var(--ui-dur) var(--ease-out),transform .3s var(--ease-swap)}
@media(hover:hover) and (pointer:fine){
  .menu-open .menu-toggle:hover .g-x{transform:rotate(225deg)}
}
.menu-open .menu-toggle:focus-visible .g-x{transform:rotate(225deg)}
/* a square rotated 45deg: side s reads as a chevron s*root2 wide and half that
   tall, so .51em of --nav-fs gives the reference's 13 x 6 at 1920 */
/* THE CHEVRON ROLLS VERTICALLY ON HOVER. Measured on hover.mp4: the reference's
   own chevron leaves upward (its ink rows go 165-171, 164-170, 163-169, 161-167)
   while a twin arrives from below (170-176, 169-174, 167-173) and settles at
   166-172 - 10 frames, .3s. It is the drawn square still; the square now sits
   in a clipping window its own visible size, so one element can do both halves.
   The word "Services" beside it does not move. */
.svc-toggle__chev{font-size:0;position:relative;display:inline-block;overflow:hidden;
  width:calc(var(--nav-fs)*.721);height:calc(var(--nav-fs)*.361);
  --cs:calc(var(--nav-fs)*.51);--cw:max(1.5px,calc(var(--nav-fs)*.093))}
.svc-toggle__chev i{position:absolute;left:50%;top:0;width:var(--cs);height:var(--cs);
  border-right:var(--cw) solid currentColor;border-bottom:var(--cw) solid currentColor;
  transform:translate(-50%,-50%) rotate(45deg);transition:transform var(--ui-dur) var(--ease-out)}
.svc-open .svc-toggle__chev i{transform:translate(-50%,calc(-50% + var(--nav-fs)*.361)) rotate(225deg)}
@keyframes chev-roll{
  0%{transform:translate(-50%,-50%) rotate(45deg);animation-timing-function:ease-in}
  49.99%{transform:translate(-50%,-140%) rotate(45deg)}
  50%{transform:translate(-50%,40%) rotate(45deg);animation-timing-function:ease-out}
  100%{transform:translate(-50%,-50%) rotate(45deg)}
}
@media(hover:hover) and (pointer:fine){
  .svc-toggle:hover .svc-toggle__chev i{animation:chev-roll var(--ui-dur) linear both}
}
.svc-toggle:focus-visible .svc-toggle__chev i{animation:chev-roll var(--ui-dur) linear both}
.svc-open .svc-toggle__chev i{animation:none}
.head-actions{margin-left:auto;display:flex;align-items:center;gap:var(--nav-agap)}
.head-form{font-family:var(--ui);font-size:var(--nav-fs);font-weight:500;letter-spacing:-.01em;text-transform:none;position:relative;color:var(--bone);
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
/* The phone is a two-line block in a row of one-line items, so centring it puts
   the NUMBER 9px above everything else's baseline - measured, and visible in
   the band. The reference sits its number on the common baseline and lets the
   studio line hang below the mid-line, so the block drops by half the studio
   line's box. transform, not margin: the cluster's widths do not move. */
.head-tel{display:flex;flex-direction:column;line-height:1.2;text-align:right;transform:translateY(calc(var(--nav-sub)*.69))}
.head-tel a{font-family:var(--ui);font-size:var(--nav-fs);font-weight:500;letter-spacing:-.01em;text-decoration:none;color:var(--bone);position:relative;
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.head-tel span{font-size:var(--nav-sub);color:var(--bone-2);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
/* the pill's inside is the reference's too: 32px of side padding and a 79px
   run between the label and the plus at 1920, which is what makes it read as
   a wide pill rather than a button with an icon stuck to the word. */
/* THE PILL CONTRASTS ITS GROUND - THE REFERENCE'S OWN RULE (1 Sep). On its
   hero the reference's Book A Call is a LIGHT pill over the film, and on its
   dark pages it stays light; on light pages it is dark. Ours was ink-filled
   everywhere, so over dark sections it read as bare text (Jenil: "it doesn't
   look like a CTA anymore"). Base = bone fill + ink label, which is the hero
   (the pill sits over the film half from the first frame) and every dark
   ground; the light-tone rules (head-ink, is-on-light, the mobile band)
   flip it to ink fill below, beside the colour rules they already own. */
.head-book{font-family:var(--ui);font-size:var(--nav-fs);font-weight:700;letter-spacing:-.02em;text-transform:none;display:inline-flex;align-items:center;gap:var(--nav-pill-gap);
  background:var(--bone);color:var(--ink);border-radius:999px;height:calc(var(--nav-h) - 2*var(--nav-py));padding:0 var(--nav-pill-px);position:relative;overflow:hidden}
.head-book__plus{transition:transform var(--ui-dur) var(--ease-out)}
.head-book__plus,.g-x{--mk:calc(var(--nav-fs)*1.167);--mkw:max(1.5px,calc(var(--nav-fs)*.111));
  --mkr:calc(var(--nav-fs)*.24)}
.head-book span{position:relative;z-index:1}
/* THE PILL DOES NOT FILL. Measured on hover.mp4: across the whole hover its
   mean luminance moves 45.4 -> 49.4 of 255 - a bone fill would take it past
   200 - its MARK never moves (bbox x1808-1828 y159-178, ink 91px, identical in
   all 43 frames), and only the LABEL rolls: the old copy rises 163 -> 158 while
   its twin arrives from 195 -> 168 and settles, 8 frames = .27s, both clipped
   by the pill's own rounded box. Ours wiped a bone fill through, inverted the
   colour and spun the plus 90deg - three things the reference does not do. */
.hb-w{display:inline-block;overflow:hidden;vertical-align:bottom;line-height:inherit}
.btn .hb-w,.lab-faq__all .hb-w{line-height:1.25}
.hb-l{position:relative;display:block;transition:transform var(--roll-mark) var(--ease-swap)}
.hb-l::after{content:attr(data-roll);position:absolute;left:0;top:100%;white-space:nowrap}
@media(hover:hover) and (pointer:fine){ .head-book:hover .hb-l{transform:translateY(-100%)} }
.head-book:focus-visible{outline-offset:-3px}
.head-book:focus-visible::before{transform:scaleX(1);transform-origin:0 50%}
/* NO UNDERLINE ON THE HEADER LINKS. Measured on hover.mp4: over the whole
   "Patient form" hover the WORD's bbox and ink count are byte-identical in
   every frame and no underline row ever appears - the arrow beside it is the
   entire response. The phone number behaves the same way (only the chevron the
   reference has there moves, and ours has none by design). The menu overlay's
   rows carry the same arrow, so they answer the same way. */
/* over the open menu the film shadows read as blobs; the pill needs an edge */
body.menu-open .head-form,body.menu-open .head-tel a,body.menu-open .head-tel span,
body.menu-open .menu-toggle,body.menu-open .svc-toggle{text-shadow:none}
body.menu-open .head-book{border:1px solid rgba(234,232,233,.28)}
@media(max-width:999px){
  body:not(.legal) .menu-toggle,body:not(.legal) .svc-toggle{color:var(--ink-d);text-shadow:none}
  body.menu-open .menu-toggle,body.menu-open .svc-toggle{color:var(--bone)}
  .head-form,.head-tel{display:none}
  .site-head{padding:12px 20px}
  .brand{--wm-w:clamp(104px,28vw,124px)}   /* the phone row is brand + Menu + the pill on one line; this is what fits at 390 */
  .head-book{height:44px;padding:0 18px;gap:14px}
  /* the phone band is the light tone (ink text, above, legal excluded there
     too), so the pill is ink on it - and bone again on legal's dark band */
  body:not(.legal) .head-book{background:var(--ink);color:var(--bone)}
}
@media(min-width:1000px){
  /* the left controls sit on the panel: they ride the same handover var as
     the wordmark, so state 2 recolours them with everything else */
  .menu-toggle,.svc-toggle{color:var(--brand-c,var(--ink-d))}
  body:not(.legal) .menu-toggle,body:not(.legal) .svc-toggle{text-shadow:none}
  body.menu-open .menu-toggle,body.menu-open .svc-toggle{color:var(--bone)}
}

/* ---------- the services panel ---------- */
.svcpanel{position:fixed;inset:0;z-index:60;background:rgba(16,18,22,.22);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  opacity:0;visibility:hidden;transition:opacity var(--ui-dur) var(--ease-out),visibility 0s linear var(--ui-dur)}
.svcpanel.is-open{opacity:1;visibility:visible;transition:opacity var(--ui-dur) var(--ease-out)}
/* THE SHEET IS THE REFERENCE'S OWN, MEASURED ON ITS LIVE DOM AT 1920 (1 Sep,
   Jenil with the two side by side: "that bar is bigger than on calder. So
   match the sizing"). Its panel: bg rgb(234,232,232), radius 0 0 40 40, a
   12rem label column, then FOUR tiles of 202.7px (9.5rem) on a 42.7px (2rem)
   gap, labels 18.67px w500 rgb(66,67,70) sitting 21px under the pictures,
   the whole thing top:0 over the header. Its rem is W/90, so everything
   converts to vw exactly: tile 10.56vw, gap 2.22vw, label col 13.33vw,
   right pad 3.05vw, label 0.972vw, radius 2.083vw. Ours holds FIVE tiles at
   the same tile size and gaps, so the panel is 78.06vw against their 65.3vw,
   centred. The close sits at their 1.5rem/1.75rem inset with the site's own
   drawn mark at their 1rem box. */
.svcpanel__sheet{position:absolute;top:0;left:50%;transform:translate(-50%,-14px);
  width:min(78.06vw,calc(100vw - 2 * var(--nav-px)));
  background:var(--bone);color:var(--ink-d);
  border-radius:0 0 clamp(24px,2.083vw,40px) clamp(24px,2.083vw,40px);
  padding:2.24vw 3.05vw 3.33vw 13.33vw;transition:transform var(--ui-dur) var(--ease-out)}
.svcpanel.is-open .svcpanel__sheet{transform:translate(-50%,0)}
.svcpanel__close{position:absolute;left:1.67vw;top:1.94vw;font-family:var(--ui);
  font-size:clamp(13px,.972vw,18.67px);font-weight:500;background:none;border:0;cursor:pointer;color:var(--ink-d);
  display:inline-flex;gap:.28vw;align-items:center;padding:6px 2px}
/* the X is the site's drawn mark at the reference's 1rem box; ITS HOVER IS THE
   REFERENCE'S OWN HALF-TURN - `.btn-close:hover .wrap-cross{rotate(180deg)}`
   over .3s in its stylesheet. Our mark's X is the plus at 45deg, so the half
   turn lands on 225. */
.svcpanel__x{--mk:clamp(16px,1.111vw,21.4px);--mkw:max(1.5px,calc(var(--mk) * .0951));
  --mkr:calc(var(--mk) * .2057);transform:rotate(45deg);transition:transform .3s var(--ease-swap)}
@media(hover:hover) and (pointer:fine){
  .svcpanel__close:hover .svcpanel__x{transform:rotate(225deg)}
}
.svcpanel__close:focus-visible .svcpanel__x{transform:rotate(225deg)}
/* THE SHEET TILE'S HOVER IS A FILLED PANEL, NOT AN OUTLINE. Matched 29 Aug to
   the reference's own services sheet (Jenil, with the two side by side). What
   it does, and ours did not: the hovered tile gets a SOLID ink panel behind it
   that extends past the picture on all four sides and encloses the label; the
   label turns from graphite to BONE against it; and an ARROW appears after the
   last word. Ours drew a 3px ink ring at inset -6 and changed nothing else, so
   the tile read as selected rather than as lifted.
   The panel is the ::before, filled and at z-index -1 inside an isolated `a`,
   so it paints behind the picture and the label but above the sheet's bone.
   The arrow is the site's OWN `.ext` - the drawn 12x12-on-2px mark, which
   already rolls diagonally on hover under the one rule in the hover block - so
   nothing new is drawn and the grammar is the one every other link uses. It is
   `opacity:0` at rest because the reference shows it only on the hovered tile.
   THE GRID GAP WENT 16 -> 24 to make room: the panel reaches 12px past the
   tile on each side, so at a 16px gap two neighbouring panels would have left
   4px between them. At 24 they clear each other by 12. */
/* the reference's tiles are SQUARE at 10.56vw on a 2.22vw gap; the label is
   0.972vw w500 one gap-of-1.11vw under the picture. 50% 25% keeps the two
   portrait subjects' heads in the square crop, the same aim the mobile card
   band uses. */
.svcpanel__tiles{list-style:none;display:grid;grid-template-columns:repeat(5,1fr);gap:2.22vw}
.svcpanel__tiles a{display:block;position:relative;isolation:isolate;border-radius:var(--radius-tile);color:var(--ink-d)}
.svcpanel__tiles img{width:100%;height:auto;aspect-ratio:1;object-fit:cover;object-position:50% 25%;border-radius:var(--radius-tile);display:block;filter:grayscale(1)}
/* a > span, not span: .ext nests two bare spans of its own inside the label */
.svcpanel__tiles a>span{display:block;font-size:clamp(13px,.972vw,18.67px);line-height:1.13;font-weight:500;margin-top:1.11vw;
  transition:color var(--ui-dur) var(--ease-out)}
.svcpanel__tiles a .ext{opacity:0;transition:opacity var(--ui-dur) var(--ease-out)}
.svcpanel__tiles a::before{content:"";position:absolute;inset:-12px -12px -14px;z-index:-1;
  background:var(--ink);border-radius:calc(var(--radius-tile) + 9px);
  opacity:0;transform:scale(.96);transition:transform var(--ui-dur) var(--ease-out),opacity var(--ui-dur) var(--ease-out);pointer-events:none}
@media(hover:hover) and (pointer:fine){
  .svcpanel__tiles a:hover::before{opacity:1;transform:scale(1)}
  .svcpanel__tiles a:hover>span{color:var(--bone)}
  .svcpanel__tiles a:hover .ext{opacity:1}
}
.svcpanel__tiles a:focus-visible::before{opacity:1;transform:scale(1)}
.svcpanel__tiles a:focus-visible>span{color:var(--bone)}
.svcpanel__tiles a:focus-visible .ext{opacity:1}
@media(max-width:999px){ .svcpanel{display:none} .svc-toggle{display:none} }

/* ---------- the menu: 100svh dark overlay ---------- */
/* Desktop, measured against the reference: utility cluster in the left half,
   editorial navigation starting at x=752; Services label and page links at
   the 83px section scale; 140px thumbs on 32px gaps; 80px circular controls.
   The close control never moves - the trigger stays fixed at 23.26%. */
.menu{position:fixed;inset:0;z-index:55;background:radial-gradient(120% 90% at 30% 40%,#1A1C26 0%,var(--ink) 60%);
  visibility:hidden;opacity:0;transition:opacity .4s var(--ease-out),visibility 0s linear .4s;
  display:flex;align-items:stretch;padding:calc(var(--nav-h) + 5vh) 32px 6vh;overflow:auto}
.menu.is-open{opacity:1;visibility:visible;transition:opacity .4s var(--ease-out)}
.menu__util{align-self:flex-end;display:flex;flex-direction:column;gap:6vh;width:688px;flex:none}
.menu__circles{list-style:none;display:flex;gap:16px}
.menu__circ{position:relative;display:grid;place-items:center;width:80px;height:80px;border-radius:50%;
  border:1px solid rgba(234,232,233,.28);color:var(--bone-2);overflow:hidden;transition:color var(--ui-dur) var(--ease-out)}
.menu__circ svg{position:relative;z-index:1}
.menu__circ::before{content:"";position:absolute;inset:0;border-radius:50%;background:var(--bone);
  transform:scale(0);transition:transform var(--ui-dur) var(--ease-out)}
@media(hover:hover) and (pointer:fine){ .menu__circ:hover{color:var(--ink-d)} .menu__circ:hover::before{transform:scale(1)} }
.menu__circ:focus-visible{color:var(--ink-d)}
.menu__circ:focus-visible::before{transform:scale(1)}
.menu__rows{list-style:none;width:min(300px,80vw)}
.menu__rows li{border-top:1px solid var(--line)}
.menu__rows li:last-child{border-bottom:1px solid var(--line)}
.menu__rows a{display:flex;justify-content:space-between;align-items:center;padding:16px 2px;color:var(--bone-2);
  font-size:14px;font-weight:500;position:relative;transition:color var(--ui-dur) var(--ease-out)}
@media(hover:hover) and (pointer:fine){ .menu__rows a:hover{color:var(--bone)} }
.menu__main{margin-left:auto;display:flex;flex-direction:column;justify-content:space-between;gap:6vh;padding-left:32px;min-width:0}
.menu__svclabel{font-family:var(--serif);font-weight:400;font-size:var(--t-d2);line-height:.93;letter-spacing:-.02em;color:var(--bone);margin-bottom:4vh}
.menu__tiles{list-style:none;display:flex;gap:32px;flex-wrap:wrap;--menu-thumb:clamp(96px,7.29vw,140px)}
/* the tile is as wide as its thumb, so the LABEL wraps under it instead of
   setting the item width: "Veneers, Bonding & Whitening" is 186px of
   max-content against a 140px thumb, and five of those wrapped the row at
   1600 where four never did. */
.menu__tiles a{display:block;width:var(--menu-thumb);color:var(--bone-2)}
/* FIVE TILES HAVE TO SHARE THE ROW FOUR USED TO. The tile column measures
   656px at 1440 and 955 at 1920, so five 140px thumbs on the 32px gap (828)
   wrapped to a second row below ~1612 and pushed the page links off the
   bottom - measured, 52px of "Contact" clipped at 1440x900. 7.29vw lands on
   140.0 at 1920 (the measured reference size, unchanged) and on 105.0 at
   1440, which is exactly what fits: 5x105 + 4x32 = 653 of 656. Below 1440 it
   wraps, which is what four tiles already did there. */
.menu__thumb{display:block;width:var(--menu-thumb);height:var(--menu-thumb);overflow:hidden;border-radius:var(--radius-tile);background:#20222c}
.menu__thumb img{width:100%;height:100%;object-fit:cover;filter:grayscale(1);
  transform:scale(1);transition:transform var(--ui-dur) var(--ease-io)}
/* the reference's thumb hover: the image grows inside a fixed, clipping frame */
@media(hover:hover) and (pointer:fine){ .menu__tiles a:hover .menu__thumb img{transform:scale(1.1)} }
.menu__tiles a:focus-visible .menu__thumb img{transform:scale(1.1)}
.menu__tname{display:block;font-size:14px;font-weight:500;margin-top:10px;transition:color var(--ui-dur) var(--ease-out)}
@media(hover:hover) and (pointer:fine){ .menu__tiles a:hover .menu__tname{color:var(--bone)} }
.menu__tiles a:focus-visible .menu__tname{color:var(--bone)}
.menu__pages{list-style:none;display:grid;grid-template-columns:auto auto;gap:2vh 5vw;justify-content:start;margin-top:auto}
.menu__pages a{display:block;font-family:var(--serif);font-weight:400;font-size:var(--t-d2);line-height:1.02;letter-spacing:-.02em;color:var(--bone)}
/* the reference's large-link hover: two stacked copies roll upward over 800ms */
/* THE ROLL WINDOW MUST HOLD THE DESCENDERS. Instrument Serif at line-height
   1.02 puts its descenders 14.8px below the line box at 110px - 0.135em - so
   `overflow:hidden` sliced the g and the y off "Technology" and "Laboratory"
   at rest (Jenil, 24 Aug). The window takes .15em of padding and gives it
   straight back as margin, so nothing in the menu's layout moves; the exit
   travel grows by the same .15em so the outgoing copy still clears it. */
.roll{display:block;position:relative;overflow:hidden;padding-bottom:.15em;margin-bottom:-.15em}
.roll__w{display:block;transition:transform var(--roll-dur) var(--ease-roll)}
.roll__w+.roll__w{position:absolute;inset:0;transform:translateY(105%)}
@media(hover:hover) and (pointer:fine){
  .menu__pages a:hover .roll__w:first-child{transform:translateY(calc(-105% - .15em))}
  .menu__pages a:hover .roll__w+.roll__w{transform:translateY(0)}
}
.menu__pages a:focus-visible .roll__w:first-child{transform:translateY(calc(-105% - .15em))}
.menu__pages a:focus-visible .roll__w+.roll__w{transform:translateY(0)}
@media(max-width:999px){
  .menu{flex-direction:column;padding:96px 20px 6vh}
  .menu__util{order:2;width:100%;margin-top:6vh;gap:4vh}
  .menu__circles{gap:12px}
  .menu__circ{width:56px;height:56px}
  .menu__main{margin-left:0;padding-left:0}
  .menu__tiles{gap:16px;--menu-thumb:96px}
  /* THE PAGE LINKS COME FIRST ON A PHONE. Measured on ours at 390x844, the
     five service tiles pushed the page list to y=285 and cut "Contact" 15px
     below the fold - the primary navigation was the one thing you had to
     scroll for. Aventura's mobile menu puts its five page names at the top at
     display scale and hides its services behind a disclosure; ours keeps the
     tiles, but underneath. */
  .menu__pages{grid-template-columns:1fr;margin-top:0;order:-1}
  .menu__svc{margin-top:5vh}
}

/* ---------- 2 · the goal ---------- */
/* bone, 192px vertical padding; heading on the left gutter, everything else in
   the right half beginning at x=720; the reveal paragraph at the 83px scale
   over 688px. The section is meant to feel suspended - the empty left half is the
   composition, not a gap to fill. */
/* MEASURED OFF THE REFERENCE at 1920x914. Its goal section is a two-row grid,
   not a headline stacked above a column:
     row 1  [ the portrait  |  the aside + the chips ]
     row 2  [ "Our goal is" |  the reveal paragraph  ]
   which is why its headline sits LOW and starts the same line as the reveal -
   the two share row 2's top, so their first baselines agree. Ours had the
   headline in row 1 at the top left, a whole composition away from it, and the
   portrait tile landed on top of it.
   Its numbers, all of which this block reproduces: gutters 43 (the nav's, not
   the narrower --g), the grid FULL WIDTH rather than 1376 centred - the
   reference's headline is hard against the gutter at x=43 where ours started
   at 272 - column 2 opening at x=957 (= 50%), the portrait 325 wide (35.4% of
   the left column) with 132 (14.4%) to that column's right edge, and 53px
   between the portrait's bottom and the headline's cap. */
#goal{background:var(--bone);color:var(--ink-d);padding:192px var(--nav-px) 200px}
@media(max-width:999px){ #goal{padding:96px var(--g) 104px} }
#goal .goal__h,#goal .goal__reveal{color:var(--goal-ink)}
.goal__grid{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:auto auto;
  row-gap:clamp(36px,5.8vh,56px);column-gap:0;width:100%;align-items:start;position:relative}
.goal__h{grid-area:2/1;opacity:var(--goal-h-op,1);font-family:var(--serif);font-weight:400;font-size:var(--t-d2);line-height:.93;letter-spacing:-.02em}
/* an empty box: it reserves the portrait's starting frame in the column so the
   travelling copy can read its rect. Nothing paints here. The aspect is 0.76,
   not the reference's 0.678: below about 0.72 this photograph's loupe barrel
   touches the frame edge (verified by rendering the crop at 0.68/0.72/0.76/0.80),
   and the loupes not being cut is the whole point of the recut. */
.goal__slot{grid-area:1/1;justify-self:end;width:35.4%;aspect-ratio:.76;margin-right:14.4%}
.goal__introrow{grid-area:1/2}
.goal__reveal{grid-area:2/2}
.goal__introrow{display:flex;align-items:center;justify-content:space-between;gap:28px}
/* THE NOTE AND THE PORTRAIT ROW ARE THE REFERENCE'S OWN, measured on its home
   DOM at 1920 (1 Sep): paragraph 20px/400 on a 21px pitch in rgb(66,67,70) -
   1.0417vw, the same curve as the hero anchors - and four circles of 6.53vw
   (125.3px) on rgb(218,213,211), overlapping a quarter of their own diameter
   (step .746d), the row ending on the right gutter, the LEFT circle on top.
   Ours are the studio's three people (the card cut-outs, which sit on the
   --bone-2 circle exactly as they sit on the partner cards) and a serif "2"
   for the studios - the reference's own 46.7px Instrument Serif figure. */
.goal__aside{font-size:clamp(15px,1.0417vw,20px);font-weight:400;line-height:1.05;color:var(--goal-ink);max-width:30ch}
.goal__aside{order:1}
.goal__chips{list-style:none;display:flex;align-items:center;--chip:clamp(84px,6.53vw,140px)}
.goal__chips{order:2}
.goal__chips li{width:var(--chip);height:var(--chip);border-radius:50%;overflow:hidden;flex:none;background:var(--bone-2);
  position:relative;margin-left:calc(var(--chip) * -.254)}
.goal__chips li:first-child{margin-left:0}
/* the left circle sits on top, as the reference stacks its own */
.goal__chips li:nth-child(1){z-index:4}
.goal__chips li:nth-child(2){z-index:3}
.goal__chips li:nth-child(3){z-index:2}
.goal__chips li:nth-child(4){z-index:1}
.goal__chips img{width:100%;height:100%;object-fit:cover;object-position:50% 0}
.goal__chip--n span{display:grid;place-items:center;align-content:center;width:100%;height:100%;text-align:center}
.goal__chip--n b{font-family:var(--serif);font-weight:400;font-size:clamp(30px,2.43vw,46.7px);line-height:1;color:var(--goal-ink)}
.goal__chip--n i{font-style:normal;font-family:var(--ui);font-size:clamp(9px,.57vw,11px);font-weight:600;
  letter-spacing:.08em;text-transform:uppercase;color:#5F656D;margin-top:5px}
.goal__reveal{font-family:var(--serif);font-weight:400;font-size:var(--t-d2);line-height:.93;letter-spacing:-.02em;max-width:688px;padding-bottom:130px}
@media(max-width:999px){ .goal__reveal{padding-bottom:32px} }
/* the word dim is applied by JS (gsap.set) so no-JS and reduced motion read the paragraph in full */
/* ---------- the goal's exit: one picture travels, the type dims out ---------- */
/* Measured off the reference recording (av-sec2, 1920x914). Three things run
   together over the section's last stretch, and they are three separate layers
   because the reference keeps them separate:
     1. THE PICTURE grows and never blurs - it measured 3.80 -> 3.37 gradient
        (that is the dim, not a blur) while the type went 0.33 -> 7.9.
        It grows from the slot's frame to the services stage's 50vw x 100svh,
        and object-fit:cover is HEIGHT-driven throughout (the reference's
        content/box-height ratio held at 0.533 for the whole growth while the
        content/box-width ratio fell 0.797 -> 0.590), so the box may widen
        faster than it grows tall without the picture ever stretching.
     2. THE TYPE blurs. That is the "dark glow" - a blur pulls the sparse dark
        glyphs out into the light ground, so each letter gains a soft dark
        halo. Measured: ground 232 -> 138 -> 125 while the glyph cores went
        66 -> 95 -> 97, i.e. they converge, which a plain dim cannot do.
     3. THE GROUND goes to ink underneath. Measured opacity 0 at the section's
        bottom edge, .31 / .52 / .68 / .90 as it climbs, 1 by the handover.
   The picture sits ABOVE the dim (z 3 vs 2), which is why it keeps its light. */
/* THE GOAL HOLDS STILL WHILE THE SERVICES RISE OVER IT. Measured: over 138px
   of reference scroll the goal's type moved 0px (cross-correlation of the
   right column, best vertical shift +0) while the services' top edge climbed
   the viewport. So the section is not scrolling away - it is pinned by its
   BOTTOM (it is taller than the viewport, so bottom:0 is the sticky edge that
   holds its last screenful still) and the next section is pulled up over it.
   The pin's padding and the section's negative margin are equal and opposite,
   so the document is exactly as tall as it was. */
/* The whole travel is gated behind .travel-js, which the controller sets on
   <html>. Without it - no JS - the picture is a plain block in the column and
   the two sections simply follow one another, so nothing is pinned, covered or
   left stranded in a corner.
   The hold is a transform, not position:sticky, because sticky CANNOT pin a
   box taller than the viewport - verified in isolation: bottom:0 and a
   negative top both let a 1873px section run straight past (top -933 -> -1100
   -> -1500 -> -1900 against a 940px viewport). #goal is two viewports tall, so
   JS translates it down by exactly the scroll it should not have taken. The
   pin's padding and the section's negative margin are equal and opposite, so
   the document is exactly as tall as it was. */
.travel-scope{position:relative;z-index:0}
/* .is-covering is set by the hero timeline's matchMedia block ONLY - desktop
   + motion + JS, the one state in which the hero pin holds a viewport past
   the release. It pulls the goal up by exactly that viewport, so the bone
   ground slides over the hero's resting sentence (the reference's cover-exit)
   while the extra pin spacer and this margin cancel: the goal's document
   geometry, every later trigger start and the page height are unchanged.
   A bare margin here would break mobile, reduced motion and no-JS, none of
   which pin the hero - never move it into plain CSS. */
.travel-scope.is-covering{margin-top:-100svh}
.goal-pin{position:relative;background:var(--bone)}
#goal{position:relative;z-index:0}
/* NO z-index here on purpose: with a stacking context of its own, the whole
   section would sit under .goal__travel (z 5) and the travelling picture
   printed over the service title. Left at auto, the section still paints
   after #goal (tree order) while .svcs__titles can climb past the traveller. */
#services{position:relative}
.goal__travel{pointer-events:none}
.goal__pic{width:min(46vw,420px);aspect-ratio:1100/940;margin:0 auto 48px;overflow:hidden}
@media(min-width:1000px){
  .travel-js .goal-pin{padding-bottom:100svh}
  .travel-js #goal{will-change:transform}
  .travel-js #services{margin-top:-100svh}
  .travel-js .goal__travel{position:absolute;inset:0;z-index:5}
  .travel-js .goal__frame{position:sticky;top:0;height:100svh}
  .travel-js .goal__pic{position:absolute;margin:0;aspect-ratio:auto;
    left:var(--gp-l,0px);top:var(--gp-t,0px);width:var(--gp-w,230px);height:var(--gp-h,307px)}
}
/* Reduced motion gets the same shape as a narrow screen: no hold, no overlap,
   no growth - the picture is simply a block in the column. Without this the
   -100svh would still pull the services over a section that is no longer being
   held, and the goal's last screenful would be covered before it was read. */
@media(min-width:1000px) and (prefers-reduced-motion:reduce){
  .travel-js .goal-pin{padding-bottom:0}
  .travel-js #goal{will-change:auto;transform:none}
  .travel-js #services{margin-top:0}
  .travel-js .goal__travel{position:static;z-index:auto}
  .travel-js .goal__frame{position:static;height:auto}
  .travel-js .goal__pic{position:relative;left:auto;top:auto;margin:0 auto 48px;
    width:min(46vw,420px);height:auto;aspect-ratio:1100/940}
  .goal__h,.goal__introrow,.goal__reveal{filter:none}
  .goal__dim{display:none}
}
.goal__h,.goal__introrow,.goal__reveal{filter:blur(var(--goal-blur,0px));will-change:filter}
.goal__dim{position:absolute;inset:0;z-index:2;pointer-events:none;background:var(--goal-wash);opacity:var(--goal-dim,0)}
/* pinned to the WRAPPER, so it is still pinned when the services stage is.
   It is hidden the instant the stage pins with the same file at the same box -
   both are the identical picture at the identical rect, so the swap cannot be
   seen; before that instant it covers the un-pinned stage rising underneath. */
.goal__travel.is-handed{visibility:hidden}
/* and its counterpart: until the hand-over the stage's own first frame is
   hidden, or the same picture prints twice - the stage's copy already at
   full size behind the travelling one still growing in front of it */
@media(min-width:1000px){
  .travel-js .goal__travel:not(.is-handed) ~ #services .svcs__media img:first-child{visibility:hidden}
}
/* 22%, not 50%: the stage frame this picture becomes carries .is-high, and
   the two copies must be framed identically or the hand-over jumps at the
   widths where the stage box is wider than the picture (1920x900 is 1.067
   against its 0.90). */
.goal__pic img{width:100%;height:100%;object-fit:cover;object-position:50% 22%;filter:grayscale(1) contrast(1.04)}
@media(max-width:999px){
  .goal__grid{grid-template-columns:1fr;grid-template-rows:auto;row-gap:40px}
  .goal__h{grid-area:auto}
  .goal__slot{display:none}
  .goal__introrow{grid-area:auto;flex-wrap:wrap}
  .goal__reveal{grid-area:auto}
  /* NO PICTURE IN THE GOAL BLOCK ON A PHONE - IT WOULD PRINT TWICE.
     Since 29 Aug the picture that travels out of this section IS the first
     treatment's own picture, and on a phone there is no travel: the goal's
     260px copy and the first treatment card's full-bleed band landed back to
     back, the same portrait in the same pose twice in one screenful. The card
     keeps it, because that is where it means something. */
  .goal__travel{display:none}
  .goal__h,.goal__introrow,.goal__reveal{filter:none}
  .goal__dim{display:none}
}

/* ---------- 3 · services: one sticky composition ---------- */
/* Left: one stable 50vw x 100svh media stage, sticky. Right: the five panels
   in flow. The oversized title is a third grid layer spanning both columns,
   sticky with the stage, centred on the divide. Images hand over by
   opacity + clip + a 1.03 settle - no layout moves between services. */
#services{background:var(--ink);padding:0;overflow:clip}
.svcs{display:grid;grid-template-columns:1fr 1fr}
.svcs__stage{grid-area:1/1/2/2;position:sticky;top:0;height:100svh;align-self:start;overflow:hidden}
/* THE HAND-OVER IS A HARD EDGE, NOT A CROSS-FADE. Measured on the reference:
   through a whole switch the outgoing frame is pixel-identical and pinned
   (frame-to-frame difference 0.000, best vertical shift 0px) while a single
   hard boundary climbs from the viewport bottom to its top - rows 772, 753,
   742, 685, 598, 499, 428, 384, 360, 338, 280, 196, 98, 27, 0. Nothing is
   ever semi-transparent, which is why the reference never double-exposes.
   So: every frame is opaque and fully painted; the incoming one is revealed
   from the bottom by its own top inset, and paints over the one before it
   because it is later in the stack. --svc-wipe is scrubbed per frame in JS.
   Frame 0 carries no wipe - the goal section hands it over already whole. */
.svcs__media{position:absolute;inset:0;background:var(--ink)}
.svcs__media img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;filter:grayscale(1);
  clip-path:inset(calc(var(--svc-wipe,1) * 100%) 0 0 0);will-change:clip-path}
.svcs__media img:first-child{--svc-wipe:0}
/* two frames are portraits of a person and the stage box runs from 0.71
   (1280x900) to ~1.34 (a short, wide window), so a centred cover crop
   takes the top of a head off at the wide end. 22% keeps the heads. */
.svcs__media img.is-high{object-position:50% 22%}
/* the nav corner needs a ground on the pale images (svc-smile lower-left
   measured 216/255 - bone 14px text dies there); a local gradient is the
   grade-for-the-image answer, never a whole-frame darken */
.svcs__stage::after{content:"";position:absolute;left:0;right:0;bottom:0;height:32%;z-index:1;pointer-events:none;
  background:linear-gradient(to top,rgba(16,18,22,.68),rgba(16,18,22,0))}
.svcs__nav{position:absolute;left:var(--nav-px);bottom:clamp(31px,2.14vw,41px);z-index:2}
/* THE CORNER INDEX IS THE REFERENCE'S OWN SET, MEASURED AT 1920 (24 Aug).
   Ours ran 12px over 14px on a 1.7 leading: same 23.7px row pitch as the
   reference, but with the type a third too small inside it, so the block read
   as small text floating in air where the reference's nearly fills its rows.
   The reference: label and items BOTH render a 15px cap (= 20.5px on Inter
   Tight), the rows pitch 23.7px (line-height 1.155), the block starts at
   x=43 (--nav-px, not 32) and its last baseline sits 46px off the viewport
   bottom, and label -> first item is 67px baseline to baseline. Stem widths
   measured 2.0px on the label and 2.0px on the ACTIVE item and thinner on the
   rest, so the active row carries the weight, not just the colour. */
.svcs__nav p{font-size:var(--svc-list);font-weight:600;letter-spacing:-.01em;margin-bottom:39px;color:var(--bone-2);
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.svcs__nav ol{list-style:none;font-size:var(--svc-list);font-weight:500;letter-spacing:-.01em;line-height:1.155;
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.svcs__nav li{color:var(--muted);transition:color var(--ui-dur) var(--ease-out)}
.svcs__nav li.is-active{color:var(--bone);font-weight:600}
.svcs__titles{grid-area:1/1/2/3;position:sticky;top:0;height:100svh;align-self:start;z-index:6;pointer-events:none}
/* The titles do NOT ride the wipe's edge - they fade, on a schedule that never
   lets two of them be legible at once. A shared edge is wrong here: these are
   two-line blocks sitting on the same two lines, so clipping the outgoing one
   to the top band and the incoming one to the bottom band prints line 1 of the
   old over line 2 of the new - literally "Smile / Whitening". The reference
   fades instead, and fast: measured across a switch, the outgoing title is
   gone by 45% of the boundary's travel and the incoming one only starts there
   (full at 35%, gone at 45%, new title ~10% at 45%, bright by 80%). --svc-op
   is that schedule, scrubbed in JS. */
/* Size and placement are the reference's, measured: its "Restorative" is 720px
   of ink at 1920, which is Instrument Serif at ~145px = 7.55vw - ours ran at
   --t-d1 (204px), 40% larger, and that alone pushed it into the copy. Both
   lines are CENTRED on the divide with no stagger: its "Restorative"/"Dentistry"
   centre on 974/965 and its "Esthetic"/"Dentistry" on 898/975 - the apparent
   offset is only the two words being different lengths. The +/-9vw stagger we
   had was ours, and it threw the second line 173px further right, straight
   into the panel. */
.svcs__titles p{position:absolute;left:50%;bottom:4svh;transform:translateX(-50%);width:100%;text-align:center;
  /* THE LEADING HAS TO CLEAR AN ITALIC DESCENDER. At .86 the italic p of
     "Implants" and the g of "Planning" ran straight into the dot of the i in
     "Alignment" and the ascenders of "Aftercare" - measured, those two pairs
     had NO gap at all between their ink bands while Smile/Design had 19px
     (Jenil, 25 Aug). The reference's own two lines sit on a 163px pitch at a
     145px size - line-height 1.12 - and leave a 16px gap; 1.04 lands our worst
     pair on 13px, which is the same air with a face whose ink is shorter. */
  font-family:var(--serif);font-weight:400;font-size:clamp(48px,7.55vw,168px);line-height:1.04;letter-spacing:-.03em;color:var(--bone);
  opacity:var(--svc-op,0);will-change:opacity;
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.svcs__titles p:first-child{--svc-op:1}
/* THE REFERENCE SETS ITS SERVICE TITLE IN TWO STYLES: line 1 ITALIC, line 2
   roman - Preventive/Care, Restorative/Dentistry. Ours ran both roman, which
   is the difference Jenil could see between the two stages (25 Aug). */
.svcs__titles p span{display:block;white-space:nowrap}
.svcs__titles p span:first-child{font-style:italic}
/* THE PANEL'S COPY SITS FAR RIGHT AND HOLDS STILL - that is what stops the
   display title running straight through it. Measured on the reference at
   1920: its copy starts at x=1360, i.e. inset 400 from the 960 divide (41.7%
   of the column) and running to 1872, and it occupies rows 41..399 of the
   viewport in every one of its services - the same rows each time, so it
   is pinned, not scrolling. Ours started 64px past the divide and was centred
   in a 812px panel, so the copy drifted through exactly the band the title
   occupies. The panel is now a viewport tall with the copy sticky in its upper
   third, and the title's widest word clears the copy's left edge. */
.svcs__info{grid-area:1/2/2/3;min-width:0}
/* the panel opens with the reference's own 41px of air above its label. It is
   real top padding, not the sticky offset: the label is 40-41px below the
   section's top edge THROUGHOUT its climb (measured at four frames: bound 891
   / label 874, 763 / 803, 658 / 699, 561 / 601), where ours started level with
   that edge and read as stuck to it. --nav-px is 43/32, within 2px of it. */
.svcs__panel{min-height:100svh;padding:clamp(27.5px,1.91vw,36.7px) var(--nav-px) 0 41.7%;position:relative}
/* THE LAST PANEL IS HALF A VIEWPORT TALLER, BECAUSE ITS FRAME HAD NOWHERE TO REST.
   The wipe reveals frame k from the bottom (clip-path insets from the TOP, so an
   unfinished wipe shows .svcs__media's own ink ground as a black band across the
   top of the picture). w[k] reaches 0 when panel k's top reaches the viewport
   top, and the next wipe only starts half a viewport later - so every frame gets
   450px of rest at a 900 viewport, fully revealed with the stage still covering
   the screen. Every frame except the last: the stage un-sticks when #services'
   bottom reaches the viewport bottom, which is the SAME instant panel 5's top
   reaches the viewport top. Measured at 1440x900 - wipe completes at scrollY
   4524 / 6324 / 7224 / 8124 / 9024, rest 450 / 450 / 450 / 450 / **30**, and the
   stage was last fully covering the viewport at 9024. So the picture finished
   revealing exactly as the section began to leave, and in practice it read as a
   black band that never cleared (Jenil, 29 Aug, with two screenshots).
   50svh of extra panel is the 450px, so the last frame now rests exactly as long
   as the other four. The panel is extended rather than #services padded, because
   .svcs__body is sticky INSIDE the panel - padding the section would let the last
   panel's copy slide up and away at full opacity while the picture rested, and a
   block sliding at full opacity is the slip --svc-body-op exists to stop.
   Mobile is reset below, where the stage does not exist at all. */
.svcs__panel:last-child{min-height:150svh}
/* the copy carries the SAME schedule as its title, so two services can never
   be read at once - the reference dips its panel to 45% at the crossover and
   brings it back, and with two blocks in flow at different heights anything
   less than a full hand-over leaves both legible */
/* MEASURED ON THE REFERENCE at 1920: its label is ~18px with no tracking,
   100px of air under it; its paragraph runs 3 lines on a 29px pitch (~23px
   on 1.26) across 506px; its list rows are 55px on ~18px text; its
   thumbnail is 216x331. Ours ran 12 / 20-on-1.2 / 14 in 43px rows with a
   128x154 tile - a whole step down across the board. Seated a little lower
   than the reference's 41 as well, at Jenil's ask, so the label clears the
   header band instead of sitting under it. */
.svcs__body{position:sticky;top:9svh;display:flex;flex-direction:column;
  opacity:var(--svc-body-op,var(--svc-op,0));will-change:opacity}
/* thumbnail BESIDE the list, as the reference sets it - stacked, the copy
   block ran 676px against the reference's 358 and was pushed off the top of
   the viewport long before its fade began */
.svcs__row{display:flex;align-items:flex-start;gap:24px}
/* the call to action is not part of the copy block: the reference pins it
   near the viewport bottom, right-aligned with the copy */
/* THE LEARN-MORE BUTTON MUST NOT TRAVEL UP THE PANEL. A sticky box cannot be
   pinned below its containing block's bottom edge, and the panel is exactly
   100svh with the button as its last child - so the pin held for only 43px of
   scroll and then the button rode the panel's bottom edge straight up into its
   own link list (Jenil, 24 Aug, with screenshots of it sitting on "Written
   plan" and on "Review visits"). The button now lives in an absolutely
   positioned wrapper that reaches 100svh PAST the panel, so the pin lasts the
   whole panel and a viewport more; --svc-op has taken it to 0 long before. */
.svcs__ctaw{position:absolute;left:41.7%;right:var(--nav-px);top:0;bottom:-100svh;
  display:flex;justify-content:flex-end;align-items:flex-start;pointer-events:none}
.svcs__panel .svcs__cta{position:sticky;top:calc(100svh - var(--btn-h) - var(--nav-px));display:flex;width:max-content;pointer-events:auto;
  opacity:var(--svc-op,0);will-change:opacity}

.svcs__panel:first-child{--svc-op:1;--svc-body-op:1}
.svcs__name{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
/* the reference's own vertical set at 1920: label cap 13 (= 18px, --nav-fs),
   then 100px of air to the paragraph, the paragraph 3-4 lines on a 29px pitch,
   then only 15px to the tile-and-list block. Ours ran 50 and 40 - the air was
   in the wrong place, half of it above the paragraph and too much below. */
.svcs__kicker{font-size:var(--nav-fs);font-weight:600;letter-spacing:0;color:var(--bone-2);margin-bottom:clamp(49px,4.53vw,87px)}
.svcs__intro{font-family:var(--ui);font-size:clamp(18px,1.2vw,23px);font-weight:600;line-height:1.26;color:var(--bone);margin-bottom:clamp(11px,.78vw,15px)}
/* NO THUMBNAIL IN THE COPY COLUMN ON DESKTOP - THE PICTURE WAS THE SAME PICTURE.
   The reference pairs each stage frame with a DIFFERENT detail shot in its copy
   column (Jenil, 29 Aug, with four of its panels). Ours could not: the tile was
   a crop of the stage's own source, so the left half and the right half showed
   one photograph twice, which is worse than showing one.
   Every asset on disk and in `_incoming` was searched for five distinct detail
   frames, and judged AS THE TILE RENDERS - 112-140px wide, aspect .65, under
   `filter:grayscale(1)`, which is where a subject that separates only by colour
   dies. Only two of the five families could be filled at all, and each of those
   two repeated a picture the site already carries: Smile Planning would have put
   a SECOND panoramic radiograph on a page whose film bridge already has one, and
   Veneers would have used the same bench photograph as `calder-bench.webp` and
   `bench-dark.webp` in the laboratory rail - which the Implants family
   independently picked as well, so two panels would have collided. Clear
   Alignment and Ongoing Care had nothing: the pool holds no clear aligner, no
   retainer and no review-visit detail, and the one frame that reads as a
   retainer at preview size resolves at native resolution into a denture with two
   threaded implant screws in its acrylic - the wrong family and a rule-3 risk.
   So the thumbnail is gone from the desktop composition and the list now runs
   the full copy column, flush with the label, the paragraph and the button,
   which is the site's own grammar. THE FIGURE STAYS IN THE MARKUP AND STAYS
   VISIBLE BELOW 1000, where it is the mobile card's full-bleed picture and is
   the only picture a phone gets - that is a different design and it is approved.
   If a real detail set ever arrives (an aligner, a retainer, a review visit),
   restore this block; the geometry below 1000 does not need to change. */
.svcs__tile{display:none}
.svcs__items{list-style:none;width:100%}
.svcs__items li{border-top:1px solid var(--line)}
.svcs__items li:last-child{border-bottom:1px solid var(--line)}
.svcs__items a{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:10px 2px;
  font-size:var(--svc-list);font-weight:500;letter-spacing:-.01em;color:var(--bone-2);position:relative;transition:color var(--ui-dur) var(--ease-out)}
.svcs__items a::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:1px;background:currentColor;
  transform:scaleX(0);transform-origin:100% 50%;transition:transform var(--ui-dur) var(--ease-out)}
@media(hover:hover) and (pointer:fine){ .svcs__items a:hover{color:var(--bone)} .svcs__items a:hover::after{transform:scaleX(1);transform-origin:0 50%} }
.svcs__items a:focus-visible::after{transform:scaleX(1);transform-origin:0 50%}
.svcs__items{flex:1;min-width:0}
@media(max-width:999px){
  .svcs{grid-template-columns:1fr}
  /* no long pin on narrow screens: the stage becomes a dominant stacked block
     that keeps responding as the panels pass */
  /* THE STAGE IS GONE ON A PHONE - EACH TREATMENT CARRIES ITS OWN PICTURE.
     A sticky 56svh band could only ever show ONE frame here (the wipes are
     cleared below 1000), so five treatments shared one picture, and the panels
     scrolled over it. Aventura's own mobile site does not keep its stage
     either: measured off av-mob.mp4 at 384x848, each of its services is a
     single full-width card - a photograph band about 300px tall, then the
     display title, a short paragraph and a Learn More pill. Ours is that card,
     with one departure: its copy is CENTRED and ours stays flush left, because
     centred type on this site is reserved for three named set-pieces. */
  .svcs__stage{display:none}
  .svcs__titles{display:none}
  .svcs__info{grid-area:auto}
  .svcs__panel{min-height:0;padding:0 0 clamp(56px,9vw,88px);
    display:flex;flex-direction:column}
  /* no stage on a phone, so no wipe and nothing to rest - undo the desktop tail */
  .svcs__panel:last-child{min-height:0}
  /* display:contents hoists the copy out of its two wrappers so the picture can
     be ordered above the heading without moving anything in the markup */
  .svcs__body{display:contents}
  /* THE COPY SCROLLS OVER THE STICKY STAGE, SO IT NEEDS A GROUND OF ITS OWN.
     Without one the stage's picture AND its corner index printed straight
     through the panel text at 390 - the treatment names appeared twice, once
     as the list and once as the index behind it. Pre-existing: four panels
     did exactly the same. */
  .svcs__info{position:relative;z-index:1;background:var(--ink)}
  /* the picture band: full bleed, no radius, at the head of its own card.
     object-position 25% because the tile is a 0.857 portrait in a ~1.2 box and
     a centred crop takes the top of a head off on the two portrait frames. */
  .svcs__tile{order:-1;display:block;width:100%;height:38svh;min-height:240px;
    margin:0 0 clamp(24px,5vw,36px);overflow:hidden;border-radius:0}
  .svcs__tile img{width:100%;height:100%;object-fit:cover;object-position:50% 25%;
    filter:grayscale(1)}
  .svcs__name,.svcs__kicker,.svcs__intro,.svcs__items,.svcs__ctaw{padding-inline:var(--g)}
  .svcs__name{order:0}
  .svcs__kicker{order:1}
  .svcs__intro{order:2}
  .svcs__items{order:3}
  .svcs__ctaw{order:4}
  /* the CTA's wrapper is the thing that has to come out of absolute flow: it
     is pinned at top:0 / left:41.7% of the panel for the desktop pin, so on a
     phone the pill printed across the panel's own heading. Pre-existing. */
  .svcs__ctaw{position:static;inset:auto}
  .svcs__panel .svcs__cta{position:static;margin:32px 0 0;opacity:1}
  .svcs__row{display:contents}
  .goal__travel{background:var(--bone)}
  .svcs__name{position:static;width:auto;height:auto;clip-path:none;white-space:normal;overflow:visible;
    font-family:var(--serif);font-weight:400;font-size:clamp(34px,9vw,48px);line-height:.95;letter-spacing:-.02em;color:var(--bone);margin-bottom:22px}
}

/* ---------- the standard button: 158x48, label + plus, fill wipe ---------- */
/* THE BUTTON IS FILLED AT REST, AND IT IS THE REFERENCE'S SIZE. Its "Learn More"
   is a 211 x 63 pill in full bone rgb(234,232,233) with ink type - ours was a
   158 x 48 outline in bone, less than three quarters the size and the opposite
   tone. Measured at 1920: label 18px w700 at 31px inside the left edge, 35px of
   air, a 20 x 20 mark on a 2px stroke, 33px to the right edge. */
.btn,.lab-faq__all{display:inline-flex;align-items:center;gap:var(--btn-gap);height:var(--btn-h);padding:0 var(--btn-px);
  border:0;border-radius:999px;font-family:var(--ui);font-size:var(--btn-fs);font-weight:700;letter-spacing:-.01em;
  background:var(--bone);color:var(--ink-d);
  position:relative;overflow:hidden;width:max-content;z-index:0;cursor:pointer}
.btn>span,.lab-faq__all>span{position:relative;z-index:1}
.btn>.mk-cross,.lab-faq__all>.mk-cross{--mk:var(--btn-mk);--mkw:max(1.5px,calc(var(--mk) * .0951));
  --mkr:calc(var(--mk) * .2057);margin-left:0}
/* THE BUTTON DOES NOT WHITE OUT AND IT DOES NOT BLACK OUT. It carried a bone
   fill wipe that inverted it on hover, and #planning's copy of it went one worse
   - it set `color:var(--bone)` on a BONE ground, so on the planning section the
   label AND the mark simply vanished and left an empty pill (Jenil, 24 Aug, with
   a screenshot). The reference's pill moves its mean luminance 45.4 -> 49.4 of
   255 across a whole hover: only the label rolls. Same answer here, on both. */
@media(hover:hover) and (pointer:fine){ .btn:hover .hb-l,.lab-faq__all:hover .hb-l{transform:translateY(-100%)} }
.btn:focus-visible,.lab-faq__all:focus-visible{outline-offset:-3px}
/* on bone grounds the fill inverts - the reference's own white section sets its
   Book A Call the same way round */
#planning .btn{background:var(--ink);color:var(--bone)}

/* ---------- 4 · the film: a cinematic breath ---------- */
/* Full-bleed, poster up immediately, a slow 1.00-1.03 drift under scroll and
   nothing else - the long frame-by-frame scrub is gone. ~1,200px at 1440x900. */
#film{background:var(--ink-2);padding:0;position:relative;clip-path:inset(0)}
.film-frame{position:relative;height:clamp(520px,133svh,1250px);overflow:hidden}
.film-video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center;will-change:transform;
  filter:grayscale(.35) saturate(.7) contrast(1.08) brightness(.86)}
.film-frame::after{content:"";position:absolute;inset:auto 0 0;height:28%;z-index:1;pointer-events:none;
  background:linear-gradient(to top,rgba(16,18,22,.48),rgba(16,18,22,0))}
/* THE LABELS SIT 100px UNDER THE WORD'S INK, AND THE MIDDLE ONE IS CENTRED ON
   THE FRAME. Measured on av-sec3 at 1920: the reference's word ink is 148px
   tall and its "Faster" row starts 107, 101, 99, 94 below the word's ink
   bottom through the crossing - call it 100. Ours ran 14, so the labels were
   jammed into "digitally"'s descenders (Jenil, 24 Aug, with the screenshots).
   Our own word ink is 149 tall and starts 4 below its line box, so the labels
   belong at 1.235em of --t-d1 under that box, not .88.
   And the row is a GRID, not space-between: with three items of unequal width
   space-between leaves the middle one off-centre (ours sat at 46% of the frame
   where the reference's "Modern Dentistry: / Smarter" is dead centre). */
.film-labelw{position:absolute;left:0;right:0;
  top:calc(100% + var(--cross-drop) - var(--cross-lift) + var(--t-d1) * 1.235);
  height:calc(var(--cross-lift) + var(--cross-lineh));
  z-index:2;padding-inline:var(--g);pointer-events:none}
.film-labels{list-style:none;position:sticky;margin-inline:calc(var(--nav-px) - var(--g));
  top:calc(var(--cross-top) + var(--t-d1) * 1.235);
  display:grid;grid-template-columns:1fr auto 1fr;align-items:start;gap:16px;
  font-size:var(--nav-fs);font-weight:700;line-height:1.13;color:var(--bone);
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.film-labels li:nth-child(2){justify-self:center;text-align:center}
.film-labels li:nth-child(3){justify-self:end;text-align:right}
/* 18px at 1920, measured on the reference's own three labels: ink height 15px,
   "Faster" 49px wide at x=44 and "Pain-Free" ending at 1876 - the same gutter
   the nav uses. Ours were set at a flat 15px and read a step small beside them. */
@media(max-width:999px){
  /* no crossing below 1000: the labels go back to the frame's own bottom */
  .film-labelw{position:static;height:auto;padding-inline:0}
  .film-labels{position:absolute;left:var(--g);right:var(--g);margin-inline:0;top:auto;bottom:32px;
    grid-template-columns:1fr;gap:8px}
  .film-labels li:nth-child(2),.film-labels li:nth-child(3){justify-self:start;text-align:left}
}

/* ---------- 5 · planned digitally: THE CROSSING + the index ---------- */
/* "Planned digitally" crosses the film's bottom edge - bone above it on the
   picture, ink below it on the bone ground - exactly as the reference crosses
   "Technology-Driven" onto the white where the rest of its sentence rests.
   The two halves are SEPARATE ELEMENTS in the two sections, each pinned to the
   same viewport line and each clipped by its OWN section's real box:
     #film{clip-path}     clips the bone half at the film's bottom edge
     #planning{clip-path} clips the ink half at the planning section's top edge
   Those are the same edge from opposite sides, so the halves always tile the
   line exactly. No JS, no scrub, nothing to fall a frame behind - which is what
   killed the old scrub-synced version of this twice (it doubled the word).
   The lift is what lets the ink half be pinned BEFORE its section reaches the
   pin line: without it the ink half would sit at the section's top edge and the
   two halves would print 60svh apart during the approach. #planning is
   flow-root so that negative margin cannot collapse out through the section. */
/* --cross-drop is where the held line COMES TO REST inside the bone section, and
   it is the whole point of the slot: measured on the reference at 1920x919 its
   crossing word settles with its ink 78px below that section's top edge (constant
   from the frame the section catches up), its second line at 292 and its third at
   456 - and those two never move relative to the section, so the bone opens EMPTY
   and they ride in with it. --cross-lift is the room ABOVE the slot that the held
   line borrows while it waits, and it is what sets when the line arrives, not how
   far it travels (that is always viewport-bottom to --cross-top).
   --cross-drop is set against --t-d1, not in svh: the reference's crossing block
   scales with WIDTH (every figure it prints at 1920 is 1.333x its 1440 set), so
   .382em of the display size reproduces its 78 at 1920 and 58 at 1440. */
:root{ --cross-top:44svh; --cross-lift:62svh; --cross-drop:calc(var(--t-d1) * .382);
       --cross-lineh:calc(var(--t-d1) * .8); }
/* the bottom air is the reference's own rhythm under its settled block -
   measured on av-sec3 f8 at 1920: "Results" ink bottom 653, its next content
   opens at 810 = 157px of air under the ink. Ours prints its last baseline
   12px above the flow bottom (lh .8, no descenders), so the padding is
   157-12 = 145 = .71 of the 204px display size - measured back by pixel
   scan: 157px of ink air at 1920. The flat 320px this replaces was the
   spacing to the removed planning index and left half a viewport of dead
   bone (Jenil, 3 Sep, with the crop). */
#planning{background:var(--bone);color:var(--ink-d);position:relative;padding:0 var(--g) calc(var(--t-d1) * .71);
  clip-path:inset(0);display:flow-root}
@media(max-width:999px){ #planning{padding-bottom:120px} }
/* THE BONE HALF TRAVELS IN FROM THE BOTTOM OF THE VIEWPORT - it does not just
   appear on the pin line. Measured on the reference (av-sec3, 1920x919):
   "Technology-Driven" first shows with its BOTTOM on the viewport's bottom edge
   (frame 53, top 772 -> 54, top 710 -> 55, 646 -> 57, 586), rises about 350px,
   and only then holds while the film's bottom edge sweeps up THROUGH it
   (bound 891 -> 409 against a word that moved 586 -> 357). Its three labels
   move with it to the pixel (both -43px between frames 55 and 56), so they ride
   the same layer. Ours was position:fixed on the pin line and so was revealed
   in place by the film's own top edge instead of arriving.
   .cross-fix is absolutely positioned against #film's bottom edge and reaches
   96svh PAST it, so its sticky children can stay pinned right through the
   crossing - a sticky child cannot be pushed below its containing block, and a
   wrapper that ended at the film's bottom would release the bone half exactly
   when the boundary reached it. Both halves are position:sticky at the SAME
   --cross-top with the SAME natural top (the boundary minus --cross-lift), so
   they are identical at every scroll position by construction - still no JS. */
.cross-fix{position:absolute;left:0;right:0;
  top:calc(100% + var(--cross-drop) - var(--cross-lift));height:calc(var(--cross-lift) + var(--cross-lineh));
  z-index:2;padding-inline:var(--g);pointer-events:none}
.plan-mega--bone{position:sticky;top:var(--cross-top)}
.plan-cross{position:relative;margin-top:var(--cross-drop)}
/* the slot: one line box of flow, --cross-lift of room above it. The held line is
   sticky INSIDE it, so it renders at clamp(natural, --cross-top, slotBottom - 1 line)
   = it rides up with the page, holds on the crossing line while the edge sweeps
   through it, then settles into the slot. Nothing is computed; it is one sticky. */
.pm-slot{display:block;margin-top:calc(-1 * var(--cross-lift));height:calc(var(--cross-lift) + var(--cross-lineh));
  margin-bottom:calc(var(--t-d1) * .25)}   /* the reference puts 50px more between its
  crossing line and the rest of the sentence than between lines 2 and 3 - 226->292
  against 440->456 - which is what makes its block breathe under the held line */
.pm-l1{position:sticky;top:var(--cross-top)}
/* THE THREE LINES SIT THE WAY THE REFERENCE'S DO, measured on av-sec3 f8 at
   1920 (Jenil, 3 Sep: "correct the spacing and positioning here" - ours ran
   left / centre / right-stepped in a 1376 wrap, a composition the reference
   never had): its crossing word is CENTRED (ink centre 962 of 1920), its
   second line is SPREAD GUTTER TO GUTTER - "Dentistry" from x48, "for
   Exceptional" ending 1880 - and its third is centred again (965). So the
   block is full-width now (the wrap cap put line 1 at x272), line 1 centres
   by text-align (one rule, both copies - the halves stay identical by
   construction), line 2 is a space-between flex row (the em and the
   anonymous text item spread to the box's edges), and line 3 self-centres. */
.plan-mega{display:flex;flex-direction:column;width:100%;margin-inline:auto;
  font-family:var(--serif);font-weight:400;font-size:var(--t-d1);line-height:.8;letter-spacing:-.03em;pointer-events:none}
.plan-mega--bone{color:var(--bone);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.plan-mega--ink{color:var(--ink-d)}
.pm-l1{display:block;text-align:center}
.plan-mega--bone .pm-l1{position:static}   /* the bone half's own <p> is the sticky one */
.pm-l2{display:flex;justify-content:space-between}
.pm-l3{display:block;align-self:center}
:root{
       --pi-title:clamp(32px,3.82vw,73.3px);
  --st-name2:clamp(26px,2.43vw,46.7px);
  /* the reference's about page, all measured at 1920 and divided by 19.2 */
  --ab-mega:clamp(58px,28.23vw,542px);--ab-belief:clamp(30px,5.766vw,110.7px);
  --ab-band:clamp(64px,19.17vw,368px);--ab-note:clamp(17px,1.391vw,26.7px);
  --ab-small:clamp(13px,0.833vw,16px);--ab-nav:clamp(14px,0.974vw,18.7px);
  --ab-dur:.35s;--ab-ease:ease-in-out;
  /* --team-fs IS RE-MEASURED WHENEVER THE TEAM LINE'S WORDING CHANGES. The ink is
     a constant multiple of the font-size and the multiple belongs to the STRING,
     so the vw that lands 93.2% dies the moment the words do. "The people you'll
     meet" set 6.90x and took 13.5vw; "The people behind Calder" (29 Aug) sets
     7.949x, so at 13.5vw it filled 107.3% and was being clipped by #team's own
     overflow. 93.18 / 7.949 = 11.72vw. The 259px cap now binds at 2210 rather
     than 1918, so the share holds further out than it used to. */
  --team-fs:clamp(40px,11.72vw,259px); }
@media(max-width:999px){
  /* the crossing is a wide-screen composition: below 1000 the bone half is gone
     and the sentence simply opens the section on bone */
  /* the labels live inside .cross-fix now, so the layer stays - it just stops
     being a layer: static, no height of its own, and the bone half is dropped */
  .cross-fix{position:static;height:auto;padding-inline:0}
  .cross-fix .plan-mega--bone{display:none}
  #film{clip-path:none}
  .plan-cross{margin-top:0}
  .pm-slot{margin-top:0;height:auto;margin-bottom:0}
  .pm-l1{position:static}
  .plan-mega{padding-top:64px}
  .pm-l1{text-align:left}
  .pm-l2{display:block}
  .pm-l2,.pm-l3{align-self:auto;padding-right:0}
}

/* ---------- 6 · one clinician ---------- */
/* The reference's theatrical scale on a single-clinician truth: deep air, the
   276px line, the silhouette wider than the viewport, one circle of restrained
   geometry, one statement on the lower grid edge. No name, no caption - ever. */
.experts__figure{margin:calc(var(--t-giant) * -.3) auto 0;width:min(1240px,104vw);position:relative;z-index:1;will-change:transform}
.experts__figure img{width:100%;height:auto;display:block;filter:grayscale(1)}
@media(max-width:999px){ .experts__figure{width:100%} }

/* ---------- 7 · why calder: the portal (3 Sep) ---------- */
/* Jenil's refsec.mp4 gesture, from the approved curtain stage (B) of
   _review/CALDER-WHY-V3-portal-variants.src.html; the aperture this replaces
   was retired the same day. Three layers on one pinned stage, all cut on the
   viewport's centre line. L2, two ink halves carrying Why | Calder, parts
   first; L1, ONE bone curtain carrying the sentence, rises hem-last - its hem
   is the footer dome's true circle upside down (diameter 4.751 viewport
   widths, sagitta .0532W), drawn as a px clip-path in calder.js from the same
   constant the dome uses; L0, the photograph, settles 1.10 -> 1.00 as it is
   uncovered, then the shade and the closing block arrive. The curtains hide
   with OPACITY in the still states, never display: the h2 must stay readable
   to assistive tech where the timeline never runs. */
#why{background:var(--ink);padding:0}
.why__stage{position:relative;height:100svh;min-height:640px;overflow:hidden;isolation:isolate;background:var(--ink)}
/* L0 - the photograph. Rests at the timeline's from-state 1.1; reduced motion
   and no-JS override it to the settled 1. */
.why__photo{position:absolute;inset:0;z-index:0;overflow:hidden}
.why__photo img{width:100%;height:100%;object-fit:cover;object-position:50% 45%;
  transform:scale(1.1);transform-origin:50% 45%;will-change:transform}
.why__shade{position:absolute;inset:0;opacity:0;
  background:linear-gradient(to top,rgba(16,18,22,.78) 0%,rgba(16,18,22,.25) 34%,rgba(16,18,22,0) 60%)}
/* L1 - the bone curtain. inset bottom -8vw: the hem's sagitta is .0532W, so
   the arc needs body below the stage's own bottom edge to dip into. */
.why__curtain{position:absolute;inset:0 0 -8vw 0;z-index:1;background:var(--bone);
  will-change:transform;pointer-events:none}
.why__sent{position:absolute;left:50%;top:calc(50% - 4vw);transform:translate(-50%,-50%);margin:0;
  font-family:var(--serif);font-weight:400;font-size:clamp(28px,5.9vw,112px);letter-spacing:-.03em;
  line-height:.95;color:var(--ink-d);white-space:nowrap;text-align:center}
/* L2 - the ink curtain, two halves on the same 50% line as the hero seam.
   The words are the section's h2 (aria-label carries the space). */
.why__ink{position:absolute;inset:0;z-index:2;margin:0;pointer-events:none}
.why__cur{position:absolute;top:0;bottom:0;width:50%;background:var(--ink);will-change:transform}
/* the left half runs .5px past the centre line, under the right: measured at
   rest the abutting halves leaked a sub-pixel seam of the bone behind them
   (21-82 px of the centre column at RGB 66,70,77 - a ~24% bleed). Overlap,
   never a widened half: the words stay anchored on the same centre. */
.why__cur--l{left:0;width:calc(50% + .5px)}
.why__cur--r{left:50%}
.why__w{position:absolute;top:50%;transform:translateY(-52%);font-family:var(--serif);font-weight:400;
  font-size:clamp(64px,17.5vw,336px);letter-spacing:-.035em;line-height:1;color:var(--bone);white-space:nowrap}
.why__cur--l .why__w{right:0;padding-right:.11em}
.why__cur--r .why__w{left:0;padding-left:.11em}
/* the end: the closing block on the house gutter, over the shade */
.why__end{position:absolute;left:var(--nav-px);right:var(--nav-px);bottom:var(--nav-px);z-index:3;
  display:flex;justify-content:space-between;align-items:flex-end;gap:var(--g)}
.why__close{margin:0;color:var(--bone);font-size:clamp(16px,1.25vw,19px);line-height:1.45;max-width:40ch;
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.why__cta{display:grid;gap:12px;justify-items:end;text-align:right}
.why__note{color:var(--bone-2);font-size:13px;line-height:1.5;
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
/* the closing block is hidden ONLY where the timeline will reveal it */
@media (prefers-reduced-motion: no-preference){
  html.has-js .why__end{opacity:0;visibility:hidden}
}
/* the still states rest on the finished composition: photograph, shade,
   closing block. Opacity, not display - see the block comment above. */
@media (prefers-reduced-motion: reduce){
  .why__ink,.why__curtain{opacity:0}
  .why__shade{opacity:1}
  .why__photo img{transform:none}
}
html:not(.has-js) .why__ink,html:not(.has-js) .why__curtain{opacity:0}
html:not(.has-js) .why__shade{opacity:1}
html:not(.has-js) .why__photo img{transform:none}
@media(max-width:999px){
  /* no pin below 1000 - the same timeline plays once on entry (calder.js).
     The sentence wraps to two balanced lines; the closing block stacks left. */
  .why__sent{white-space:normal;text-wrap:balance;width:max-content;max-width:min(9.6em,92vw);
    font-size:clamp(26px,7.4vw,44px);line-height:1.06}
  .why__w{font-size:clamp(56px,19vw,120px)}
  .why__end{flex-direction:column;align-items:flex-start;left:var(--g);right:var(--g);bottom:28px}
  .why__cta{justify-items:start;text-align:left}
}


/* ---------- 9 · pre-footer ---------- */
#prefooter{background:var(--bone);padding:0;position:relative;overflow:hidden}
/* the frame IS the picture's box, so the two display blocks can be placed as
   percentages of the photograph instead of of a section the curve keeps
   resizing. The picture is exactly viewport-wide: at 106vw the composition
   drifted with the width and the blocks could not be aimed at the lit half.
   `isolation` keeps the blend below confined to this box. */
.pf__frame{position:relative;isolation:isolate}
.pf__figure{margin:0;width:100%;max-width:none;position:relative;z-index:0}
.pf__figure img{width:100%;height:auto;display:block;filter:grayscale(1) contrast(1.04)}
/* NO VISIBLE LINE ABOVE THE PORTRAIT. Measured at 1920: the section above ends
   on a flat --ink 18/255 and the picture's own first row runs 17 on the left to
   4 on the right, so a 14-level step printed straight across the frame (Jenil,
   25 Aug: "there's no visible line here ... match that"). This band paints --ink
   over the picture's top and fades it out, so the two grounds meet at exactly
   the same value and the join has nothing to show. */
.pf__frame::before{content:"";position:absolute;left:0;right:0;top:0;z-index:1;pointer-events:none;
  height:clamp(80px,13vh,170px);background:linear-gradient(var(--ink),rgba(16,18,22,0))}
/* THE SPILL: the picture continues below its own frame, mirrored. The dome's
   growth (see .pf__curve::before) means its flanks sit up to ~10vw BELOW the
   resting flank line mid-entrance, and the reference's dome always has its
   pre-footer PICTURE behind those states - its silhouette runs on past the
   footer boundary. Ours stopped 20px below the resting flanks, so the growth
   would have exposed the portrait's bottom edge against bare bone at the
   viewport edges. This paints the photograph on downward, reflected about its
   own bottom row so the join is continuous by construction. At rest the dome
   covers all of it - verified invisible - and #prefooter's overflow:hidden
   contains it. Same grayscale/contrast grade as the img above it. */
.pf__frame::after{content:"";position:absolute;top:calc(100% - 2px);left:0;width:100%;height:11vw;z-index:0;pointer-events:none;
  background:url("../img/pf-spill.webp") 50% 0/100% 100% no-repeat;
  filter:grayscale(1) contrast(1.04)}
/* pf-spill.webp is a BUILT edge-extend, not the photograph re-shown: its two
   top rows are the photo's own last two rows (so the 2px overlap is seamless)
   and every row below repeats the bottom row - each column continues its own
   edge pixel straight down. Two earlier in-CSS attempts failed measurably: a
   scaleY(-1) mirror bent the shoulder back up into a V (a reflection cannot
   continue a diagonal), and "background-size:100% 800%" only stretched it
   1.57x, because percentage background sizes resolve against the ELEMENT'S
   box, not the image's proportions - the trap that made the fix look done.
   The photograph ends at row 940; a straight-down extend is the only
   continuation that invents no shapes. */
/* top is 100% MINUS 2px: at exactly 100% a fractional image height left a
   sub-pixel crack between the img's bottom and the spill's top, and the
   section's bone printed through it as a white hairline at the join (Jenil,
   1 Sep, his img 6). The 2px overlap repeats two rows of photograph, which
   nothing can see. */
/* THE LETTERS CHANGE SHADE WHERE THEY CROSS THE PORTRAIT, and they do it by
   themselves. The reference's line runs from the lit backdrop onto the
   silhouette and flips tone on the edge (Jenil, 25 Aug, img 9 vs 10); ours was
   two separately-coloured blocks that each stopped short of the boundary, so
   nothing ever crossed. One `mix-blend-mode:exclusion` layer at rgb(212,210,211)
   does the whole thing: exclusion(S,B) = S + B - 2SB/255, so over the backdrop's
   227 it renders 62 - the reference's OWN display grey, measured - and over the
   silhouette's 10 it renders 205. 8.1:1 and 12.5:1. The size is set so the tail
   of the left block reaches the edge: the silhouette starts at 47% of the width
   at this height, and 11.2vw puts "Nothing here" at 48%. */
.pf__line{position:absolute;z-index:2;font-family:var(--serif);font-weight:400;font-size:clamp(40px,11.2vw,215px);
  letter-spacing:-.03em;line-height:.8;white-space:nowrap;will-change:transform;margin:0;
  color:rgb(212,210,211);mix-blend-mode:exclusion}
/* 47% is where the backdrop's bright plateau starts: measured on the source it
   holds 226-231 from y 45% down and only then rolls off, so the whole left
   block sits on it and only its tail crosses the silhouette's hard edge. */
/* 58/67, NOT 47/56: THE SENTENCE SITS BELOW THE FACE. Jenil, 29 Aug: "reposition
   this text somewhere not on his face." At 47% the left block's ink ran rows
   340-550 of the 810 frame, straight across the loupes, the eye, the nose and
   the mouth - the tail letter landed on his lips. Mapped the silhouette row by
   row: the head fills the frame from ~150 to ~620 and its left edge holds at
   660-668 from row 440 down to 600, with no specular feature below row 200, so
   the jaw-and-neck band is the only place the line can cross the portrait
   without crossing a face. +11% puts the ink at 429-639 and the crossing on the
   jawline. It is the largest move available: at 62% the second block's ink
   reaches 744 and starts meeting the curve, which tops out at 729 at the centre.
   THE CROSSING IS PRESERVED, and it has to be - it is the whole effect. The ink
   still ends at 803 against an edge at ~663, i.e. 140px of overlap, so the tail
   letters still change shade on the silhouette's own edge.
   68/73 IS FITTED TO THE NEW PORTRAIT, AND IT WAS SWEPT, NOT GUESSED. The
   picture changed on 29 Aug (see the pf-clinician note in SOURCES.md), and its
   silhouette is a different shape: the head sits in the MIDDLE of the frame
   rather than hard right, so the lit rim that the line crosses IS his face
   between rows 400 and 650, and only below 650 does the edge become neck and
   collar. Four positions were rendered and measured per-slice against the bare
   ground, 16 slices per block, at 1440 and 1920:
     58/63  left 2.92 / 3.10   1 slice under 3:1 at 1440   FAILS
     64/69  left 3.66 / 3.78   0 slices under 3:1
     68/73  left 4.01 / 4.02   0 slices under 3:1          BEST
     71/76  left 2.64 / 2.34   1-2 slices under 3:1        FAILS
   71 drops the block onto the collar where the ground passes through the
   exclusion blend's fixed point at B=127.5 and the letters vanish; 68 is the
   lowest position that still clears it. The right block reads 5.10-5.25.
   Do not move either block without re-running that sweep. */
.pf__line--a{top:68%;left:calc(var(--nav-px) + 1.6vw)}
.pf__line--b{top:73%;right:calc(var(--nav-px) + 1.6vw)}
.pf__line a{color:inherit}
/* where exclusion is not available the two blocks fall back to the tones they
   would have rendered: ink on the lit half, bone over the head */
@supports not (mix-blend-mode:exclusion){
  .pf__line{mix-blend-mode:normal}
  .pf__line--a{color:var(--ink-d)}
  .pf__line--b{color:var(--bone);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
}
/* THE SMALL LABEL IS GONE (25 Aug). The reference prints its own between the
   two display blocks, but its two blocks share a baseline and leave a clean
   column between them; ours sit on different lines with a diagonal gap, so
   the label landed on the jaw and read as debris (Jenil: "looks very weird
   here and forced and unnatural"). It was also saying a second time what the
   curve directly beneath it already says - Ready when you are. Book a call. */
/* THE CURVE MUST NOT EAT THE PORTRAIT. It is 150% wide on a -25% margin, so its
   rounded corners are off-screen and only the shallow middle of the dome shows:
   the visible top edge drops just 61px from the screen centre to the screen
   edges (ry 240 x .2546, a ratio the 150%/-25% geometry fixes at every width).
   At -300 that made it a near-flat band covering the picture's bottom 239-300px
   and cutting the head off at the jaw (Jenil, 25 Aug). -81 leaves 20px of
   overlap at the screen edges - which is what the curve's own 20px rise needs so
   no bone gap opens beneath it - and 81 at the centre, 7.5% of the picture.
   THE CURVE'S 25% PADDING RESOLVES AGAINST #prefooter, NOT ITSELF. Percentage
   padding is measured against the containing block's inline size, so 25% here is
   25% of the viewport (480 at 1920) and not 25% of the curve's own 150% (720).
   The content box therefore came out exactly viewport-wide starting at x=0: the
   first chip sat on the left edge and the CTA ran to the right one, both cut.
   The gutter has to be added on top of that 480. */
/* THE CURVE IS THE TOP CAP OF A CIRCLE, NOT A SHALLOW ELLIPSE. Measured on the
   reference's own footer DOM at 1920 and 1280 (it calls the element .bg): an
   absolutely positioned div of 9122x9122 at 1920 and 6081.6x6081.6 at 1280,
   border-radius:50%, centred on the viewport with its top edge on the footer's
   top edge, inside a footer that is overflow:hidden. Both readings are the same
   multiple of the viewport WIDTH - 4.75104 and 4.75125 - so the diameter is
   475.1% and the arc is a true circle at every width.
   Its sagitta, i.e. how far the edge drops from the apex to the frame's edges,
   is therefore R - sqrt(R^2 - (W/2)^2) = 0.05322W: 102.2px at 1920, 68.1 at
   1280. Ours was an ellipse of 150% width on a FIXED 240px vertical radius,
   which gives 0.2546 x 240 = 61.1px at EVERY width - flatter than the reference
   everywhere, and increasingly so as the frame grows.
   A border-radius cannot do this: the vertical radius would have to be 237.55%
   of the viewport width, and CSS scales all four radii down when they exceed
   the box's own height, so on a ~700px block the dome collapses. Hence the
   reference's own construction - a real circle, clipped by the box.
   The overlap at the SCREEN EDGES is still the invariant, and it is still 20px:
   margin-top is the sagitta plus that 20, so the GSAP rise (which is also 20)
   can never open a bone gap under the dome. Percentage margins resolve against
   the containing block's WIDTH, which is what keeps this one number correct at
   every viewport without a single vw - and vw would be wrong here anyway, since
   a classic scrollbar makes 100vw wider than the layout viewport. */
.pf__curve{position:relative;z-index:2;overflow:hidden;
  margin-top:calc(-5.322% - 20px);width:100%;margin-left:0;background:transparent;
  padding:260px var(--nav-px) 236px;will-change:transform}
/* ON THE STUDIO PAGE THE CURVE'S GROUND IS BONE (1 Sep, Jenil's img 1-2: the
   corners beside the growing dome read as "a basic flat footer"). The curve
   section is transparent, so beside and under the deep entrance dome the
   BODY's ink showed as flat black corners below the CTA's bone edge. On home
   the corners must stay transparent - the picture and its spill live there -
   but on studio the ground above the dome is bone everywhere, so the section
   simply carries it. The circle covers the section's full width at its
   bottom edge at every growth state (measured geometry), so no bone can leak
   into the footer. */
.scta + .pf__curve{background:var(--bone)}
/* THE CIRCLE GROWS AS THE FOOTER ARRIVES - the reference's own mechanism,
   measured on its live DOM (1 Sep): its circle is 176.0% of the viewport wide
   while the footer is still below the fold and grows linearly to 475.1% as
   the footer's top travels from 85% of the viewport to 10% past its top, so
   the dome's flanks LIFT as it settles - the subtle pop Jenil pointed at in
   aventura.mp4 at 34-36s. Implemented as a scale about the apex (top centre),
   not a width change, so it stays compositor-only: 176/475.1 = .3704 -> 1.
   The default is 1, so no-JS, reduced motion and mobile rest on the settled
   curve. The apex is a fixed point of the scale by construction, so the
   settled geometry - sagitta 5.322vw, 20px edge overlap - is untouched. */
.pf__curve::before{content:"";position:absolute;top:0;left:50%;width:475.1%;aspect-ratio:1;
  transform:translateX(-50%) scale(var(--pfs,1));transform-origin:50% 0;
  border-radius:50%;background:var(--ink-f);z-index:-1}
@media(max-width:999px){ .pf__curve{padding:120px var(--g) 72px} }
.pf__brand img{width:clamp(150px,15.6vw,240px);height:auto;display:block;margin-inline:auto}
.pf__brand{font-weight:600;font-size:13px;letter-spacing:.26em;text-transform:uppercase;color:var(--bone);
  margin-bottom:clamp(28px,4.4vh,54px);text-align:center}
.pf__row{display:flex;justify-content:space-between;align-items:flex-end;gap:6vw;flex-wrap:wrap}
/* the curve is a centred signature since 1 Sep - the CTA it carried said what
   the footer headline says one screen later, so it is the mark and the chips
   now, and the row centres under the mark instead of spreading to the gutters */
.pf__row--centre{justify-content:center}
.pf__chips{display:flex;gap:12px;list-style:none;flex-wrap:wrap}
.pf__chips a{display:inline-flex;align-items:center;gap:10px;border:1px solid rgba(234,232,233,.28);border-radius:999px;
  height:48px;padding:0 22px;font-size:14px;font-weight:600;color:var(--bone-2);position:relative;overflow:hidden;
  transition:color var(--ui-dur) var(--ease-out)}
.pf__chips a::before{content:"";position:absolute;inset:0;background:var(--bone);
  transform:scaleX(0);transform-origin:100% 50%;transition:transform var(--ui-dur) var(--ease-out)}
.pf__chips a span{position:relative;z-index:1}
@media(hover:hover) and (pointer:fine){ .pf__chips a:hover{color:var(--ink-d)} .pf__chips a:hover::before{transform:scaleX(1);transform-origin:0 50%} }
.pf__chips a:focus-visible{color:var(--ink-d)}
.pf__chips a:focus-visible::before{transform:scaleX(1);transform-origin:0 50%}
.pf__cta{font-family:var(--serif);font-size:clamp(28px,3vw,44px);line-height:1.1;color:var(--bone);max-width:16ch;text-align:right}
.pf__cta a{color:inherit;text-decoration:underline;text-underline-offset:6px;text-decoration-thickness:1px}
@media(max-width:999px){
  .pf__cta{text-align:left}
  .pf__figure{width:100%;height:420px}
  .pf__figure img{height:100%;object-fit:cover;object-position:center}
  /* the phone crop puts the lit half at x 0-160 from y 210 down and the head at
     0 from x 200; the blend tones both blocks by itself there too */
  .pf__line--a{top:222px;left:var(--g)}
  .pf__line--b{top:272px;right:var(--g)}
  .pf__frame::before{height:70px}
  .pf__curve{padding-bottom:120px}
}

/* ---------- 10 · footer ---------- */
/* THE FOOTER IS THE REFERENCE'S GRID, MEASURED AT 1920 (24 Aug). Its whole
   footer is ONE three-track grid running gutter to gutter at --nav-px:
   column starts x=43 / 348 / 949 and a right edge at 1877, i.e. 0 /
   16.63% / 49.40% of the 1834 content width. The form, the headline, the
   Locations group and the bottom bar's centre run ALL start at 949 - the
   third track - which is why the reference reads as one column of
   information and ours, boxed into --wrapmax at x=272, did not. */
.footer{background:var(--ink);padding:128px var(--nav-px) 32px}
/* the home footer sits on the reference's navy (--ink-f), continuing the dome
   above it - the two must always be one colour or the section boundary prints.
   --muted is lifted a step inside it: #7E848D reads 3.96:1 on the lighter
   ground, under the 4.5 floor for the body-size rows; #8A9099 reads 4.62:1. */
.footer--navy{background:var(--ink-f);--muted:#8A9099}
.footer__cta{display:grid;grid-template-columns:16.63% 32.77% 50.6%;
  padding-bottom:clamp(40px,5.1vw,98px)}
.footer__ctaw{grid-column:3;min-width:0}
/* the reference's form headline, off its live DOM (1 Sep): 73.33px Instrument
   Serif w400, lh .87 (63.8/73.33), ls -3%, bone, 104px above the field group. */
.footer__ready{font-family:var(--serif);font-weight:400;font-size:clamp(34px,3.82vw,73.33px);line-height:.87;letter-spacing:-.03em;color:var(--bone);
  margin-bottom:clamp(48px,5.4vw,103.7px)}
/* the reference's radio row: 32px circles on a 1px graphite ring, labels
   21.33px w400 bone, the legend 18.67 w500 muted, 53px above the fields. */
/* the reference stacks these: "Choose your location:" on its own line, the
   radio row beneath it (Jenil's screenshot of its live footer, 1 Sep) */
.footer__studios-pick{border:0;padding:0;margin-bottom:clamp(28px,2.78vw,53.3px);display:flex;gap:clamp(18px,2.9vw,56px);align-items:center;flex-wrap:wrap}
.footer__studios-pick legend{font-size:var(--f-label);font-weight:500;color:var(--muted);
  float:none;width:100%;margin-bottom:clamp(12px,1.3vw,25px)}
.footer__studios-pick label{display:inline-flex;align-items:center;gap:clamp(8px,.63vw,12px);font-size:clamp(15px,1.111vw,21.33px);color:var(--bone);cursor:pointer}
.footer__studios-pick input{accent-color:var(--bone);width:clamp(20px,1.67vw,32px);height:clamp(20px,1.67vw,32px)}
/* the reference's own field run: two 398.5 fields on a 12px gap, then an 11px
   gap and a 107px circle, 950 -> 1877 */
/* the reference's field run, off its live DOM (1 Sep): two 400x87.3 pills on
   a 10.7 gap, border 1px rgba(233,231,231,.15), the word inside 20px at the
   42.7px inset, then the 810.7x106.7 message pill with the 106.7 send circle
   beside it on the same row. All in the same W/90 rem, carried here as vw. */
.footer__fields{display:grid;grid-template-columns:1fr 1fr auto;gap:clamp(8px,.56vw,10.7px);align-items:start}
.f-field{position:relative;display:flex;flex-direction:column;justify-content:center;
  min-height:clamp(56px,4.55vw,87.3px);border:1px solid rgba(233,231,231,.15);border-radius:999px;
  padding:0 clamp(20px,2.22vw,42.7px);
  transition:border-color var(--ui-dur) var(--ease-out),transform var(--ui-dur) var(--ease-out)}
.f-field--wide{grid-column:1/2;grid-column:1/3;border-radius:999px;min-height:clamp(64px,5.56vw,106.7px)}
.f-field label{display:block;font-size:clamp(14px,1.042vw,20px);font-weight:400;letter-spacing:-.01em;text-transform:none;color:var(--muted);
  transition:transform var(--ui-dur) var(--ease-out)}
.f-field input,.f-field textarea{width:100%;background:transparent;border:0;color:var(--bone);font:inherit;font-size:clamp(14px,1.042vw,20px);padding:2px 0}
/* height beats the rows attribute: the reference's message pill is one quiet
   line at rest (106.7 tall in all), growing only if the visitor drags it */
.f-field textarea{resize:vertical;height:1.55em;min-height:0}
.f-field input:focus-visible,.f-field textarea:focus-visible{outline:none}
.f-field:focus-within{border-color:var(--bone);transform:translateY(-2px)}
.f-field:focus-within label{transform:translateY(-1px)}
/* THE SEND CIRCLE IS BONE NOW, NOT CALDER RED - Jenil, 1 Sep: "instead of a
   red submit button, use white submit button", matching the reference's own
   rgb(234,232,232) circle. (This supersedes the "one calder-coloured element"
   note - the wordmark's incision carries the red now.) It sits beside the
   message pill on its own row, the reference's position. */
.footer__send{grid-column:3;grid-row:2;width:clamp(64px,5.56vw,106.7px);border-radius:50%;aspect-ratio:1;align-self:center;
  background:var(--bone);color:var(--ink);border:0;font-size:clamp(20px,1.25vw,24px);cursor:pointer;position:relative;overflow:hidden;justify-self:end;
  display:grid;place-items:center}
.footer__send svg{display:block;width:clamp(20px,1.4vw,27px);height:auto}
.footer__send span{line-height:0}
.footer__send span{position:relative;z-index:1;transition:transform var(--ui-dur) var(--ease-out)}
@media(hover:hover) and (pointer:fine){ .footer__send:hover span{display:inline-block;transform:translateX(6px)} }
.footer__send:focus-visible span{display:inline-block;transform:translateX(6px)}
.footer__price{margin-top:16px;font-size:13px;color:var(--bone-2)}
/* the reference's DEFAULT column row (re-confirmed 1 Sep against its live
   footer, after a day of confusion: the studios-first screenshot that drove a
   brief reorder was its CONTACT footer): Services at the 43 gutter, Our
   Clinic at 348, Locations at 949 spreading right in ruled columns - the
   original 24 Aug tracks. */
/* col1 is 19.3%, not the cta row's 16.63 (Jenil, 1 Sep: "leave a little more
   space between the services column and the studio column") - the longest
   service name ran to ~15px of the track edge; 19.3% gives it the reference's
   own ~60px of clear air. Col3 stays 50.6% so Studios keeps its 949 anchor. */
.footer__cols{display:grid;grid-template-columns:19.3% 30.1% 50.6%;
  padding-block:0 clamp(96px,12.3vw,236px)}
@media(max-width:999px){ .footer__cols{padding-block:0 64px} }
/* THE COLUMN LABEL IS A 14px CAP = 19.2px, NOT THE 12.4 FIRST RECORDED.
   Measured on the reference at 1920: "Services" runs cap-top 370 to baseline
   383 and its x-height band is 10 - 19.2px on Inter Tight's .7275/.53 ratios.
   Its cap-top sits 65px above the first link's, which on these two line boxes
   is 37px of margin. Ours ran 12.4px on 44 and read as a caption. */
.footer__collabel{font-size:var(--f-label);font-weight:500;line-height:1.19;color:var(--muted);
  margin-bottom:clamp(20px,1.93vw,37px)}
.footer__cols ul{list-style:none}
/* THE FOOTER LINKS ROLL - THEY DO NOT UNDERLINE. Measured frame by frame on
   hover.mp4 at 1920: the reference's "Technology" splits into two runs and the
   old copy rises out of a line-box window while its twin arrives from below
   (old bottom 818 -> 806 -> 802 -> 799 -> 796 -> 794 -> 792 -> 790 -> 789
   against a new top of 811 -> 808 -> 805 -> 803 -> 801 -> 799 -> 798 -> 797),
   settling in 9 frames = .3s. No underline row ever appears, and the colour
   does not change. Ours wiped an underline in and lifted the colour instead.
   The twin is `content:attr(data-roll)`, so it costs one attribute per link and
   no extra element; the LI is the clip window, and it is the LI that carries
   :hover so the pointer never chases the link out from under itself. */
.footer__cols nav li{overflow:hidden;margin-bottom:clamp(6px,.55vw,10.6px)}
.footer__cols nav li:last-child{margin-bottom:0}
/* THE FOOTER LINKS ARE THE REFERENCE'S SIZE, MEASURED AT 1920 (24 Aug): its
   rows sit on a 40px pitch (cap tops 715, 755, 795, 835) and render a 21px CAP
   - 28.9px on Inter Tight's .7275 ratio - with a 3.5px stem, which is w700 on
   that cap, in full bone rgb(237,236,240). Ours ran 15px w600 in --bone-2, less
   than half the size and a step light. Scaled by the same 1.333 the rest of the
   replica uses, that is 21.7 at 1440. */
.footer__cols nav a{display:block;position:relative;font-size:var(--f-link);font-weight:700;
  letter-spacing:-.01em;line-height:1.13;color:var(--bone);padding:3.75px 0;
  transition:transform .32s var(--ease-soft)}
/* THE TWIN MUST WRAP EXACTLY LIKE THE ORIGINAL, AND IT DID NOT.
   It carried `white-space:nowrap` and no right edge, so it shrink-to-fit to
   max-content while the real link wrapped inside its column. Two faults fell
   out of that, both visible on hover (Jenil, 29 Aug, four screenshots):
   (1) HORIZONTALLY the twin ran out of its own column and printed over the
   next one - measured at 1440, four of the five service links overran the
   column's right edge by 5 / 68 / 45 / 60px, and that edge IS where "The
   studio" begins, so "Smile Planning & Design" landed on top of "Home".
   (2) VERTICALLY the twin was one line tall (24px) inside a window sized to
   the wrapped original (56px), so the roll left an empty line under it.
   Neither showed before 29 Aug: the treatment names were short then. The five
   renamed families are up to 29 characters and wrap to two lines, which is
   what the twin had to be taught to do.
   `right:0` gives it the link's own width so it wraps identically, and the
   matching padding keeps the two copies on the same baseline - `top:100%`
   measures the padding box, and the transform moves by that same box. */
.footer__cols nav a::after{content:attr(data-roll);position:absolute;left:0;right:0;top:100%;
  padding:3.75px 0}
@media(hover:hover) and (pointer:fine){ .footer__cols nav li:hover a{transform:translateY(-100%)} }
/* the roll's window would clip the global 4px-offset ring, so a focused link
   keeps its place and takes an inset ring instead - visible, never cut */
.footer__cols nav a:focus-visible{outline-offset:-2px}
/* THE STUDIO BLOCKS CARRY A 2px RULE ON THEIR LEFT EDGE AND SIT 21px INSIDE IT.
   Measured at 1920: the reference's rules are 2px at x=949/1269/1589 (a 320
   pitch = 288 columns on a 32 gap), each running the block's full content box
   (y 430 -> 659), and its text starts 21px right of the rule. Its "Locations"
   label sits at the rule's own x, not the text's. */
/* the reference's location columns, confirmed on its live footer (1 Sep):
   ruled on their left edge, the name UNDERLINED at the links' own 21.33 w700,
   address below, bold 20px number, hours row - the 24 Aug structure, at the
   corrected scale. */
.footer__locgrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:32px}
.floc{border-left:2px solid rgba(234,232,233,.10);padding:3.75px 0 0 21px}
.floc h3{font-family:var(--ui);font-size:var(--f-link);font-weight:700;line-height:1.13;letter-spacing:-.01em;
  color:var(--bone);text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:5px;
  text-decoration-color:currentColor}
.floc__addr{margin-top:clamp(13px,1.2vw,23px);font-size:var(--f-body);line-height:1.06;color:var(--bone)}
.floc__tel{margin-top:clamp(22px,2.03vw,39px);font-size:var(--f-tel);font-weight:700;line-height:1.13;color:var(--bone)}
/* the reference's number is bold and NOT underlined - only the studio name is.
   `p a` was putting a second rule under it. */
.floc__tel a{color:inherit;text-decoration-color:transparent}
@media(hover:hover) and (pointer:fine){ .floc__tel a:hover{text-decoration-color:currentColor} }
.floc__tel a:focus-visible{text-decoration-color:currentColor}
.floc__hours{margin-top:clamp(23px,2.08vw,40px);font-size:var(--f-fine);line-height:1.152;
  display:grid;grid-template-columns:auto 1fr;column-gap:clamp(14px,1.46vw,28px)}
.floc__hours span:first-child{color:var(--muted)}
.floc__hours span+span{color:var(--bone)}
/* THE BOTTOM BAR IS THE SAME THREE TRACKS. Measured at 1920: the reference's
   copyright pair sits at the gutter on a 19px pitch (cap tops 893 and 912,
   line 1 muted and line 2 in bone, both a 13px cap = 17.9px) and its centre
   run starts at 949 - the third track - not at the middle of the page. */
.footer__base{display:grid;grid-template-columns:16.63% 32.77% 50.6%;align-items:center}
.footer__baseid{grid-column:1}
.consult-marker{font-size:var(--f-body);font-weight:400;letter-spacing:0;text-transform:none;color:var(--bone);
  line-height:1.06;margin:0}
.foot-copy{font-size:var(--f-body);font-weight:400;letter-spacing:0;text-transform:none;color:var(--muted);
  line-height:1.06;margin:0}
.foot-disclosure{color:var(--bone-2);font-size:14px;line-height:1.5;max-width:52ch;margin:0}
.footer__base .foot-disclosure{grid-column:3;color:var(--bone);font-size:var(--f-body);line-height:1.32;max-width:none}
/* THE CONTACT PAGE'S FOOTER PUTS THE STUDIOS FIRST. Measured off the reference
   at 1920: the studio list runs from the 43px gutter across the first two
   tracks, Services still starts at 949 - the same third track the rest of the
   footer uses - Our Clinic at 1255 (33.8% into that track) and two circles sit
   at the right gutter. The stacked studio is a muted name over a bone number on
   the same 17.9 / 20.6 pair the columns already use. */
.footer__cols--contact{grid-template-columns:49.4% 50.6%}
.footer__cols--contact .footer__locs{grid-column:1}
.footer__navs{grid-column:2;display:grid;grid-template-columns:40% minmax(0,1fr) auto;
  column-gap:0;align-items:start}   /* was 33% (the reference's 1255 anchor); widened 1 Sep with the
     other footers so the service names clear the next column by the same air */
.footer__locstack{display:grid;gap:clamp(28px,2.9vw,56px)}
.fstack__name{font-size:var(--f-body);line-height:1.06;color:var(--muted)}
.fstack__tel{margin-top:clamp(8px,.83vw,16px);font-size:var(--f-tel);font-weight:700;line-height:1.13;color:var(--bone)}
.fstack__tel a{color:inherit;text-decoration-color:transparent}
@media(hover:hover) and (pointer:fine){ .fstack__tel a:hover{text-decoration-color:currentColor} }
.fstack__tel a:focus-visible{text-decoration-color:currentColor}
.footer__circles{list-style:none;display:flex;gap:clamp(12px,1.25vw,24px);justify-self:end}
/* the pair in the form row sit at the LEFT gutter, level with the headline,
   at the reference's 106.7 with its rgba(66,67,70,.4) ground */
.footer__circles--cta{grid-column:1;grid-row:1;justify-self:start;align-self:start}
.footer__circles--cta .footer__circ{width:clamp(64px,5.56vw,106.7px);background:rgba(66,67,70,.4)}
.footer__circ{display:grid;place-items:center;width:clamp(56px,4.17vw,80px);aspect-ratio:1;border-radius:50%;
  background:rgba(234,232,233,.07);color:var(--bone-2);position:relative;overflow:hidden;
  transition:color var(--ui-dur) var(--ease-out)}
.footer__circ svg{position:relative;z-index:1}
.footer__circ::before{content:"";position:absolute;inset:0;border-radius:50%;background:var(--bone);
  transform:scale(0);transition:transform var(--ui-dur) var(--ease-out)}
@media(hover:hover) and (pointer:fine){ .footer__circ:hover{color:var(--ink-d)} .footer__circ:hover::before{transform:scale(1)} }
.footer__circ:focus-visible{color:var(--ink-d)}
.footer__circ:focus-visible::before{transform:scale(1)}
@media(max-width:999px){
  .footer__cols--contact,.footer__navs{grid-template-columns:1fr;gap:32px;column-gap:0}
  .footer__cols--contact .footer__locs,.footer__navs{grid-column:auto}
  .footer__circles{justify-self:start}
}
/* the compact footer (laboratory): the embedded close above carries the form */
.footer--compact{padding:64px var(--nav-px) 32px}
.footer--compact .footer__cols{grid-template-columns:19.3% 30.1% 50.6%;padding-block:0 clamp(72px,9vw,172px)}
.footer--compact .footer__brandline{grid-column:1}
.footer--compact .footer__cols>nav{grid-column:2}
.footer--compact .footer__locs{grid-column:3}
.footer__brandline{font-weight:600;font-size:13px;letter-spacing:.26em;text-transform:uppercase;color:var(--bone)}
/* the decorative brand signatures are the open-rail mark now, on-dark on both
   counts because both sit on --ink. height:auto is load-bearing - the width and
   height ATTRIBUTES map to a presentational height hint that would otherwise
   beat the file's own aspect. */
.footer__brandline img{width:clamp(120px,10.4vw,160px);height:auto;display:block}
@media(max-width:999px){
  .footer{padding-top:80px}
  .footer__cols nav a{padding:10px 0}
  .footer__cta,.footer__base{grid-template-columns:1fr;gap:40px}
  .footer__ctaw{grid-column:auto}
  .footer__base .foot-disclosure{grid-column:auto}
  .footer__fields{grid-template-columns:1fr}
  .f-field--wide{grid-column:auto}
  .footer__send{grid-row:auto;grid-column:auto;justify-self:start}
  .footer__cols,.footer--compact .footer__cols{grid-template-columns:1fr;gap:32px}
  .footer--compact .footer__brandline,.footer--compact .footer__cols>nav,
  .footer--compact .footer__locs{grid-column:auto}
  .footer__locgrid{grid-template-columns:1fr;gap:28px}
  .footer__base{gap:24px}
}

/* ---------- subpages: header tone per page ground ---------- */
body.head-ink .brand,body.head-ink .menu-toggle,body.head-ink .svc-toggle,
body.head-ink .head-form,body.head-ink .head-tel a{color:var(--ink-d);text-shadow:none}
body.head-ink .brand{--wm-ink:1}
body.head-ink .head-tel span{color:#5F656D;text-shadow:none}
body.head-bone .brand,body.head-bone .menu-toggle,body.head-bone .svc-toggle{color:var(--bone)}
body.head-bone .brand{--wm-ink:0}
body.head-ink.menu-open .brand,body.head-ink.menu-open .menu-toggle,body.head-ink.menu-open .svc-toggle,
body.head-ink.menu-open .head-form,body.head-ink.menu-open .head-tel a{color:var(--bone)}
body.head-ink.menu-open .brand{--wm-ink:0}
body.head-ink .head-book{background:var(--ink);color:var(--bone)}
/* over the open menu's ink ground the pill is bone whatever the page tone -
   .site-head is in the selector so it also outweighs the is-on-light rule */
body.menu-open .site-head .head-book{background:var(--bone);color:var(--ink);border:0}
body.head-bone .menu-toggle,body.head-bone .svc-toggle{text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
@media(min-width:1000px){
  .site-head.is-on-light .brand,.site-head.is-on-light .menu-toggle,.site-head.is-on-light .svc-toggle,
  .site-head.is-on-light .head-form,.site-head.is-on-light .head-tel a{color:var(--ink-d);text-shadow:none}
  .site-head.is-on-light .brand{--wm-ink:1}
  .site-head.is-on-light .head-tel span{color:#5F656D;text-shadow:none}
  .site-head.is-on-dark .brand,.site-head.is-on-dark .menu-toggle,.site-head.is-on-dark .svc-toggle,
  .site-head.is-on-dark .head-form,.site-head.is-on-dark .head-tel a{color:var(--bone);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  .site-head.is-on-dark .head-tel span{color:var(--bone-2);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  .site-head.is-on-dark .brand{--wm-ink:0}
  .site-head.is-on-light .head-book{background:var(--ink);color:var(--bone)}
  .site-head.is-on-dark .head-book{background:var(--bone);color:var(--ink)}
  /* THE SPLIT TONE - the bench bridge's rest band, which is the home hero's
     own composition: the bone panel always covers the band's LEFT (the brand
     and the two toggles never leave it - the seam rests at 36% and they end
     by ~26%), while the film is under the RIGHT cluster once the seam has
     passed it. One whole-band tone cannot serve both sides, so the bridge
     controller flips its section between 'light' (seam still right of the
     action cluster) and 'split'. The menu-open overrides below stay in
     charge when the menu is up: they are (0,3,1) against these (0,3,0). */
  .site-head.is-on-split .brand,.site-head.is-on-split .menu-toggle,.site-head.is-on-split .svc-toggle{color:var(--ink-d);text-shadow:none}
  .site-head.is-on-split .brand{--wm-ink:1}
  .site-head.is-on-split .head-form,.site-head.is-on-split .head-tel a{color:var(--bone);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  .site-head.is-on-split .head-tel span{color:var(--bone-2);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  .site-head.is-on-split .head-book{background:var(--bone);color:var(--ink)}
  body.menu-open .site-head .brand,body.menu-open .site-head .menu-toggle,body.menu-open .site-head .svc-toggle,
  body.menu-open .site-head .head-form,body.menu-open .site-head .head-tel a{color:var(--bone);text-shadow:none}
  body.menu-open .site-head .head-tel span{color:var(--bone-2);text-shadow:none}
  body.menu-open .site-head .brand{--wm-ink:0}
}
@media(max-width:999px){
  body.head-bone:not(.menu-open) .site-head .brand,body.head-bone:not(.menu-open) .site-head .menu-toggle,
  body.head-bone:not(.menu-open) .site-head .svc-toggle{color:var(--bone);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  body.head-bone:not(.menu-open) .site-head .brand{--wm-ink:0}
  body.head-ink:not(.menu-open) .site-head .brand,body.head-ink:not(.menu-open) .site-head .menu-toggle,
  body.head-ink:not(.menu-open) .site-head .svc-toggle{color:var(--ink-d);text-shadow:none}
  body.head-ink:not(.menu-open) .site-head .brand{--wm-ink:1}
}

/* ---------- technology ---------- */
/* THE HEADER BAND GETS A LOCAL GRADIENT, NOT A WHOLE-FRAME DARKEN. The 29-Aug
   hero photograph is a bright clinical room and its top band measures mean 141
   / p90 226, where the old one was near-black - so the bone header (Menu,
   Services, the number, the pill) sat on light grey and read at about 1.3:1.
   The house answer to type over imagery is a local gradient, the same device
   .svcs__stage::after uses for its corner index and .pf__frame::before uses
   over the portrait's top edge - never a scrim across the whole picture, which
   is the mistake that killed the first menu set. It covers the band the header
   occupies and is gone by 26% of the hero, so the photograph itself is
   untouched where the title sits. */
.tech-hero{position:relative;height:100svh;min-height:620px;overflow:hidden;
  display:flex;align-items:flex-end;justify-content:center;padding:0 var(--g) 5svh}
.tech-hero::before{content:"";position:absolute;left:0;right:0;top:0;height:26%;z-index:1;pointer-events:none;
  background:linear-gradient(to bottom,rgba(16,18,22,.86) 0%,rgba(16,18,22,.72) 34%,rgba(16,18,22,0) 100%)}
.tech-hero__bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:50% 32%}
/* .tech-hero__eyebrow was deleted 29 Aug on Jenil's instruction - the hero title
   stands alone now. */
/* THE LINE IS SIZED TO A SHARE OF THE FRAME, SO IT CAN CARRY NEITHER A BOX CAP
   NOR A TYPE CAP - AND IT HAD BOTH. The ink of "Advanced Technology" measures a
   constant multiple of the font-size on this face at this tracking, so the vw IS
   the share of the viewport the ink fills - 93.18%, the same share the home team
   line was fitted to. THE MULTIPLE IS A PROPERTY OF THE STRING, so the vw must be
   RE-MEASURED whenever the wording changes, exactly as --ab-mega's note says.
   It has been, once: "Advanced Technology" set 6.985 x the font-size and took
   13.34vw; "We start by looking" (29 Aug) sets 6.107 x, so at 13.34vw it filled
   only 81.5%. 93.18 / 6.107 = 13.895vw, and that lands it back on 93.2%.
   Two faults, opposite signs, and they only showed above 1440.
   (1) `width:min(--wrapmax,100%)` froze the BOX at 1376 while the type kept
   tracking the viewport. 1376 is exactly the 1440 content box (1440 - 2x32, --g
   at its ceiling), which is why 1440 looked right and nothing above it did. The
   nowrap ink outgrows 1376 above vw 1476.6, and .tech-hero's justify-content
   :center then spent the slack as an empty LEFT margin (x=112 at 1600, x=272 at
   1920), aiming the whole overrun at the right edge: measured 2.9px past it at
   1600 and 28.4px at 1920, with overflow:hidden slicing the y rather than
   showing a scrollbar. That is the cut letter in Jenil's screenshot.
   (2) The 240px ceiling is the same fault inverted - it bites from vw 1799 up
   and the share FALLS 93.18 -> 87.31 at 1920 -> 69.85 at 2400, so the line stops
   filling the frame. Fixing either one alone still fails at the other end.
   Both edits are no-ops at and below 1440: min(1376px,100%) already resolves to
   100% there, and 13.34vw is under 240px until 1798.8. Do not put either cap
   back. */
.tech-hero__title{position:relative;z-index:1;width:100%;
  font-family:var(--serif);font-weight:400;font-size:max(48px,13.895vw);line-height:.9;letter-spacing:-.05em;color:var(--bone);
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
@media(min-width:1000px){ .tech-hero__title{white-space:nowrap} }
/* THE EQUIPMENT IS AN INDEX, NOT A ROW OF CARDS (concept 02 of
   _review/CALDER-CONCEPTS-02Sep, approved by Jenil). The order is real - a
   case is captured, imaged, planned, milled, checked - so one instrument
   holds the frame at a time while the stage pins 3.8 viewports: the active
   name grows and turns bone, its two lines unfold, and the still wipes into
   the well on a clip-path edge (the JS block owns the wipe - clip-path,
   never width or left). The five stills are the page's own five, unchanged.
   THE COLLAPSE IS GATED ON .eq--js, set by the desktop controller: no-JS,
   reduced motion and phones all render every row expanded with its own
   still, so nothing is unreachable without a pin. The copy is Jenil's
   approved set, verbatim - do not rewrite it (rule 6). */
.eq{background:var(--ink);padding:0}  /* the generic section padding is owned by the children */
/* THE HEAD IS THE GOAL SECTION'S OWN ARMATURE (Jenil, 3 Sep: "improve the
   structure of this section and positioning of the paragraph"): two 1fr
   columns with NO gap, so with the symmetric --g padding column 2 opens at
   EXACTLY the viewport's half-width - the site's composition line (the goal's
   reveal, .hero-mid, the old tools intro all sit on it). The intro is
   bottom-anchored level with the headline's last line, and the headline
   breaks on the half-column into three balanced lines instead of the 10ch
   four-line tower the first pass shipped. */
.eq__head{padding:clamp(96px,15svh,170px) var(--g) clamp(40px,7svh,64px);
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);column-gap:0;align-items:end}
.eq__label{font-size:var(--t-label);font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.eq__head h2{font-family:var(--serif);font-weight:400;font-size:var(--t-sec);line-height:.9;letter-spacing:-.03em;
  color:var(--bone);margin-top:22px;text-wrap:balance;padding-right:.4em}
.eq__intro{font-size:var(--t-lead);line-height:1.45;color:var(--bone-2);max-width:38ch;justify-self:start;align-self:end}
.eq__stage{position:relative;min-height:100svh;
  padding:calc(var(--nav-h) + clamp(16px,3svh,32px)) var(--g) clamp(24px,4svh,40px);
  display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);column-gap:var(--g);align-items:center}
/* exactly one viewport only when the controller pins it; the static layouts
   are allowed to grow instead of clipping their expanded rows */
.eq--js .eq__stage{height:100svh;min-height:640px}
.eq__index{list-style:none;margin:0;padding:0}
.eq__row{display:grid;grid-template-columns:44px 1fr;column-gap:12px;padding:14px 0 18px;border-top:1px solid var(--line)}
.eq__row:last-child{border-bottom:1px solid var(--line)}
.eq__name{margin:0;grid-column:1/-1}
.eq__name button{display:grid;grid-template-columns:44px 1fr;column-gap:12px;align-items:start;width:100%;
  background:none;border:0;padding:0;cursor:pointer;text-align:left;
  font-family:var(--serif);font-weight:400;font-size:clamp(24px,2.2vw,36px);line-height:1;letter-spacing:-.02em;color:var(--bone);
  transition:color .5s var(--ease-soft),font-size .6s var(--ease-swap)}
/* the row type is the site's own set (Jenil, 3 Sep: "match the rest of the
   website's font, typography, font size and weight"): the numeral rides the
   services corner index's grammar (--svc-list, w500, -.01em - the site's one
   numbered-list voice), the two lines sit on the fluid --t-body the page's
   copy already uses (the first pass froze them at 15/14px, a step small at
   1920), and the bold lead-in is the site's strong - 600 in bone. */
.eq__num{font-family:var(--ui);font-weight:500;font-size:var(--svc-list);letter-spacing:-.01em;line-height:1;
  color:var(--muted);font-variant-numeric:tabular-nums;padding-top:8px}
.eq__what,.eq__you{grid-column:2;margin:0;display:grid;grid-template-rows:1fr}
.eq__what{margin-top:12px;font-size:var(--t-body);line-height:1.5;color:var(--bone-2);max-width:44ch}
.eq__you{margin-top:8px;font-size:var(--t-body);line-height:1.5;color:var(--muted);max-width:44ch}
.eq__you b{font-weight:600;color:var(--bone)}
.eq__what>span,.eq__you>span{display:block;overflow:hidden;min-height:0}
/* resting rows are collapsed only under the controller; .6s on the site's
   swap curve, the same family the services class flips ride */
.eq--js .eq__name button{color:var(--muted)}
.eq--js .eq__row.is-on .eq__name button{color:var(--bone);font-size:clamp(28px,2.8vw,44px)}
.eq--js .eq__what,.eq--js .eq__you{grid-template-rows:0fr;opacity:0;
  transition:grid-template-rows .6s var(--ease-swap),opacity .5s var(--ease-soft)}
.eq--js .eq__row.is-on .eq__what,.eq--js .eq__row.is-on .eq__you{grid-template-rows:1fr;opacity:1}
.eq__still{display:none}
.eq__well{position:relative;height:min(76svh,820px);border-radius:var(--radius-tile);overflow:hidden;
  background:var(--ink-2);isolation:isolate}
.eq__well img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:saturate(.55) contrast(1.05);opacity:0}
.eq__well img.is-cur{opacity:1}
.eq__bar{position:absolute;left:0;top:0;width:100%;height:2px;background:var(--bone);
  transform:scaleX(0);transform-origin:left;z-index:3}
.eq__cap{position:absolute;left:0;right:0;bottom:0;z-index:3;display:flex;justify-content:space-between;align-items:center;gap:16px;
  padding:18px 22px;font-family:var(--ui);font-size:var(--t-label);font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--bone);
  background:linear-gradient(to top,rgba(16,18,22,.55),rgba(16,18,22,0))}
.eq__cap>span{display:inline-flex;align-items:center;gap:10px;font-variant-numeric:tabular-nums;white-space:nowrap}
.eq__ret{display:inline-block;flex:none;width:10px;height:10px;border:1px solid var(--bone);border-radius:50%;position:relative}
.eq__ret::before,.eq__ret::after{content:"";position:absolute;left:50%;top:50%;background:var(--bone)}
.eq__ret::before{width:14px;height:1px;transform:translate(-50%,-50%)}
.eq__ret::after{width:1px;height:14px;transform:translate(-50%,-50%)}
/* below 1000 AND under reduced motion: no pin, no well, no wipe - every row
   expanded with its own still (base state), the well not rendered */
@media(max-width:999px),(prefers-reduced-motion:reduce){
  .eq__stage{grid-template-columns:1fr;align-items:start;min-height:0;padding-top:24px}
  .eq__index{max-width:860px}
  .eq__well{display:none}
  .eq__still{display:block;grid-column:2;width:100%;height:auto;margin-top:16px;border-radius:10px;
    aspect-ratio:4/3;object-fit:cover;filter:saturate(.55) contrast(1.05)}
}
@media(max-width:999px){
  .eq__head{grid-template-columns:1fr;row-gap:24px;padding-top:80px}
  .eq__row{grid-template-columns:36px 1fr}
  .eq__name button{grid-template-columns:36px 1fr}
}

/* THE BENCH BRIDGE IS THE HOME HERO'S SEAM, REPRISED (concept 03 of
   _review/CALDER-CONCEPTS-02Sep, approved by Jenil): the bone panel is the
   chair, the film is the bench, and the page closes on the edge the home
   hero taught. THE FOUR SEAM-DRIVEN LAYERS SHARE ONE BOX - the August seam
   invariant: the panel, both headline copies and the edge wrapper are all
   inset:0 against the stage, so every percentage clip resolves against the
   same border box and the two halves of the headline tile exactly. The ink
   copy sits INSIDE the panel (so the panel's own clip also cuts it - same
   box, same inset, identical by construction); the bone copy carries the
   hero's two-layer text-shadow. The hairline is drawn by a ::before at
   left:var(--seam) inside an inset:0 wrapper, never as a positioned 1px
   element of its own - the wrapper is what keeps it in the shared box.
   --seam defaults to 36% - the RESTING composition - so no-JS and reduced
   motion render the finished state; the controller drives it 100 -> 36 and
   the cursor-follow breathes +/-4.5 about the rest. The film is
   calder-bench.mp4 - THE LABORATORY HERO'S OWN FILM (11.6 MB, 1920x1080
   yuv420p, do not re-compress) - armed by the site's IntersectionObserver
   one viewport out, so reduced motion never fetches it. */
.bench-bridge{--seam:36%;position:relative;height:100svh;min-height:640px;overflow:hidden;isolation:isolate;background:var(--ink);
  padding:0}  /* the generic section padding would inset the STATIC phone stack (measured: a 20px ink frame at 390) */
.bridge__film{position:absolute;inset:0;z-index:0}
.bridge__film video{width:100%;height:100%;object-fit:cover;filter:saturate(.7)}
.bridge__film::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to right,rgba(16,18,22,.35),rgba(16,18,22,0) 40%,rgba(16,18,22,0) 70%,rgba(16,18,22,.35))}
.bridge__panel{position:absolute;inset:0;z-index:1;background:var(--bone);clip-path:inset(0 calc(100% - var(--seam)) 0 0)}
.bridge__top{position:absolute;left:var(--g);top:calc(var(--nav-h) + clamp(20px,4svh,40px));margin:0;
  font-size:var(--t-label);font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:#5F656D}
.bridge__h{position:absolute;inset:0;z-index:2;margin:0;display:grid;place-items:center;text-align:center;
  padding:0 var(--g);pointer-events:none;
  font-family:var(--serif);font-weight:400;font-size:clamp(48px,9.4vw,160px);line-height:.9;letter-spacing:-.03em}
.bridge__h--ink{color:var(--ink-d);clip-path:inset(0 calc(100% - var(--seam)) 0 0)}
.bridge__h--bone{color:var(--bone);clip-path:inset(0 0 0 var(--seam));
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.bridge__copy{position:absolute;left:var(--g);bottom:clamp(28px,5svh,44px);z-index:2;max-width:34ch;
  display:grid;gap:22px;justify-items:start}
.bridge__copy p{font-size:var(--t-lead);line-height:1.45;color:#2A2E35}
.bridge__copy .btn{background:var(--ink);color:var(--bone)}
.bridge__cap{position:absolute;right:var(--g);bottom:clamp(28px,5svh,44px);z-index:2;margin:0;
  font-size:var(--t-label);font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--bone);
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}  /* the film-crossing pair, like every element over the film */
.bridge__edge{position:absolute;inset:0;z-index:2;pointer-events:none}
.bridge__edge::before{content:"";position:absolute;top:0;bottom:0;left:var(--seam);width:1px;
  transform:translateX(-.5px);background:var(--bone);opacity:.35}
@media(max-width:999px){
  .bench-bridge{height:auto;min-height:0;display:grid;overflow:visible}
  .bridge__panel{position:relative;inset:auto;clip-path:none;order:1;
    padding:clamp(56px,10vh,96px) var(--g) 48px;display:grid;gap:28px;justify-items:start}
  .bridge__top{position:static}
  .bridge__h--ink{position:static;display:block;text-align:left;padding:0;clip-path:none;pointer-events:auto;
    font-size:clamp(44px,13vw,96px)}
  .bridge__h--bone{display:none}
  .bridge__copy{position:static}
  .bridge__film{position:relative;inset:auto;order:2;height:64svh}
  .bridge__cap{bottom:24px}
  .bridge__edge{display:none}
}

/* ---------- laboratory ---------- */
/* THE HERO IS THE REFERENCE'S OWN LABORATORY COMPOSITION, MEASURED OFF
   aventura.mp4 t=60/62 (its /laboratory page at 1920x919, 1 Sep, two frames
   agreeing to the pixel). The panel: x 960..1877 - the viewport's CENTRE LINE
   to the right --nav-px gutter - top 141 = nav-h + gutter, bottom ON the
   gutter, corner RADIUS 32 = 1.5rem of its W/90 system. grid column 1 is
   calc(50% - 32px): the content box is centred, so 50% of it ends exactly on
   the viewport's centre line at every width - never 50vw, which a classic
   scrollbar widens past the layout viewport. Heading: cap 150 -> fs 200 at
   1920, PITCH 165 = lh .825, ink on the gutter flush with the panel top.
   Sub 46.7 = --st-name2's own curve, ink 44 under the baseline. Paragraph
   20px w400 on a 21px pitch (lh 1.05), ink 360 wide, near-bone (measured
   ~.82 over ink), its last line resting on the bottom gutter - the left
   column is a flex column and margin-top:auto seats it. */
.lab-hero{background:var(--ink);min-height:100svh;padding:0 var(--nav-px) var(--nav-px);
  display:grid;grid-template-columns:calc(50% - 32px) 1fr;gap:32px;align-items:start}
.lab-hero__left{padding-top:calc(var(--nav-h) + var(--nav-px));min-width:0;
  display:flex;flex-direction:column;align-items:flex-start;
  min-height:calc(100svh - var(--nav-px))}
/* THE SET IS PROPORTIONED TO OUR OWN STRINGS, NOT THE REFERENCE'S PIXELS
   (Jenil, 2 Sep: the 200px match "looks oversized" and the paragraph "can be
   bigger"). Its "VM Labs" is 7 characters and fills 59% of the left track;
   our "at the bench" sets 4.26x its font-size of ink, so the same 200px put
   96% of the track under ink and nearly touched the panel. 8.75vw holds a
   CONSTANT 81% of the track at every width below the cap - ink clearance to
   the panel 63 / 101 / 119 / 169 at 1000 / 1280 / 1440 / 1920. Sub 44 and
   paragraph 23 at 1920 rebalance around it (the para up from the reference's
   own 20, on his instruction). The mobile block keeps the 9.9vw phone set. */
.lab-hero__left h1{font-family:var(--serif);font-weight:400;font-size:clamp(52px,8.75vw,168px);line-height:.825;letter-spacing:-.03em;color:var(--bone)}
.lab-hero__sub{font-family:var(--serif);font-size:clamp(26px,2.29vw,44px);line-height:1;color:var(--bone-2);margin-top:clamp(14px,1.35vw,26px)}
.lab-hero__intro{font-size:clamp(16px,1.2vw,23px);line-height:1.05;color:rgba(234,232,233,.82);max-width:clamp(280px,22.14vw,425px);margin-top:auto;padding-top:48px}
.lab-hero__video{width:100%;height:calc(100svh - var(--nav-h) - 2*var(--nav-px));object-fit:cover;display:block;
  margin-top:calc(var(--nav-h) + var(--nav-px));border-radius:clamp(20px,1.667vw,32px)}
.lab-benefits{background:var(--bone);color:var(--ink-d);padding:64px var(--g) 160px}
.lab-benefits__row{list-style:none;display:grid;grid-template-columns:repeat(4,1fr);gap:32px;
  width:min(var(--wrapmax),100%);margin-inline:auto;padding-top:64px}
/* THE FOUR BENEFITS ARE CARDS WITH A DOT, after the reference's own laboratory
   page, which sets its four in rounded panels each carrying a small marker. Ours
   were four loose 234px paragraphs floating on the bone with nothing holding
   them. The card is the site's own light-ground treatment - a --bone-2 fill and
   a hairline, no shadow - so it reads as Calder rather than as an import. */
.lab-benefits__row li{position:relative;max-width:none;font-family:var(--ui);font-size:15px;font-weight:700;
  line-height:1.2;color:var(--ink-d);background:var(--bone-2);border:1px solid rgba(62,62,62,.10);
  border-radius:var(--radius-tile);padding:clamp(46px,3.6vw,54px) 24px 26px;min-height:clamp(150px,13vw,186px);
  display:flex;align-items:flex-start}
.lab-benefits__dot{position:absolute;top:22px;right:22px;width:7px;height:7px;border-radius:50%;
  background:var(--ink-d);opacity:.42}

/* THE FEATURE: the still paired with copy, so the row is not half empty. */
.lab-feature{margin-top:clamp(96px,14vh,200px);display:grid;grid-template-columns:minmax(0,46fr) minmax(0,54fr);
  gap:clamp(32px,5vw,88px);align-items:start;width:100%}
.lab-feature__fig{margin:0;border-radius:var(--radius-tile);overflow:hidden}
.lab-feature__fig img{width:100%;height:auto;aspect-ratio:1100/1410;object-fit:cover;display:block}
.lab-feature__copy{padding-top:clamp(8px,3vw,48px)}
.lab-feature__label{font-family:var(--ui);font-size:var(--nav-fs);font-weight:600;color:var(--ink-d);
  opacity:.55;margin-bottom:clamp(24px,2.6vw,40px)}
.lab-feature__copy p:not(.lab-feature__label){font-family:var(--ui);font-size:clamp(16px,1.16vw,22px);
  font-weight:500;line-height:1.42;color:var(--ink-d);max-width:44ch}
.lab-feature__copy p + p{margin-top:1.15em}
@media(max-width:999px){
  .lab-feature{grid-template-columns:1fr;gap:clamp(28px,7vw,44px)}
  .lab-feature__copy{padding-top:0}
}
.lab-reveal{font-family:var(--serif);font-weight:400;font-size:var(--t-d2);line-height:.93;letter-spacing:-.02em;color:var(--ink-d);
  max-width:968px;margin-top:clamp(96px,14vh,192px)}
@media(min-width:1000px){ .lab-reveal{margin-left:198px} }
/* .lab-benefits__still is retired - replaced by .lab-feature above, 29 Aug. */
/* THE RAIL IS PINNED AND SCRUBBED - IT HOLDS UNTIL EVERY PICTURE HAS PASSED.
   Jenil, 29 Aug: "the img grid should move while scrolling and pinned till all
   images appear". It used to scrub `top 85%` -> `bottom 15%` WITHOUT a pin, so
   the track slid a little as the section went by and most of it was never seen.
   The section is pinned now and the track's travel drives the pin length (the
   same derivation the hero promise uses), so the speed is a constant and does
   not change with the viewport - see calder.js.
   EVERY FIGURE IS aspect-ratio 1.15 AND EVERY SOURCE IS SHIPPED AT 1.15, so
   nothing cover-crops at any width and the row cannot get ragged. The old rule
   fixed a HEIGHT and let the width run, which meant the figure ran 0.49 at 390
   and 1.52 at 1440 - the same picture cropped two different ways. */
/* A PINNED SECTION HAS TO FILL THE VIEWPORT. The rail's figures are ~590px tall,
   so pinning a 719px section left ~180px of the dark FAQ showing underneath for
   the whole hold, which reads as a mistake rather than as a held frame. */
.lab-rail{background:var(--bone);padding:0;overflow:hidden;
  min-height:100svh;display:flex;align-items:center}
.lab-rail__track{display:flex;gap:var(--rail-gap,10px);will-change:transform;width:max-content;
  padding-inline:var(--g)}
.lab-rail__track figure{margin:0;flex:none;width:clamp(240px,46vw,680px);aspect-ratio:1.15;overflow:hidden}
.lab-rail__track img{width:100%;height:100%;object-fit:cover;display:block}
.lab-faq{background:var(--ink);padding:clamp(64px,10.5vh,96px) var(--g)}
.lab-faq__grid{display:grid;grid-template-columns:1fr 1fr;gap:32px;width:min(var(--wrapmax),100%);margin-inline:auto;align-items:start}
.lab-faq__h{font-family:var(--serif);font-weight:400;font-size:clamp(56px,9.5vw,190px);line-height:.84;letter-spacing:-.04em;color:var(--bone)}
.lab-faq__acc{max-width:688px;width:100%}
.lab-faq__acc details{border-bottom:1px solid var(--line)}
.lab-faq__acc details:first-of-type,.lab-faq__more details:first-of-type{border-top:0}
.lab-faq__acc > details:first-child{border-top:1px solid var(--line)}
.lab-faq__acc summary{font-family:var(--ui);font-size:15px;font-weight:700;line-height:1.13;color:var(--bone-2);
  min-height:97px;display:flex;justify-content:space-between;align-items:center;gap:24px;cursor:pointer;list-style:none;
  transition:color var(--ui-dur) var(--ease-out)}
.lab-faq__acc summary::-webkit-details-marker{display:none}
.lab-faq__acc summary>span{position:relative}
.lab-faq__acc summary>span::after{content:"";position:absolute;left:0;right:0;bottom:-4px;height:1px;background:currentColor;
  transform:scaleX(0);transform-origin:100% 50%;transition:transform var(--ui-dur) var(--ease-out)}
.lab-faq__acc summary::after{content:"+";font-weight:400;font-size:22px;color:var(--muted);flex:none;
  transition:transform var(--ui-dur) var(--ease-out)}
.lab-faq__acc details[open] summary{color:var(--bone)}
.lab-faq__acc details[open] summary::after{transform:rotate(45deg)}
@media(hover:hover) and (pointer:fine){
  .lab-faq__acc summary:hover{color:var(--bone)}
  .lab-faq__acc summary:hover>span::after{transform:scaleX(1);transform-origin:0 50%}
}
.lab-faq__acc summary:focus-visible{color:var(--bone)}
.lab-faq__acc summary:focus-visible>span::after{transform:scaleX(1);transform-origin:0 50%}
.lab-faq__acc details p{font-size:15px;line-height:1.5;color:var(--bone-2);max-width:56ch;padding-bottom:28px}
.lab-faq__acc details p+p{margin-top:-12px}
.lab-faq__more{overflow:hidden}
.lab-faq__more[hidden]{display:none}
.lab-faq__all{margin-top:48px}
.lab-faq__all{border-radius:999px}
.lab-close{position:relative;min-height:clamp(720px,131svh,1180px);overflow:hidden;display:grid;place-items:center;padding:120px var(--g)}
.lab-close__bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;will-change:transform}
.lab-close::before{content:"";position:absolute;inset:0;background:rgba(16,18,22,.58);z-index:0}
.lab-close__box{position:relative;z-index:1;width:min(792px,100%)}
.lab-close__title{font-family:var(--serif);font-weight:400;font-size:clamp(36px,3.82vw,60px);line-height:.95;letter-spacing:-.02em;
  color:var(--bone);text-align:center;margin-bottom:clamp(36px,6vh,64px)}
@media(max-width:999px){
  .lab-hero{grid-template-columns:1fr;min-height:0;padding:0 var(--g) 32px}
  .lab-hero__left{padding-top:140px;min-height:0}
  .lab-hero__left h1{font-size:clamp(52px,9.9vw,153px)}
  .lab-hero__intro{font-size:15px;line-height:1.5;max-width:282px;margin-top:clamp(48px,10vh,110px);padding-top:0}
  .lab-hero__video{margin-top:48px;height:56svh}
  .lab-benefits__row{grid-template-columns:1fr 1fr;gap:24px}
  .lab-reveal{margin-left:0}
  .lab-faq__grid{grid-template-columns:1fr}
  .lab-faq__acc summary{min-height:76px}
}
@media(max-width:600px){ .lab-benefits__row{grid-template-columns:1fr} }

/* ---------- contact ---------- */
/* ---- the studios: the reference's expanding panels ----------------------
   Measured off av-contact.mp4 at 1920. Collapsed, each of its three panels is
   640 wide on bone with a centred serif name (a 81px CAP, cap-top 299), a
   two-line address at 17.9 on a 22px pitch (cap-top 452), a serif number at a
   33px cap = 44px (cap-top 535) and a 278 x 278 picture whose foot sits 43px
   off the viewport bottom. On hover that panel goes to 960 and the other two to
   480 - flex 2:1:1 - over about 0.6s: the picture opens from the square to full
   bleed, the name grows to a 150px cap (1.85x) and rises, the type turns bone,
   and a pill lands at the bottom right on the same 43px inset with the hours at
   the bottom left. Ours is two panels, so the swing is 2:1.
   Two deliberate departures. (1) The panels start BELOW the header band: the
   reference runs its photo behind its own header and leaves the logo, Menu and
   Services barely legible on it. (2) The pill is Book a call, not View on Map -
   a map pin would assert an address this studio does not have. */
.locs{background:var(--bone);color:var(--ink-d);padding:var(--nav-h) 0 0}   /* the global section gutter is off here: the panels are full bleed */
.locs__row{display:flex;height:calc(100svh - var(--nav-h));min-height:600px}
.loc{position:relative;overflow:hidden;flex:1 1 0;min-width:0;
  padding:clamp(40px,21.1vh,203px) clamp(16px,2.1vw,40px) 0;text-align:center;
  transition:flex-grow var(--loc-dur) var(--ease-swap),padding-top var(--loc-dur) var(--ease-swap)}
.loc + .loc{border-left:1px solid rgba(16,18,22,.14)}
/* the reference's picture sits with its top at 63% of the panel and its foot
   43px off the bottom (4.98%); 32% either side keeps it near-square at rest */
.loc__pic{position:absolute;inset:63% 32% 4.98% 32%;margin:0;overflow:hidden;z-index:0;
  transition:inset var(--loc-dur) var(--ease-swap)}
.loc__pic img{width:100%;height:100%;object-fit:cover;display:block}
.loc__body{position:relative;z-index:1}
.loc__name{font-family:var(--serif);font-weight:400;font-size:clamp(30px,4.58vw,88px);line-height:.94;letter-spacing:-.02em;
  color:var(--ink-d);transition:font-size var(--loc-dur) var(--ease-swap),color var(--loc-dur) var(--ease-swap),
  text-shadow var(--loc-dur) var(--ease-swap)}
.loc__addr{margin-top:clamp(16px,1.7vw,33px);font-size:var(--f-body);line-height:1.23;color:#5F656D;
  transition:color var(--loc-dur) var(--ease-swap),font-weight var(--loc-dur) var(--ease-swap),
  text-shadow var(--loc-dur) var(--ease-swap)}
.loc__tel{margin-top:clamp(18px,1.9vw,36px);font-family:var(--serif);font-weight:400;
  font-size:clamp(20px,2.29vw,44px);line-height:1;color:var(--ink-d);
  transition:color var(--loc-dur) var(--ease-swap),text-shadow var(--loc-dur) var(--ease-swap)}
.loc__tel a{color:inherit;text-decoration-color:transparent;text-underline-offset:6px}
.loc__foot{position:absolute;left:var(--nav-px);right:var(--nav-px);bottom:clamp(24px,4.4vh,43px);z-index:2;
  display:flex;align-items:flex-end;justify-content:space-between;gap:24px;
  opacity:0;pointer-events:none;transition:opacity var(--loc-dur) var(--ease-swap)}
.loc__hours{font-size:var(--f-fine);line-height:1.152;display:grid;grid-template-columns:auto 1fr;
  column-gap:clamp(14px,1.46vw,28px);text-align:left;
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.loc__hours span:first-child{color:var(--bone-2)}
.loc__hours span+span{color:var(--bone)}
/* the open state. It is driven by :hover and by :focus-within, so the panel
   opens for the keyboard too - the pill inside it is taken out of the tab order
   until then, or Tab would land on a control nobody can see. */
@media(hover:hover) and (pointer:fine){
  .loc:hover{flex-grow:2;padding-top:clamp(28px,10.1vh,97px)}
  .loc:hover .loc__pic{inset:0}
  .loc:hover .loc__name{font-size:clamp(44px,9.4vw,180px);color:var(--bone);
    text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  .loc:hover .loc__addr{color:var(--bone);font-weight:700;
    text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  .loc:hover .loc__tel{color:var(--bone);
    text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  .loc:hover .loc__foot{opacity:1;pointer-events:auto}
  .loc:hover .loc__tel a:hover{text-decoration-color:currentColor}
}
.loc:focus-within{flex-grow:2;padding-top:clamp(28px,10.1vh,97px)}
.loc:focus-within .loc__pic{inset:0}
.loc:focus-within .loc__name{font-size:clamp(44px,9.4vw,180px);color:var(--bone);
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.loc:focus-within .loc__addr{color:var(--bone);font-weight:700;
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.loc:focus-within .loc__tel{color:var(--bone);
  text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
.loc:focus-within .loc__foot{opacity:1;pointer-events:auto}
@media(max-width:999px){
  /* no hover to open it with, so each panel ships open: the picture is the
     ground and the type sits on it in bone */
  .locs__row{display:block;height:auto}
  .loc{padding:clamp(56px,12vh,120px) var(--g) clamp(150px,22vh,190px);min-height:70svh}
  .loc + .loc{border-left:0;border-top:1px solid rgba(16,18,22,.14)}
  .loc__pic{inset:0}
  .loc__name{font-size:clamp(34px,10vw,64px);color:var(--bone);
    text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  .loc__addr,.loc__tel{color:var(--bone);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
  .loc__addr{font-weight:700}
  .loc__foot{opacity:1;pointer-events:auto;flex-direction:column;align-items:flex-start;gap:20px;left:var(--g);right:var(--g)}
}
.contact-cta{background:var(--ink);overflow:hidden;padding-block:clamp(48px,8vh,110px) clamp(56px,9vh,110px);text-align:center}
.contact-cta__mega{font-family:var(--serif);font-weight:400;font-size:var(--t-giant);line-height:.84;letter-spacing:-.04em;color:var(--bone);white-space:nowrap}
/* the close's crossing (1 Sep): the pre-footer's exclusion grammar on the
   practitioner silhouette. One colour; the ground decides the shade. The line
   is anchored at 46% of the frame so 'talk' runs onto the head - the backdrop
   reads 204-228 on the left and the silhouette 0-20, so the pair of shades is
   the same bimodal ground the device needs, and the features are unreadable
   black, so nothing sits "on a face". The mega keeps its size and simply
   crosses instead of being cut by the picture's own straight edge. */
.ccta__frame{position:relative;isolation:isolate;margin-top:0;
  /* full-bleed: the section carries the global --gut padding, so the frame
     cancels exactly it - the same reasoning as .film-labels and --nav-px */
  margin-inline:calc(-1 * var(--gut))}
.ccta__figure{margin:0;width:100%;max-width:none}
.ccta__figure img{width:100%;height:auto;display:block;filter:grayscale(1) contrast(1.04);
  transform:scale(var(--ccs,1));transform-origin:50% 50%;will-change:transform}
.ccta__frame::before,.ccta__frame::after{content:"";position:absolute;left:0;right:0;z-index:1;pointer-events:none}
.ccta__frame::before{top:0;height:clamp(70px,12vh,150px);background:linear-gradient(to bottom,var(--ink),rgba(16,18,22,0))}
.ccta__frame::after{bottom:0;height:clamp(70px,12vh,150px);background:linear-gradient(to top,var(--ink),rgba(16,18,22,0))}
.ccta__mega{position:absolute;z-index:2;top:50%;left:48%;margin:0;
  transform:translate(-50%,-50%) translateX(var(--ccx,0px));will-change:transform;
  color:rgb(212,210,211);mix-blend-mode:exclusion}
@supports not (mix-blend-mode:exclusion){
  .ccta__mega{color:var(--bone);text-shadow:0 1px 2px rgba(16,18,22,.38),0 4px 30px rgba(16,18,22,.55)}
}
@media(max-width:999px){
  /* stacked and static on a phone, like every scrubbed set-piece */
  .ccta__mega{position:static;transform:none;mix-blend-mode:normal;color:var(--bone);
    white-space:normal;padding-inline:var(--g);margin-bottom:24px}
  .ccta__frame{display:flex;flex-direction:column-reverse}
}
.contact-cta__line{font-family:var(--serif);font-size:clamp(24px,2.4vw,36px);color:var(--bone);margin-top:6vh;padding-inline:var(--g)}
@media(max-width:999px){
  .contact-cta__mega{white-space:normal}
}

/* ============================================================
   THE HOME LOADING SCREEN. index.html only - the four internal pages carry
   neither the markup nor the head flag.

   It is composed of the SAME approved geometry the header wordmark uses, taken
   apart so the two halves can move independently: the word is the outlined
   CALDER path out of assets/brand/calder-open-rail-on-dark.svg, and the rail is
   a 2px line at the file's own coordinates - x 248..1352 of 1600 is 15.5% in
   from each edge, and y 260 of 520 is the box's own mid-line, so the rail sits
   dead centre of the stage and the stage sits dead centre of the viewport. That
   is what lets step 6 rotate it about its own centre and land exactly on the
   viewport's vertical centre line, which is where the two panels then part.

   Scale is the approved poster's: its rail measures 2549px of a 4800 canvas,
   and the rail is 89.75% of the mark, so the mark is 59.2% of the viewport
   width, centred. Floored at 240px so the letters survive a 390 phone.

   Nothing here animates layout: the rail is transform-only, the word is a
   symmetrical clip-path inset driven by --rev, and the panels translate. No
   blur, no scale on any form, no loop.
   ============================================================ */
html.is-loading{overflow:hidden;background:var(--ink)}   /* the lock and the class are ONE thing,
   so removing the class can never strand the scroll lock */
html:not(.has-js) .loader,html:not(.is-loading) .loader{display:none}
.loader{position:fixed;inset:0;z-index:999;overflow:hidden}
.loader__panel{position:absolute;top:0;bottom:0;width:calc(50% + 1px);background:var(--ink)}
.loader__panel--l{left:0}
.loader__panel--r{right:0}
.loader__stage{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1;
  width:clamp(240px,59.2vw,1180px);aspect-ratio:1600/520}
/* the reveal is symmetrical about the rail: --rev 0 is a zero-height slot ON
   the rail line, --rev 1 is the whole box */
.loader__word{position:absolute;inset:0;width:100%;height:100%;display:block;
  --rev:0;clip-path:inset(calc(50% * (1 - var(--rev))) 0)}
/* 15.5% = 248/1600 and (1600-1352)/1600 - the file's own rail inset after the
   26 Aug shortening, both ends. It has to stay EQUAL at both ends: that is what
   puts the rail's centre on the stage's centre, and therefore on the viewport's,
   which is where the quarter turn lands it and where the panels part. */
.loader__rail{position:absolute;left:15.5%;right:15.5%;top:calc(50% - 1px);height:2px;
  background:#42464D;transform-origin:50% 50%}

/* ============================================================
   THE STUDIO PAGE. Built to the reference's about/team grammar, measured off
   https://aventuradentalarts.com/about at 1920x1080 on 28 Aug:

     gutter            43px, i.e. --nav-px, the same gutter the footer uses
     content width     1835 (43 -> 1877), grid gap 32
     partner card      3 x 590 on a 32 gap; INSIDE it, top to bottom:
                       a 16px/500 role label at 40% opacity, then the name in
                       Instrument Serif at 73.3px / lh 63.8 / ls -2.199 (-3%),
                       then a 584 x 757 portrait (aspect .771, object-fit cover,
                       no radius, no filter - colour, not monochrome), then a
                       16px/500 bio. Its name and label are rgb(66,67,70) - a
                       GRAPHITE on a LIGHT ground - which is why our founder and
                       people sections are bone, not ink.
     doctor card       4 x 435, name one step down at 46.7px (2.43vw)
     staff list        a two-column display table: the role at the 43 gutter and
                       the name at x=1096 (57.1% of the viewport), BOTH set at
                       73.3px Instrument Serif, on a 192px row pitch
     counter           "20+" at 73.3px serif with "Specialists" at 16px/500 beside it

   73.3px at 1920 is 3.82vw, which is EXACTLY the curve --pi-title already
   carries for the planning index - so the display names on this page cost no
   new token. Only the secondary card name needed one.
   ============================================================ */

/* ---------- 01-04 · THE REFERENCE'S ABOUT PAGE, TO THE "ADA PARTNERS" ROW
   Measured 29 Aug off `about.mp4` at 1920 AND off the live DOM of
   aventuradentalarts.com/about, which is where every figure below comes from.
   Its run of sections, in order: a group photograph under a scrubbing band of
   giant words; a small three-line note at the half-width; a display statement
   revealed word by word; a small centred label; an enormous centred heading;
   then the three partner cards.

   THE TYPE, ALL OF IT MEASURED AT 1920 AND CONVERTED TO vw (/19.2):
     word band     368px/400 serif, lh .84 (309.1), ls -.04em, bone at op .3
     note block    26.7px/600 InterTight, lh 1.09 (29.1), ls -.02em, bone at 40%
     statement     110.7px/400 serif, lh .93 (102.92), ls -.02em, x307 w1195
     small label   16px/500 InterTight, lh 1.19 (19), bone, centred
     mega heading  438.7px/400 serif, lh .90 (394.8), ls -.05em, centred, and
                   its ink measures 1710 of 1920 - 89% of the frame
   ---------- */
/* THE HERO PICTURE IS THE WHOLE PHOTOGRAPH, UNCROPPED, AND THE SECTION IS TALLER
   THAN THE VIEWPORT BECAUSE OF IT. Jenil, 29 Aug: "use the full img of team
   portrait here". It used to be a 62svh box on object-fit:cover, which at 1920
   threw away 402px of a 960px picture - 35% off the bottom, i.e. all three of
   them cut at the thigh. The figure now runs at the file's own 1774:887, so its
   height IS half the frame's width and nothing is cropped at any viewport.
   A 2:1 picture full-bleed cannot share one 100svh screen with the word band at
   16:9 or wider - the arithmetic simply does not close - and the reference does
   not try: measured on its own about page at 1440, its hero section is 1,906px
   (2.1 viewports) around a 1440x1104 photograph rendered at native size with
   nothing cropped. So the section grows instead, and --ab-top is the room the
   line and the band need above the picture, stated once. */
:root{ --ab-top:calc(var(--nav-h) + 3.4vh + var(--ab-nav) * 3); }
.ab-hero{position:relative;min-height:100svh;overflow:hidden;background:var(--ink);color:var(--bone);
  display:flex;flex-direction:column;justify-content:flex-end;
  padding:calc(var(--ab-top) + (.84 - .346) * var(--ab-band)) 0 0}
.ab-hero__line{position:absolute;top:calc(var(--nav-h) + 3.4vh);left:0;right:0;z-index:3;margin:0;text-align:center;
  font-size:var(--ab-nav);font-weight:500;line-height:1.13;letter-spacing:-.01em;color:rgba(233,231,231,.4)}
/* one positioned box holds the band and the picture, so the band is seated off
   the PICTURE's own height (100% of the stack) rather than off a literal 62svh */
.ab-hero__stack{position:relative;width:100%}
/* the band is nowrap and deliberately wider than the frame so it has somewhere
   to travel; .ab-hero's own overflow:hidden is what stops the page scrolling
   sideways, exactly as .st-people's did */
.ab-hero__band{position:absolute;bottom:calc(100% - .346 * var(--ab-band));left:0;z-index:1;margin:0;display:flex;white-space:nowrap;
  gap:clamp(30px,3.6vw,70px);pointer-events:none;
  font-family:var(--serif);font-weight:400;font-size:var(--ab-band);line-height:.84;letter-spacing:-.04em;
  color:rgba(234,232,232,.3);will-change:transform;transform:translate3d(var(--ab-wx,0px),0,0)}
/* THE MASK IS ON THE FIGURE, NOT THE IMAGE, so it takes the edge overlay with
   it: the top has to stay a real mask (transparent, not an ink wash) or the
   band's words - which sit BEHIND the picture - would be painted over. */
.ab-hero__fig{position:relative;z-index:2;margin:0;width:100%;overflow:hidden;
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 9%);
  mask-image:linear-gradient(to bottom,transparent 0,#000 9%)}
.ab-hero__fig img{width:100%;height:auto;display:block;transform-origin:50% 50%;
  transform:scale(var(--ab-figs,1));will-change:transform}
/* THIS PICTURE IS BONE ON AN INK PAGE, so the three edges the mask does not
   reach are faded into --ink rather than left as a cut rectangle - the same
   device .pf__frame::before and .tech-hero::before already use. 6% at the sides:
   the outermost subject's arm starts at 8.2% of the frame, so the fade is on
   backdrop only. */
.ab-hero__fig::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(to right,var(--ink),rgba(16,18,22,0) 6%,rgba(16,18,22,0) 94%,var(--ink)),
             linear-gradient(to top,var(--ink),rgba(16,18,22,0) 13%)}

/* (the half-width note section was removed 3 Sep on Jenil's instruction; the
   --ab-note token stays - the partner cards' Read More roll reads it) */

/* the display statement, revealed word by word. The reference sets its unread
   words at rgb(66,67,70) on its ink ground, which is bone at .22 over ours -
   measured, that renders rgb(63,64,71) against its 66,67,70. The top padding
   is the note section's old stanza air, carried by the statement itself now
   that the note is gone (its 0 relied on the note above). */
.ab-belief{background:var(--ink);color:var(--bone);padding:clamp(90px,12vw,220px) var(--nav-px) clamp(90px,12vw,220px)}
.ab-belief p{margin:0 0 0 14.4%;max-width:10.8em;
  font-family:var(--serif);font-weight:400;font-size:var(--ab-belief);line-height:.93;letter-spacing:-.02em;
  color:var(--bone)}

/* the partner row (its centred label above the mega was removed 3 Sep on
   Jenil's instruction - the heading opens the section alone) */
.ab-partners{background:var(--ink);color:var(--bone);padding:0 var(--nav-px) clamp(90px,12vw,220px)}
.ab-partners__h{margin:0 0 clamp(30px,3.4vw,66px);text-align:center;white-space:nowrap;
  font-family:var(--serif);font-weight:400;font-size:var(--ab-mega);line-height:.90;letter-spacing:-.05em;
  color:var(--bone)}
.ab-cards{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(14px,1.67vw,32px)}

/* THE CARD, measured on the live DOM: 590 x 809, radius 40, white at rest and
   rgb(13,13,19) on hover, everything on ONE 0.35s ease-in-out. Every inside
   offset is a percentage of the card's own height (809), so the whole card
   scales with its track and nothing has to be re-tuned per width. */
.ab-card{position:relative;overflow:hidden;border-radius:clamp(18px,2.08vw,40px);
  background:#fff;aspect-ratio:590/809;min-width:0;
  transition:background-color var(--ab-dur) var(--ab-ease)}
.ab-card__role{position:absolute;top:3.955%;left:6%;right:6%;z-index:3;margin:0;text-align:center;
  font-size:var(--ab-small);font-weight:500;line-height:1.19;color:rgba(66,67,70,.4);
  transition:color var(--ab-dur) var(--ab-ease)}
.ab-card__name{position:absolute;top:8.900%;left:3%;right:3%;z-index:3;margin:0;text-align:center;
  font-family:var(--serif);font-weight:400;font-size:var(--pi-title);line-height:.87;letter-spacing:-.03em;
  color:rgb(66,67,70);transition:color var(--ab-dur) var(--ab-ease)}
.ab-card__fig{position:absolute;top:16.81%;left:50%;width:98.98%;transform:translateX(-50%);
  margin:0;z-index:1}
.ab-card__fig img{width:100%;height:auto;display:block}
.ab-card__bio{position:absolute;top:76.39%;left:21.1%;right:21.1%;z-index:3;margin:0;text-align:center;
  font-size:var(--ab-small);font-weight:500;line-height:1.19;color:var(--bone);
  opacity:0;transition:opacity var(--ab-dur) var(--ab-ease)}
.ab-card__more{position:absolute;top:92.09%;left:0;right:0;z-index:3;display:flex;justify-content:center}
/* the roll: two stacked copies in a window one line tall, exactly the grammar
   the header and footer links already use. The reference moves them 33.42px in
   a 32px window, i.e. one line. */
.ab-card__roll{display:block;overflow:hidden;font-size:var(--ab-note);height:1.09em;
  border-bottom:2px solid currentColor;color:rgb(66,67,70);
  transition:color var(--ab-dur) var(--ab-ease)}
.ab-card__roll span{display:block;
  font-size:1em;font-weight:600;line-height:1.09;letter-spacing:-.02em;
  transition:transform var(--ab-dur) var(--ab-ease)}

/* ALL THREE CARDS FLIP NOW. Guillem's exception is gone: his portrait is shot
   on Calder Ink, and the 29-Aug verdict that his tunic sat inside that sweep's
   noise was measuring a fit poisoned by his own hair. With the background
   sample corrected the sweep models to 1.30 levels - its own grain - and his
   tunic reads 5.9 above it. See SOURCES.md. `.ab-card--dark` and its three
   colour rules went with it. */
/* THE BIO SLOT IS BOTTOM-ANCHORED AND WIDER BELOW 1440, AND ONLY BELOW IT.
   The card was fitted to the reference at 1920, where the bio sits at top
   76.39% in a 341px column - and to bios of about 150 characters. The three
   supplied biographies run ~240, and the card scales with its track: at 1000
   the column is 174px wide and nine lines of it ran 74px PAST the Read More
   control (the old copy already ran 13px past it there). Measured at 1440 and
   1520 and above the reference geometry still holds - the tightest is 11px of
   clearance at 1600 - so it is left exactly as measured; below 1520 (where
   1440 clears by only 2px) the slot hangs from just above the control
   and takes 84% of the card, so long copy grows UP into the picture - which
   on hover is the card's own dark ground - instead of over the control. */
@media(max-width:1519px){
  .ab-card__bio{top:auto;bottom:9.9%;left:8%;right:8%}
}

@media(hover:hover) and (pointer:fine){
  .ab-card:hover{background:rgb(13,13,19)}
  .ab-card:hover .ab-card__role{color:var(--bone)}
  .ab-card:hover .ab-card__name,.ab-card:hover .ab-card__roll{color:var(--bone)}
  .ab-card:hover .ab-card__bio{opacity:1}
  .ab-card:hover .ab-card__roll span{transform:translateY(-100%)}
}
.ab-card:focus-within{background:rgb(13,13,19)}
.ab-card:focus-within .ab-card__role{color:var(--bone)}
.ab-card:focus-within .ab-card__name,.ab-card:focus-within .ab-card__roll{color:var(--bone)}
.ab-card:focus-within .ab-card__bio{opacity:1}
.ab-card:focus-within .ab-card__roll span{transform:translateY(-100%)}
.ab-card a{position:absolute;inset:0;z-index:4;border-radius:inherit;outline-offset:-4px}

@media(prefers-reduced-motion:reduce){
  .ab-card,.ab-card__role,.ab-card__name,.ab-card__bio,.ab-card__roll,.ab-card__roll span{transition:none}
}

/* below 1000 the row stacks and the mega heading is allowed to wrap */
@media(max-width:999px){
  .ab-hero{min-height:auto;padding-top:calc(var(--nav-h) + 8vh)}
  .ab-hero__line{position:static;padding:0 var(--g) 5vh}
  /* in flow here, so the offset the desktop rule uses has to be cancelled:
     with position:relative and top:auto a `bottom` is NOT ignored - it moves
     the element UP by that much. The pull-up on a phone is the margin. */
  .ab-hero__band{position:relative;top:auto;bottom:auto;margin-bottom:-2vh}
  .ab-belief,.ab-partners{padding-inline:var(--g)}
  .ab-belief p{margin-left:0;max-width:none}
  .ab-partners__h{white-space:normal}
  .ab-cards{grid-template-columns:1fr;gap:26px}
}

/* kept for sections 05 and 06, which are unchanged */
.st-eyebrow{margin:0 0 clamp(18px,1.7vw,32px);font-size:var(--f-label);font-weight:500;line-height:1.19;
  color:rgba(234,232,233,.4)}
.st-list dt,.st-list__place{font-family:var(--serif);font-weight:400;
  font-size:var(--pi-title);line-height:.87;letter-spacing:-.03em}

/* ---------- 05 · two studios ----------
   The reference's staff table: role at the 43 gutter, value at 57.1% of the
   viewport, both at the display size, on a ruled row. */
.st-studios{background:var(--ink);color:var(--bone);padding:clamp(96px,12vw,220px) var(--nav-px) clamp(72px,9vw,160px)}
.st-studios__h{font-family:var(--serif);font-weight:400;font-size:clamp(32px,4.2vw,80px);line-height:.96;
  letter-spacing:-.03em;margin:0 0 clamp(20px,1.8vw,34px);color:var(--bone);max-width:16em}
.st-studios__copy{margin:0 0 clamp(56px,6vw,110px);max-width:36em;font-size:var(--f-body);line-height:1.42;color:var(--bone-2)}
.st-list{margin:0;padding:0}
.st-list__row{display:grid;grid-template-columns:57.1% 1fr;gap:clamp(16px,2vw,40px);align-items:baseline;
  padding:clamp(26px,3vw,58px) 0;border-top:1px solid rgba(234,232,233,.16)}
.st-list__row:last-child{border-bottom:1px solid rgba(234,232,233,.16)}
.st-list dt{margin:0;color:var(--bone)}
.st-list dd{margin:0;min-width:0}
.st-list__place{display:block;color:var(--bone)}
.st-list__note{display:block;margin-top:clamp(10px,.9vw,18px);font-size:var(--f-fine);line-height:1.5;color:var(--muted)}

/* ---------- 06 · closing ---------- */
/* ---------- 06 · the closing CTA (the reference's about-page final) ----------
   Measured on its live DOM at 1920: 204px serif (10.625vw - the site's own
   --t-hero curve), line-height .8 (163.2/204), ls -3%, graphite, centred, and
   the pill 43px under the line's box. Centred by Jenil's explicit instruction
   (1 Sep) - this joins the named centred set-pieces. The dome (.pf__curve)
   follows in flow and overlaps this section's foot, so the bottom padding
   holds the pill clear of the dome's apex: apex overlap is 5.322vw + 20px,
   and 13.5vw of padding leaves >5vw of air above it. */
.scta{background:var(--bone);color:var(--ink-d);text-align:center;
  padding:clamp(90px,8.9vw,170px) var(--g) clamp(170px,13.5vw,260px)}
/* sized to the reference's INK SHARE, not its pixels (the standing rule): its
   "Consultation" fills 48.6% of the frame at 10.625vw; "conversation" is a
   narrower string and filled 42.1% there, so 48.6/42.1 x 10.625 = 12.27vw.
   Measured back onto 48.6% at 1920. Re-measure if the wording changes. */
.scta__h{margin:0 0 clamp(28px,2.24vw,43px);font-family:var(--serif);font-weight:400;
  font-size:clamp(40px,12.27vw,236px);line-height:.8;letter-spacing:-.03em;color:var(--ink-d)}
.scta__h span{display:block}
/* the ink pill on the bone ground - the same inversion #planning's button had */
.scta .btn{background:var(--ink);color:var(--bone)}
.scta__copy{margin:clamp(28px,2.6vw,50px) auto 0;max-width:34em;
  font-size:var(--f-body);line-height:1.42;color:#5F656D}
/* the page states its own fiction, so nobody has to go to Legal & IP to find it.
   (It sat on the ink closing until 1 Sep; these are its bone-ground tones -
   #5F656D reads 4.87:1 here where --muted reads 3.11.) */
.st-fiction{margin:clamp(56px,6vw,110px) auto 0;padding-top:clamp(20px,1.8vw,34px);
  border-top:1px solid rgba(62,62,62,.18);max-width:52em;
  font-size:var(--f-fine);line-height:1.5;color:#5F656D}

/* ---------- below 1000px ---------- */
@media(max-width:999px){
  .st-hero{min-height:auto}
  /* the seam is a desktop composition; on a phone the picture is a block above
     a bone card and the line is set once, in ink */
  .st-hero__bone,.st-hero__fig{position:relative;inset:auto}
  .st-hero__fig{height:58vh}
  .st-hero__eyebrow{position:static;padding:28px var(--g) 0}
  .st-hero__line{position:static;padding:18px var(--g) 0;clip-path:none;font-size:clamp(32px,8.4vw,54px)}
  .st-hero__line--bone{display:none}
  .st-hero__line--ink{color:var(--ink-d)}
  .st-hero__intro{position:static;width:auto;padding:18px var(--g) 40px;margin:0}
  .st-principle,.st-studios{padding-inline:var(--g)}
  .st-founder,.st-people{padding-inline:var(--g);grid-template-columns:1fr}
  .st-band{grid-template-columns:repeat(2,minmax(0,1fr));gap:24px}
  .st-cards{grid-template-columns:1fr;gap:56px}
  .st-card{text-align:left}
  .st-list__row{grid-template-columns:1fr;gap:10px}
}
@media(max-width:560px){ .st-band{grid-template-columns:1fr} }

/* ============================================================
   THE TEAM BLOCK, off the reference's own two recordings (28 Aug).

   HOME (team.mp4 at 1920): one display line - "Team of Experts", ink bbox
   roughly x 61..1848, i.e. 93% of the viewport, cap about 235px, so the face is
   set near 326px = 17vw - with the group photograph layered OVER its lower
   half. The people occlude the letters and the words still read between them,
   which means their photograph is a CUT-OUT. Ours is not: the three are in dark
   tailoring on a dark ground, so a luminance mask would eat the suits. The
   picture's top edge is faded into the section instead - the line reads through
   the fade and no rectangle edge shows. That is the one departure.

   ABOUT (about.mp4): the same device again behind the partner cards, plus a
   band of repeating words. The band is SCROLL-LINKED, not a marquee: measured
   across thirty frames with the page held still, it moves 0px. Calder scrubs it
   the way it already scrubs the hero promise line.
   ============================================================ */
#team{background:var(--ink);color:var(--bone);overflow:hidden;
  padding:clamp(88px,11vw,200px) var(--nav-px) clamp(64px,8vw,140px)}
/* one line, never wrapped - it is sized so it cannot wrap, and measured after */
.team__h{margin:0;text-align:center;white-space:nowrap;position:relative;z-index:0;
  font-family:var(--serif);font-weight:400;font-size:var(--team-fs);
  line-height:.84;letter-spacing:-.03em;color:var(--bone)}
/* THE PULL-UP IS SOLVED, NOT GUESSED - AND IT IS A calc(), NOT A clamp().
   It has to land the heads on the display line's mid-height, so it is
   headTop + halfLineBox, and BOTH terms are exact rather than fitted:
     headTop     the new group frame is 1774x887, so its displayed height is
                 half the viewport width, and the heads begin at 13.3% of it
                 -> 0.133 * 0.5vw = 6.65vw
     halfLineBox the line box is font-size * line-height .84, so half of it is
                 .42 * the font size, whether that is on the vw curve or capped.
   Sharing --team-fs with .team__h is what stops the two drifting apart.
   The mask must FINISH before the heads arrive or they emerge half-transparent:
   7% against heads at 13.3% clears it with room to spare.
   (This rule was clamp(-70px,-8.9vw,-171px) until 28 Aug. clamp() resolves as
   max(MIN,min(VAL,MAX)); with the bounds written the wrong way round for
   negative numbers that is -70px at EVERY width, so the pull-up it documents
   never actually happened. Never write a negative clamp() most-negative-last.) */
.team__fig{margin:calc(-.346 * var(--team-fs)) 0 0;position:relative;z-index:1}
.team__fig img{width:100%;height:auto;display:block;
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 11%);
  mask-image:linear-gradient(to bottom,transparent 0,#000 11%)}
/* THE PICTURE MELTS INTO THE GROUND ON ITS OTHER THREE EDGES TOO (1 Sep,
   Jenil: "the team portrait should blend with background, it's frame is
   visible") - the photograph's studio black is not the page's ink, so its
   rectangle printed, hardest at the bottom where the cut crosses the ivory
   blazer. The top already dissolves through the img's own mask so the
   headline reads through it; the sides and the foot take an ink wash - the
   same three-edge device the studio hero carries. The overlay sits on the
   FIGURE, not the img, so the mask underneath cannot thin it.
   THE OVERLAY STARTS BELOW THE HEADLINE'S INK - top:17%, not 0. With inset:0
   the side washes painted over the letters' lower halves at the line's two
   ends (the T and the r live inside the 6% side zones), and the dissolve
   read as a hard half-fill (Jenil, 1 Sep, with the T and r circled). The
   letters reach ~14.5% down the figure (ink bottom = picture top + 56% of
   the ink, on the .346 pull-up), so 17% clears them at every width - both
   the ink and the figure scale with vw. */
.team__fig::after{content:"";position:absolute;inset:17% 0 0;pointer-events:none;
  background:
    linear-gradient(to right,var(--ink),rgba(16,18,22,0) 6%),
    linear-gradient(to left,var(--ink),rgba(16,18,22,0) 6%),
    linear-gradient(to top,var(--ink),rgba(16,18,22,0) 17%)}
/* a caption under each figure, on the reference's own three-up */
.team__caps{list-style:none;margin:clamp(28px,3vw,56px) 0 0;padding:0;
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(20px,2.4vw,46px)}
.team__name{margin:0;font-family:var(--serif);font-weight:400;font-size:var(--st-name2);
  line-height:.94;letter-spacing:-.03em;color:var(--bone)}
.team__role{margin:clamp(8px,.7vw,13px) 0 0;font-size:var(--f-label);font-weight:500;line-height:1.19;
  color:rgba(234,232,233,.4)}
.team__line{margin:clamp(10px,.9vw,17px) 0 0;font-size:var(--f-fine);line-height:1.5;color:var(--bone-2);max-width:24em}
.team__ctaw{margin-top:clamp(36px,4vw,76px)}
@media(max-width:999px){
  #team{padding-inline:var(--g)}
  #team{--team-fs:clamp(38px,11vw,72px)}
  .team__h{white-space:normal;text-align:left}
  .team__fig{margin-top:calc(-.346 * var(--team-fs))}
  .team__caps{grid-template-columns:1fr;gap:34px}
}

/* the word band behind the studio cards - scrubbed, never on a clock */
.st-word{grid-column:1/-1;margin:clamp(-10px,-1vw,-20px) 0 clamp(-46px,-5vw,-96px);padding:0;
  display:flex;gap:clamp(28px,3.4vw,66px);white-space:nowrap;pointer-events:none;
  font-family:var(--serif);font-weight:400;font-size:clamp(52px,11.6vw,223px);line-height:.9;
  letter-spacing:-.03em;color:rgba(234,232,233,.07);
  will-change:transform;transform:translate3d(var(--st-wx,0px),0,0)}
@media(max-width:999px){ .st-word{display:none} }
/* ---------- reduced motion: kill eases AND delays (the menu's visibility
   handoff rides on a transition-delay, which a duration override alone
   would leave running) ---------- */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:.01ms !important;transition-delay:0s !important;
    animation-duration:.01ms !important;animation-delay:0s !important;animation-iteration-count:1 !important}
}
