/* ==========================================================================
   LUMIERE LUXURY STONES — SHOWROOM MICROSITE v5
   main.css — one design system, written for this brand.

   The v5 direction: luxury European stone atelier × architectural editorial.
   Three rules drive every decision below.

   1. THE STONE IS THE ONLY SATURATED THING ON THE PAGE.
      The ground is warm ivory, the type is espresso, the accent is a muted
      bronze. Nothing competes with the photography, and photography is never
      flattened under a full-bleed scrim — where type sits over an image the
      gradient is anchored to one corner only.

   2. ASYMMETRY, NOT STACKED BANDS.
      A 12-column grid with deliberate offsets, media that breaks its column,
      captions set outside the frame. Sections differ in shape, so the page
      has rhythm instead of a repeated 50/50.

   3. THE BOX IS DESIGNED AROUND THE ASSET.
      Every media box carries --media-ratio / --object-x / --object-y from
      the curation, with separate md and sm ratios. No image is ever a crop
      of a crop.

   Carried forward from v1–v4.4 because each was earned by a real defect:
     * overflow / aspect-ratio are inert on inline boxes, so .m is block
     * percentage height resolves to auto against an indefinite parent, so
       the hero uses an explicit height chain
     * scroll-behavior: smooth makes every programmatic scrollLeft animate,
       so horizontal rails set scroll-behavior: auto and animate in JS
     * .btn declared after a display:none must not silently re-show it
     * inline SVGs are constrained by an explicit width/height rule
     * reduced motion is handled with a universal rule, not a selector list,
       so a new hover effect cannot escape it (v4.1.1)
   ========================================================================== */

/* ==========================================================================
   1. TOKENS
   ========================================================================== */
:root {
  /* ground */
  --pearl:      #FCFAF6;
  --ivory:      #F7F3EB;
  --limestone:  #EFE9DC;
  --sand:       #E2D8C6;
  --champagne:  #F3EADA;

  /* ink */
  --espresso:   #221D18;
  --charcoal:   #2E2823;
  --ink:        #35302A;
  --body:       #4C453C;
  --muted:      #6E6558;

  /* accent */
  --bronze:      #A8874E;   /* decorative rules, hairlines, icons */
  --bronze-text: #82653A;   /* AA text: 4.95:1 on ivory, 4.57:1 on tint */
  --bronze-lite:  #C6A56A;
  --bronze-soft: #D8C49B;

  /* lines + shadow */
  --line:       rgba(34, 29, 24, .13);
  --line-soft:  rgba(34, 29, 24, .07);
  --line-dark:  rgba(255, 252, 246, .18);
  --shadow-sm:  0 1px 2px rgba(34, 29, 24, .04), 0 6px 20px rgba(34, 29, 24, .05);
  --shadow-md:  0 2px 6px rgba(34, 29, 24, .05), 0 22px 54px rgba(34, 29, 24, .09);

  /* metrics */
  --wrap:   1340px;
  --gut:    clamp(20px, 5vw, 68px);
  --hdr-h:  74px;
  /* v5.4.1: the header's RENDERED height (row + 1px border). --hdr-h stays
     the row height that sizes .hdr__in; main.js refines this token from the
     measured header, and never writes --hdr-h. */
  --hdr-offset: calc(var(--hdr-h) + 1px);
  --dock-h: 0px;                /* set by JS on phone widths */
  --radius: 2px;

  /* motion — one language */
  --ease:   cubic-bezier(.22, .61, .36, 1);
  --slow:   1.05s;
  --mid:    .55s;
  --fast:   .28s;

  /* type */
  --serif: 'Cormorant Garamond', 'Iowan Old Style', 'Palatino Linotype', Georgia, 'Times New Roman', serif;
  --sans:  'Jost', 'Futura', 'Avenir Next', 'Segoe UI', system-ui, -apple-system, Helvetica, Arial, sans-serif;
}

/* ==========================================================================
   2. RESET + BASE
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--hdr-offset) + 18px);
  /* focus() and fragment scrolls never leave a field under the phone dock */
  scroll-padding-bottom: var(--dock-h);
}
body {
  margin: 0;
  background: var(--pearl);
  color: var(--body);
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 300;
  line-height: 1.72;
  letter-spacing: .006em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  padding-bottom: var(--dock-h);
}
img, picture, video, svg { max-width: 100%; }
img { border: 0; }
h1, h2, h3, h4 { margin: 0; font-weight: 400; color: var(--ink); }
p { margin: 0 0 1.05em; }
p:last-child { margin-bottom: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
address { font-style: normal; }
hr { border: 0; border-top: 1px solid var(--line); margin: 0; }

/* Unconstrained inline SVG renders at its intrinsic size — v2 shipped 200px
   chevrons because of it. Every icon is sized to its text box. */
svg { width: 1em; height: 1em; flex: 0 0 auto; }

::selection { background: var(--sand); color: var(--espresso); }

:focus-visible {
  outline: 2px solid var(--bronze-text);
  outline-offset: 3px;
  border-radius: 1px;
}
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--espresso); color: var(--pearl);
  padding: 12px 20px; font-size: .82rem; letter-spacing: .1em; text-transform: uppercase;
}
.skip:focus { left: 12px; top: 12px; }

/* ==========================================================================
   3. LAYOUT
   ========================================================================== */
.wrap {
  width: 100%;
  max-width: calc(var(--wrap) + var(--gut) * 2);
  margin-inline: auto;
  padding-inline: var(--gut);
}
.wrap--tight { max-width: calc(980px + var(--gut) * 2); }
.wrap--wide  { max-width: calc(1580px + var(--gut) * 2); }

.sec { padding-block: clamp(64px, 9vw, 132px); }
.sec--tight { padding-block: clamp(48px, 6vw, 88px); }
.sec--flush-t { padding-top: 0; }
.sec--flush-b { padding-bottom: 0; }
.sec.tint  { background: var(--ivory); }
.sec.stone { background: var(--limestone); }
.sec.dark  { background: var(--espresso); color: #E8E2D8; }
.sec.dark h1, .sec.dark h2, .sec.dark h3 { color: var(--pearl); }

/* the 12-column field everything asymmetric is built on */
.g12 { display: grid; grid-template-columns: repeat(12, 1fr); gap: clamp(20px, 3vw, 44px); }
.c1  { grid-column: 1 / -1; }

/* ==========================================================================
   4. TYPE SCALE
   ========================================================================== */
.h-xl, .h-lg, .h-md, .h-sm {
  font-family: var(--serif);
  font-weight: 300;
  line-height: 1.02;
  letter-spacing: -.014em;
  color: var(--ink);
  text-wrap: balance;
}
/* the display size is a custom property (repair round 3) so a narrow tier can
   restate it and a keep-together heading can cap it (section 20, .hkeep) */
.h-xl { --hxl-fs: clamp(2.9rem, 6.4vw, 5.6rem); font-size: var(--hxl-fs); line-height: .98; }
.h-lg { font-size: clamp(2.2rem, 4.3vw, 3.7rem); }
.h-md { font-size: clamp(1.65rem, 2.7vw, 2.5rem); line-height: 1.08; }
.h-sm { font-size: clamp(1.28rem, 1.7vw, 1.6rem); line-height: 1.16; letter-spacing: -.008em; }

.eyebrow {
  display: block;
  margin: 0 0 1.15em;
  font-family: var(--sans);
  font-size: .69rem;
  font-weight: 500;
  letter-spacing: .235em;
  text-transform: uppercase;
  color: var(--bronze-text);
  line-height: 1.5;
}
.dark .eyebrow, .hero .eyebrow { color: var(--bronze-lite); }
.eyebrow--c { text-align: center; }

.lede {
  font-size: clamp(1.02rem, 1.15vw, 1.14rem);
  line-height: 1.74;
  color: var(--body);
  max-width: 62ch;
}
.lede--lg {
  font-family: var(--serif);
  font-size: clamp(1.35rem, 2.1vw, 1.95rem);
  line-height: 1.42;
  font-weight: 300;
  color: var(--ink);
  letter-spacing: -.004em;
  max-width: 30ch;
}
.small { font-size: .84rem; line-height: 1.62; color: var(--muted); }
.tiny  { font-size: .74rem; letter-spacing: .04em; color: var(--muted); }
.mark  { font-family: var(--serif); font-style: italic; color: var(--bronze-text); }

/* a hairline that reads as a drawn rule, not a border */
.rule { display: block; height: 1px; background: var(--line); border: 0; }
.rule--short { display: block; width: 56px; height: 1px; background: var(--bronze); }

/* ==========================================================================
   5. BUTTONS + LINKS
   ========================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .6em;
  padding: 14px 26px;
  font-family: var(--sans);
  font-size: .755rem; font-weight: 500;
  letter-spacing: .175em; text-transform: uppercase;
  line-height: 1;
  border: 1px solid var(--espresso);
  background: transparent; color: var(--espresso);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease),
              border-color var(--fast) var(--ease);
  text-align: center;
}
.btn:hover { background: var(--espresso); color: var(--pearl); }
.btn--solid { background: var(--espresso); color: var(--pearl); }
.btn--solid:hover { background: var(--charcoal); border-color: var(--charcoal); }
.btn--ghost { border-color: var(--line); color: var(--ink); }
.btn--ghost:hover { border-color: var(--espresso); background: var(--espresso); color: var(--pearl); }
.btn--pill { border-color: var(--bronze); color: var(--bronze-text); border-radius: 999px; padding-inline: 24px; }
.btn--pill:hover { background: var(--bronze-text); border-color: var(--bronze-text); color: var(--pearl); }
.btn--lg { padding: 17px 34px; font-size: .79rem; }
.btn--sm { padding: 10px 18px; font-size: .69rem; letter-spacing: .15em; }
.btn--light { background: var(--pearl); border-color: var(--pearl); color: var(--espresso); }
.btn--light:hover { background: transparent; color: var(--pearl); }
/* repair round 3 (VR3-02 / VR3-04): the outline buttons over the hero carry a
   faint smoked-glass fill, so their labels hold on the brightest white slab
   (slide 3 measured 3.3-4.1:1 with no fill) now that the copy wash is
   lighter; the hover rule below still replaces the whole background */
.btn--onimg { border-color: rgba(255,252,246,.6); color: #fff; background-color: rgba(14,10,6,.2); backdrop-filter: blur(3px); }
.btn--onimg:hover { background: var(--pearl); border-color: var(--pearl); color: var(--espresso); }
.dark .btn--ghost { border-color: var(--line-dark); color: #EDE7DC; }
.dark .btn--ghost:hover { background: var(--pearl); border-color: var(--pearl); color: var(--espresso); }

.btnrow { display: flex; flex-wrap: wrap; gap: 12px; }

/* text link with a rule that draws in on hover */
.tlink {
  display: inline-flex; align-items: center; gap: .55em;
  font-size: .755rem; font-weight: 500; letter-spacing: .17em; text-transform: uppercase;
  color: var(--bronze-text); padding-bottom: 5px; position: relative;
}
.tlink::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor; transform: scaleX(.24); transform-origin: left;
  transition: transform var(--mid) var(--ease);
}
.tlink:hover::after, .tlink:focus-visible::after { transform: scaleX(1); }
.tlink svg { transition: transform var(--mid) var(--ease); }
.tlink:hover svg { transform: translateX(4px); }
.dark .tlink { color: var(--bronze-lite); }

/* ==========================================================================
   6. MEDIA BOXES
   --------------------------------------------------------------------------
   .m is the only place a crop happens. It must be a BLOCK box: overflow and
   aspect-ratio are inert on an inline box, which is how v1 shipped
   uncontained images.
   ========================================================================== */
.m {
  --media-ratio: 1.5;
  --ox: var(--object-x, 50%);
  --oy: var(--object-y, 50%);
  display: block; position: relative;
  overflow: hidden;
  aspect-ratio: var(--media-ratio);
  background: var(--m-bg, var(--limestone));
  isolation: isolate;
  width: 100%;
}
.m > picture { display: block; width: 100%; height: 100%; }
.m img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: var(--ox) var(--oy);
  transition: transform var(--slow) var(--ease);
  will-change: auto;
}
.m[data-fit="contain"] img { object-fit: contain; }
/* Designed artwork is shown whole on its own ground and never crops. */
.m[data-artwork="true"] { --m-bg: var(--champagne); aspect-ratio: var(--media-ratio) !important; }
.m[data-artwork="true"] img { object-fit: contain; }

/* the tablet box can need its own anchor, not only its own ratio: a 3/2 source
   in a 3/4 tablet hero crops 55 % of its width, so the desktop focal can walk
   the subject off the frame. --object-*-md is optional and falls back to the
   desktop focal, so nothing that does not declare one changes. */
@media (max-width: 1099.98px) {
  .m {
    aspect-ratio: var(--media-ratio-md, var(--media-ratio));
    --ox: var(--object-x-md, var(--object-x, 50%));
    --oy: var(--object-y-md, var(--object-y, 50%));
  }
}
@media (max-width: 759.98px) {
  /* v5.4.1: a copy of the phone header rules sat here, BEFORE the header's
     base rules, so it never applied; the one live copy is in section 21. */
  .m {
    aspect-ratio: var(--media-ratio-sm, var(--media-ratio-md, var(--media-ratio)));
    --ox: var(--object-x-sm, var(--object-x, 50%));
    --oy: var(--object-y-sm, var(--object-y, 50%));
  }
}

.fig { margin: 0; }
.fig__cap {
  margin-top: 14px;
  font-size: .755rem; line-height: 1.55; letter-spacing: .055em;
  color: var(--muted);
}
.fig__cap b, .fig__cap strong {
  display: block; font-weight: 500; letter-spacing: .16em; text-transform: uppercase;
  font-size: .69rem; color: var(--ink); margin-bottom: 3px;
}
.dark .fig__cap { color: #A9A296; }
.dark .fig__cap b { color: #E8E2D8; }

/* hover depth — one shared behaviour */
.hoverable .m img { transform: scale(1.0001); }
.hoverable:hover .m img,
.hoverable:focus-within .m img { transform: scale(1.042); }

/* zoom affordance on lightbox-enabled media */
.m--zoom { padding: 0; border: 0; cursor: zoom-in; background: var(--m-bg, var(--limestone)); }
.m__zoomcue {
  position: absolute; right: 12px; bottom: 12px; width: 30px; height: 30px;
  border: 1px solid rgba(255,252,246,.55); border-radius: 50%;
  background: rgba(34,29,24,.28); backdrop-filter: blur(2px);
  opacity: 0; transition: opacity var(--mid) var(--ease);
  pointer-events: none;
}
.m__zoomcue::before, .m__zoomcue::after {
  content: ''; position: absolute; background: #fff;
}
.m__zoomcue::before { left: 9px; right: 9px; top: 14px; height: 1px; }
.m__zoomcue::after  { top: 9px; bottom: 9px; left: 14px; width: 1px; }
.m--zoom:hover .m__zoomcue, .m--zoom:focus-visible .m__zoomcue { opacity: 1; }

/* ==========================================================================
   7. HEADER
   ========================================================================== */
/* v5.4.1 header contract (measured: build/reports/responsive/after/header-sweep):
     1280px and up   brand · six nav links · WhatsApp and Office lines · Enquire
     1024–1279.98    brand · WhatsApp / Ashish line · Enquire · menu
     480–1023.98     brand · WhatsApp icon · Enquire · menu
     under 480       brand · Enquire · menu (WhatsApp and Call are in the dock)
   The compact switch is ONE media query, (max-width: 79.999em), shared with
   main.js NAV_COMPACT_MQ. Every gap between header items is at least 16px on
   desktop, and every header control is at least 44px tall.
   The widths above are at the browser's default font size. Review round 1
   (F3): every header tier is written in em (79.999em, 63.999em, 47.499em,
   29.999em, 19.999em, 14.55em), because the header's text is in rem and both
   follow the browser's font-size setting; a px tier let the rem text outgrow
   it. The one exception is which of those tiers drops the Enquire pill: that
   is a fit decision in px AND em together (see the 19.999em block near the
   end of this file), because round 1's em-only rule took the pill off an
   ordinary 360-430px phone as soon as the reader chose Large text. */
.hdr {
  position: sticky; top: 0; z-index: 98;
  background: var(--pearl);
  border-bottom: 1px solid var(--line-soft);
  transition: background var(--mid) var(--ease), border-color var(--mid) var(--ease);
}
.hdr__in {
  max-width: calc(var(--wrap) + var(--gut) * 2);
  /* review round 1 (F3): the row's rem text grows with the browser's font
     size, so its content box does too (92.25rem is the same 1476px at the
     default 16px); at Large (20px) the row was 13px wider than 1340px */
  max-width: max(calc(var(--wrap) + var(--gut) * 2), 92.25rem);
  margin-inline: auto;
  padding-inline: max(var(--gut), env(safe-area-inset-left, 0px)) max(var(--gut), env(safe-area-inset-right, 0px));
  height: var(--hdr-h);
  display: flex; align-items: center; gap: clamp(16px, 2vw, 40px);
}
.brand { display: inline-flex; align-items: center; gap: 11px; flex: 0 0 auto; position: relative; }
/* The home link's own box is 30-35px tall (the logo mark plus the wordmark
   lock-up), which is under the 44px touch target the rest of the header
   keeps. A transparent 44px overlay gives it one without changing a single
   measured rectangle — the header row is 68-74px, so it always fits, and the
   adjacent gap is never less than 16px. */
.brand::before {
  content: ''; position: absolute; left: -4px; right: -4px; top: 50%;
  height: 44px; transform: translateY(-50%);
}
/* v5.4.1: logo-mark.webp is 256 x 209. It is sized by HEIGHT only, so the
   width follows the intrinsic ratio; a px width AND height squashed it 18%. */
.brand__mark { display: block; flex: 0 0 auto; height: 36px; width: auto; aspect-ratio: 256 / 209; object-fit: contain; }
.brand__txt { display: flex; flex-direction: column; line-height: 1; }
.brand__name {
  font-family: var(--serif); font-size: 1.32rem; font-weight: 400;
  letter-spacing: .10em; color: var(--ink);
}
.brand__sub {
  font-size: .535rem; font-weight: 400; letter-spacing: .365em;
  text-transform: uppercase; color: var(--muted); margin-top: 5px;
}
.nav { display: flex; align-items: center; gap: clamp(16px, 1.6vw, 30px); margin-left: auto; }
.nav a {
  position: relative;
  font-size: .715rem; font-weight: 400; letter-spacing: .175em; text-transform: uppercase;
  color: var(--ink); padding: 6px 0;
  transition: color var(--fast) var(--ease);
}
/* same 44px touch target as .brand: the link's own box is 20px tall (6px of
   padding over an 11.4px line), and the underline must stay on the text, so
   the target is a transparent overlay rather than more padding. 6px of reach
   on each side leaves at least 4px of the 16px minimum gap between links. */
.nav a::before {
  content: ''; position: absolute; left: -6px; right: -6px; top: 50%;
  height: 44px; transform: translateY(-50%);
}
.nav a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: left;
  transition: transform var(--mid) var(--ease);
}
.nav a:hover::after, .nav a[aria-current="page"]::after { transform: scaleX(1); }
.nav a[aria-current="page"] { color: var(--bronze-text); }

.hdr__act { display: flex; align-items: center; gap: 16px; flex: 0 0 auto; }
.hdr__tel {
  display: inline-flex; align-items: center; gap: .5em;
  /* the WhatsApp / Ashish line is the owner's third header priority, so it is
     a 44px target at every width, not only in the compact header where the
     rule used to live: on the desktop row its box measured 20px (one line of
     .74rem text), which is the smallest control in the header */
  min-height: 44px;
  font-size: .74rem; letter-spacing: .07em; color: var(--ink);
  white-space: nowrap;
}
.hdr__tel svg { color: var(--bronze-text); }
.hdr__tel:hover { color: var(--bronze-text); }
/* OWNER REVIEW (16 Sep 2026): the Office line leaves the top header at every
   width. The owner's header priority is logo > primary nav > WhatsApp /
   Ashish > Enquire, and a second stacked phone line was the densest thing in
   a row that already had to carry six nav links. It buys no width — .hdr__tels
   is a stretch column and the WhatsApp row is the wider of the two, so
   .hdr__act measures 369.7px either way and the compact switch does not move
   — but it turns a two-line right-hand cluster into one line, which is the
   crowding the owner reacted to.
   The link itself is NOT removed: it keeps its place in the markup with its
   tel: href, data-href="office" and data-loc="header-office" intact, so every
   tracking attribute still matches v5.4 byte for byte. The number stays
   reachable on every page in the drawer, the footer and the contact strip,
   and on visit.html and contact.html in full.
   Kept as a single base rule (not a media tier) so the header has exactly one
   breakpoint, NAV_COMPACT_MQ. */
.hdr__tels { display: flex; flex-direction: column; gap: 3px; }
.hdr__tel--office { display: none; }
.hdr__tel-k { font-size: .58rem; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); margin-right: .25em; }
.hdr--over .hdr__tel-k { color: rgba(255,252,246,.74); }
.hdr__cta { min-height: 44px; }

.burger {
  display: none;
  width: 44px; height: 44px; padding: 0;
  border: 1px solid var(--line); background: transparent; border-radius: var(--radius);
  cursor: pointer; position: relative;
}
.burger span {
  position: absolute; left: 11px; right: 11px; height: 1px; background: var(--ink);
  transition: transform var(--mid) var(--ease), opacity var(--fast) var(--ease);
}
.burger span:nth-child(1) { top: 16px; }
.burger span:nth-child(2) { top: 21px; }
.burger span:nth-child(3) { top: 26px; }
.is-open .burger span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.is-open .burger span:nth-child(2) { opacity: 0; }
.is-open .burger span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/* Header laid over the hero — a soft top wash, never a full-frame scrim.

   POSITIONING IS KEYED TO [data-over], NOT TO .hdr--over. The base .hdr is
   position: sticky, so it occupies flow space; .hdr--over used to be the thing
   that made it position: fixed. But .hdr--over is toggled off the moment the
   page scrolls past 24px — which put the header BACK into flow and pushed the
   whole document down by its own height: a 69px jump on a phone, 75px on
   desktop, with the document growing by the same amount (13,515 -> 13,584 px
   at 320x568). It fired on the first scroll of the home page, and again
   whenever the drawer opened, since that also removes .hdr--over.

   data-over is a build-time attribute that never changes, so keying position
   to it means the header is out of flow in BOTH states and nothing moves. The
   class now carries only the transparent styling it is named for. */
.hdr[data-over] { position: fixed; left: 0; right: 0; top: 0; }
.hdr--over {
  background: transparent; border-bottom-color: transparent;
}
/* review round 1 (VV-11): over the bright first slide the thin white labels
   measured 2.0-3.1:1 at their worst (the Office line 2.0-2.2:1). The wash is a
   little stronger and continues 52px below the header, so the second phone
   line no longer sits on its fading edge, and the labels carry the soft shadow
   the hero copy already has. The wash never takes pointer events. */
/* Repair round 3 (VR3-02): over the brightest white slab (slide 3, Crystallo
   Traslux) that wash read as a grey BAND with a visible lower edge at y 90-110:
   it held .5 down to 58 % of its box and then dropped to zero in 53px, and an
   abrupt change of slope is exactly what the eye sees as an edge. The wash now
   keeps the same depth where the header's text sits (about .6 at the nav line,
   so every label measures what it did) and eases out over a longer tail with
   no plateau, in a warmer near-black that reads as shade on the stone rather
   than as grey. Measured on all five slides at 1280-1920: nav, WhatsApp line,
   brand and Enquire within 0.1 of their previous contrast. */
.hdr--over::before {
  content: ''; position: absolute; inset: 0 0 -96px; z-index: -1; pointer-events: none;
  background: linear-gradient(to bottom,
    rgba(24,17,10,.66) 0%, rgba(24,17,10,.6) 22%, rgba(24,17,10,.5) 38%, rgba(24,17,10,.36) 54%,
    rgba(24,17,10,.22) 68%, rgba(24,17,10,.11) 81%, rgba(24,17,10,.04) 91%, rgba(24,17,10,0) 100%);
}
.hdr--over .brand__name, .hdr--over .nav a, .hdr--over .hdr__tel { color: #fff; }
.hdr--over .brand__sub { color: rgba(255,252,246,.78); }
.hdr--over .nav a, .hdr--over .hdr__tel, .hdr--over .brand__txt, .hdr--over .hdr__cta { text-shadow: 0 1px 10px rgba(12,9,6,.6), 0 0 2px rgba(12,9,6,.4); }
.hdr--over .hdr__tel-k { color: rgba(255,252,246,.9); }
.hdr--over .hdr__tel svg { color: var(--bronze-soft); }
.hdr--over .nav a[aria-current="page"] { color: var(--bronze-soft); }
.hdr--over .btn--pill { border-color: rgba(255,252,246,.7); color: #fff; }
.hdr--over .btn--pill:hover { background: var(--pearl); border-color: var(--pearl); color: var(--espresso); }
.hdr--over .burger { border-color: rgba(255,252,246,.45); }
.hdr--over .burger span { background: #fff; }
.hdr--solid { background: var(--pearl); border-bottom-color: var(--line-soft); }

/* ==========================================================================
   8. DRAWER
   ========================================================================== */
/* v5.4.1: the drawer sits ABOVE the phone dock (96) and the floating WhatsApp
   button (95), and only the header that holds its close control (98) is above
   it. At 88 the dock and the button painted over the drawer's own links. */
.drawer {
  position: fixed; inset: 0; z-index: 97;
  background: var(--pearl);
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform var(--mid) var(--ease), visibility 0s linear var(--mid);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding-top: var(--hdr-offset);
  /* review round 1 (a11y): the drawer's content scrolls under the fixed
     header, so a focus scroll must land below it (and above the pinned
     WhatsApp row): at 1279x900 wrapping Tab to "Showroom" left the link 87 %
     under the header */
  scroll-padding-top: calc(var(--hdr-offset) + 8px);
  scroll-padding-bottom: 84px;
}
.drawer.is-open { transform: translateY(0); visibility: visible; transition-delay: 0s; }
.drawer__in {
  --dgap: 28px;
  max-width: calc(var(--wrap) + var(--gut) * 2);
  margin-inline: auto;
  padding: 28px max(var(--gut), env(safe-area-inset-right, 0px)) calc(24px + env(safe-area-inset-bottom, 0px)) max(var(--gut), env(safe-area-inset-left, 0px));
  min-height: 100%;
  display: flex; flex-direction: column; gap: var(--dgap);
}
.drawer__nav { display: flex; flex-direction: column; }
.drawer__link {
  display: flex; align-items: center; justify-content: space-between;
  min-height: 48px;
  padding: 17px 0; border-bottom: 1px solid var(--line-soft);
  font-family: var(--serif); font-size: 1.62rem; font-weight: 300; color: var(--ink);
}
.drawer__link svg { color: var(--bronze); opacity: .65; }
.drawer__link[aria-current="page"] { color: var(--bronze-text); }
.drawer__foot { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.drawer__foot .btn:first-child { grid-column: 1 / -1; }
/* every drawer control is a 48px touch target (the buttons measured 39–42px) */
.drawer__foot .btn, .drawer__wa .btn { min-height: 48px; }
/* The WhatsApp / Ashish row is a plain block in the drawer's flow.
   Review round 1 pinned it with position:sticky so it would always be on the
   first screen (VV-03). That re-created the defect F1/F2 had just been fixed
   for, one layer down: a sticky bottom bar overlays whatever is at the bottom
   of the scrollport, so on short screens it sat ON a menu link and 18 of 159
   real clicks on VISIBLE drawer links opened WhatsApp instead of navigating
   (568x320, 667x375, 683x384 = 1366x768 at 200 %, 812x375, 844x390, 1024x500,
   on every page). v5.4, with nothing pinned, was 0 of 114. Pinning cannot be
   made safe by padding — the overlay happens at rest, at scroll offsets the
   visitor has not chosen — so it is gone, and VV-03 is solved instead by
   making the menu itself short enough to leave the row on the first screen
   (the column rules below). */
.drawer__wa .btn { width: 100%; }
/* short screens: tighter menu rows, so more of the menu is on the first screen */
@media (max-height: 820px) {
  .drawer__in { --dgap: clamp(18px, 3.4vh, 28px); padding-top: clamp(12px, 3vh, 28px); }
  .drawer__link { padding-block: clamp(6px, 1.5vh, 17px); font-size: clamp(1.3rem, 3.3vh, 1.62rem); line-height: 1.3; }
}
/* SHORT AND WIDE (landscape phones, small landscape tablets, a laptop at
   175-200 % browser zoom): eight menu rows in one column are 384px, which is
   more than the whole drawer, so the WhatsApp / Ashish row and the four
   contact buttons were always below the fold. In two columns the menu is
   192px and in three it is 144px, which puts the WhatsApp row on the first
   screen at 568x320, 667x375, 683x384, 812x375, 844x390 and 1024x500 without
   anything being pinned over anything. Portrait phones keep one column: below
   520px a second column has no room for "Collections". */
@media (max-height: 560px) and (min-width: 520px) {
  .drawer__nav { display: grid; grid-template-columns: 1fr 1fr; column-gap: clamp(20px, 3vw, 44px); }
  .drawer__link { font-size: clamp(1.1rem, 3.1vh, 1.45rem); }
  .drawer__link svg { display: none; }
  .drawer__foot { grid-template-columns: repeat(3, 1fr); }
  .drawer__foot .btn:first-child { grid-column: auto; }
}
@media (max-height: 420px) and (min-width: 520px) {
  .drawer__nav { grid-template-columns: repeat(3, 1fr); column-gap: clamp(16px, 2.4vw, 34px); }
  .drawer__link { font-size: clamp(1rem, 3.4vh, 1.3rem); }
}

/* ==========================================================================
   9. HERO
   --------------------------------------------------------------------------
   A percentage height resolves to auto against an indefinite-height parent,
   which is how v4 shipped a hero that collapsed to its intrinsic ratio on
   mobile. The chain below is explicit at every level.
   ========================================================================== */
/* v5.4.1: the hero has a MINIMUM height (the viewport, capped at 940px), not
   a fixed one. With a fixed height, copy taller than the box was pushed UP by
   align-items:flex-end, past the padding, under the fixed header (1280x720,
   1366x768, every 800px-tall desktop, short phones and landscape). The copy
   is now in flow, so a taller copy makes the hero taller instead. The slides
   stay absolutely positioned against the hero's resolved height. */
.hero {
  position: relative;
  display: flex; flex-direction: column;
  min-height: min(100vh, 940px);
  min-height: min(100svh, 940px);
  overflow: hidden;
  background: var(--espresso);
}

.hstage { position: absolute; inset: 0; }
.hslide {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity 1.5s var(--ease);
}
.hslide.is-on { opacity: 1; }
.hslide > .fig { height: 100%; margin: 0; }
.hslide .m {
  aspect-ratio: auto !important;
  height: 100%; width: 100%;
  background: var(--espresso);
}
.hslide .m > picture { height: 100%; }
.hslide .m img { height: 100%; }
.hslide.is-on .m img { animation: heroDrift 17s var(--ease) forwards; }
@keyframes heroDrift { from { transform: scale(1.008); } to { transform: scale(1.062); } }

/* The wash is anchored to the LEFT column and to the bottom edge that carries
   the slider controls — never a full-frame scrim, so the right two-thirds of
   every slide stays luminous. Owner review: the copy block now sits in the
   mid-upper left, so the left wash carries further up the frame than the
   bottom-anchored v5.4 pair did, and the bottom wash only has to carry the
   controls. */
.hero__veil {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(to right, rgba(16,12,8,.58) 0%, rgba(16,12,8,.40) 24%, rgba(16,12,8,.16) 46%, rgba(16,12,8,.03) 63%, rgba(16,12,8,0) 76%),
    linear-gradient(to top, rgba(16,12,8,.52) 0%, rgba(16,12,8,.24) 15%, rgba(16,12,8,.04) 32%, rgba(16,12,8,0) 46%);
}
/* THE COMPOSITION LINE (owner review, 16 Sep 2026)
   -------------------------------------------------------------------------
   The owner rejected the v5.4 hero: content pushed too high, competing with
   the fixed header, logo and navigation, some of it crowded beneath them.
   The measured cause was not a layout change — v5.3 and v5.4 have
   byte-identical hero CSS — but COPY GROWTH inside a BOTTOM-ANCHORED box. The
   CTA row's bottom edge is identical in v5.3, v5.4 and v5.4.1 at every
   viewport, so every extra line of copy pushed the TOP of the block upward,
   past a padding-top that align-items:flex-end ignores, and into the header
   band: 103.6px deep at 1280x720, 83.9px at 1366x768, 138.5px at 1366x529.

   Shortening the copy was not enough on its own. Still glued to the bottom,
   the shorter block sank to a median 35.8 % block top and 59.9 % centre, and
   the eyebrow travelled 94-109px between slides, because the top of a
   bottom-anchored box floats with each slide's own copy height.

   So the block is anchored to the TOP, on a line measured from the hero's own
   height:

       eyebrow top = max(header bottom + breathing zone, blockTop% of hero)

   The hero is min(100svh, 940px), so "30 % of the hero" is exactly
   min(30svh, 282px) — no JavaScript and no per-slide measurement. Every slide
   then starts on the same line (vertical jump 0), the slack falls out at the
   bottom where nothing is drawn, and the breathing zone under the header can
   never be crossed, whatever the copy measures. */
.hero__body {
  /* the protected zone between the header's bottom edge and the eyebrow */
  --hero-air: 78px;
  /* the composition line: 30 % of min(100svh, 940px) */
  --hero-line: min(30svh, 282px);
  position: relative; z-index: 2;
  flex: 1 0 auto;
  display: flex; align-items: flex-start;
  padding-top: max(calc(var(--hdr-offset) + var(--hero-air)), var(--hero-line));
  padding-bottom: clamp(104px, 15vh, 168px);
  pointer-events: none;
}
/* the five slide copies share ONE grid cell, so the hero is sized by the
   tallest copy and does not change height when the slide changes */
/* Repair round 3 (VR3-01 / NR3-01): the ONE column is minmax(0, 1fr), not the
   implicit auto track. An auto track is at least the min-content of the widest
   item in the cell, and all five copies are in the cell, so the widest
   unbreakable thing on ANY slide set the column for EVERY slide: at a 24px
   browser font the phone CTA grid (two 193px tracks) made the column 396px on
   a 360px screen and cut body text and buttons off on all five slides
   (+56 / +41 / +26 / +4px at 360 / 375 / 390 / 412). The column is now the
   container, and each copy lays out inside it on its own. */
.hero__body .wrap { width: 100%; display: grid; grid-template-columns: minmax(0, 1fr); }
/* 52rem, not 46ch. 46ch of the BODY font resolved to 426.9px on every desktop
   width and overrode the heading's own measure, so the display headline got
   11-13 characters to a line — four lines where the copy was written for two
   — and the three buttons stacked into a 150px three-row block. 52rem is wide
   enough for the longest authored line in the set ("read across the whole
   slab.", 9.7em) to stay on one line at every desktop and tablet size. */
.hcopy { --scrim: .52; max-width: min(100%, 52rem); pointer-events: auto; position: relative; }
/* review round 1 (VV-04): the copy sat on the brightest marble of the first
   slide with nothing behind it (eyebrow 1.0-1.4:1 at its worst, 1.4-1.9:1
   median). A soft scrim that belongs to each slide's COPY, not to the frame,
   darkens only what is behind the text, fades out well inside the picture,
   and comes and goes with the copy.
   Owner review: the round-1 shape was radial-gradient(closest-side), which
   reads as a dark oval laid ON the stone at 1440px and wider. It is now a
   wide ellipse with a long six-stop falloff that reaches zero outside the
   copy box, and its depth is per-slide: the three macro-stone frames are
   luminous and take --scrim .62, the two showroom frames are already dark and
   take .38, so neither is muddied (a phone spreads the same wash over twice
   the area, so it goes to .72 / .46 below 760px). */
/* closest-side with the box centred on the copy, so the wash reaches exactly
   zero on all four edges of its own box. An explicit ellipse size (or an
   off-centre position) makes the gradient's last stop fall OUTSIDE the box,
   and the box edge then shows as a soft rectangle laid on the stone — which
   is what round 1's shape did at 1440px and wider. */
.hcopy::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  /* the box is taller ABOVE the copy than below it, so the peak of the wash
     sits at about 40 % of the block height — on the eyebrow and headline,
     which are the thin, pale elements — and has decayed to about a fifth of
     its peak under the CTA buttons, which carry their own fill and border.
     Centred inset (24/24) put the peak on the paragraph and left the eyebrow
     at 2.2:1 over the brightest marble at 430x932. */
  inset: -34% -34% -14% -34%;
  background: radial-gradient(closest-side,
    rgba(14,10,6,var(--scrim)) 0%,
    rgba(14,10,6,calc(var(--scrim) * .88)) 26%,
    rgba(14,10,6,calc(var(--scrim) * .64)) 48%,
    rgba(14,10,6,calc(var(--scrim) * .34)) 68%,
    rgba(14,10,6,calc(var(--scrim) * .12)) 84%,
    rgba(14,10,6,0) 100%);
}
/* Repair round 3 (VR3-02): from 760px up the wash is a SIDE LIGHT, not an
   oval. The owner-review shape (a closest-side ellipse centred on the 52rem
   column, peak .62) put its darkest point to the right of and above a short
   headline, where no text is, so on the brightest white slab (slide 3,
   1280-1920px) it read as a grey cloud beside the words. The box now reaches
   far past the left edge of the frame and only 30 % past the column on the
   right, so the ellipse is centred about a fifth of the way into the column,
   on the headline itself, and falls off over nearly the whole column width in
   eight eased stops: the left of the frame darkens the way a slab lit from
   the right does, and the right two-thirds stay luminous. Its peak is lower
   (.5 bright / .36 deep) and a warmer near-black, and the small type carries
   its own tighter halo instead (eyebrow and body below), so every text
   measure holds: eyebrow, body and outline-button contrast at 1024-1920 are
   equal to or higher than before on all five slides; headline medians stay
   above 4.4:1 (large text). Phones keep their own full-width wash (21 below). */
.hslide-copy[data-tone="bright"] { --scrim: .5; }
.hslide-copy[data-tone="deep"]   { --scrim: .36; }
@media (min-width: 760px) {
  .hcopy::before {
    inset: -60% -30% -22% -90%;
    background: radial-gradient(closest-side,
      rgba(26,18,10,var(--scrim)) 0%,
      rgba(26,18,10,calc(var(--scrim) * .93)) 18%,
      rgba(26,18,10,calc(var(--scrim) * .8)) 34%,
      rgba(26,18,10,calc(var(--scrim) * .6)) 50%,
      rgba(26,18,10,calc(var(--scrim) * .38)) 65%,
      rgba(26,18,10,calc(var(--scrim) * .19)) 79%,
      rgba(26,18,10,calc(var(--scrim) * .06)) 91%,
      rgba(26,18,10,0) 100%);
  }
  .hcopy p:not(.eyebrow):not(.hcopy__t) { text-shadow: 0 1px 2px rgba(12,9,6,.34), 0 1px 18px rgba(12,9,6,.5); }
}
.hcopy .eyebrow {
  /* The hero eyebrow is a <p>, so ".hcopy p" (0,1,1) out-specified ".eyebrow"
     (0,1,0) and it rendered at the body measure and the body size — 15.7px
     where every other eyebrow on the site is 11px, which is why a 39-character
     eyebrow wrapped to two lines above the heading and cost the block 26px.
     It is sized here, on the winning selector, as the small tracked label the
     rest of the design uses. */
  font-size: clamp(.72rem, .62vw, .82rem);
  font-weight: 500; letter-spacing: .215em; line-height: 1.55;
  max-width: none;
  /* a paler bronze than --bronze-soft for small text over photography.
     Repair round 3: paler again (#EBDCB8 -> #F2E6CA, the same champagne a
     step lighter) with a tighter three-layer halo, because the side-light
     wash is lighter than the oval it replaced; the eyebrow now measures at
     least what it did on every slide (slide 3 at 1440x900: 3.96 -> 4.03,
     slide 4: 3.02 -> 3.39, slide 5: 3.95 -> 5.03) */
  color: #F2E6CA;
  margin-bottom: clamp(14px, 1.9vh, 22px);
  /* balanced: a two-line eyebrow breaks at the separator ("Lumiere Luxury
     Stones · / West Palm Beach"), never inside the place name. The separator
     is bound to the word before it with a non-breaking space in the copy, so
     line 2 can never open with a stranded middot (measured at 390x844 and
     320x568, where text-wrap:balance alone broke BEFORE the separator). */
  text-wrap: balance;
  text-shadow: 0 1px 2px rgba(12,9,6,.62), 0 0 8px rgba(12,9,6,.55), 0 0 20px rgba(12,9,6,.4);
}
.hcopy h1, .hcopy .hcopy__t {
  /* No ch measure: the parent column (52rem) is the measure, so the authored
     <br> controls every line break and the longest second line stays on one
     line. v5.4.1: the size follows the viewport HEIGHT as well as its width
     (9.2vh), so a 720-900px tall desktop does not get the full display size;
     the 4.85rem ceiling is what keeps the Patagonia slide at two lines
     (9.7em x 77.6px = 753px inside a 832px column). */
  max-width: none;
  font-family: var(--serif); font-weight: 300; color: #fff;
  font-size: clamp(2.7rem, min(5.4vw, 9.2vh), 4.85rem);
  line-height: 1.0; letter-spacing: -.018em;
  /* the owner asked for a comfortable gap under the headline; it scales with
     the viewport height so a short laptop keeps the same rhythm in less room */
  margin: 0 0 clamp(22px, 3.8vh, 46px);
  text-shadow: 0 1px 30px rgba(12,9,6,.42);
}
/* repair round 3: a tight edge shadow on the display headline over the lighter
   desktop wash (the soft 30px glow stays) */
@media (min-width: 760px) {
  .hcopy h1, .hcopy .hcopy__t { text-shadow: 0 1px 2px rgba(12,9,6,.24), 0 1px 30px rgba(12,9,6,.42); }
}
.hcopy p {
  color: rgba(255,252,246,.93);
  font-size: clamp(.98rem, 1.1vw, 1.08rem); line-height: 1.66;
  max-width: 40ch;
  margin-bottom: clamp(26px, 4.4vh, 52px);
  text-shadow: 0 1px 18px rgba(12,9,6,.45);
}
.hcopy .btnrow { gap: 12px; }

/* slide copy transitions with the image. v5.4.1: inactive copies are also
   visibility:hidden (after the fade), so their CTAs leave the tab order.
   Owner review: align-self is START, not END — the copies share one grid cell
   and every one of them begins on the composition line, so the headline no
   longer rises and falls by 94-109px as the carousel turns. */
.hslide-copy {
  grid-area: 1 / 1; align-self: start;
  opacity: 0; transform: translateY(14px); visibility: hidden; pointer-events: none;
  transition: opacity .8s var(--ease), transform .8s var(--ease), visibility 0s linear .8s;
}
.hslide-copy.is-on {
  opacity: 1; transform: none; visibility: visible; pointer-events: auto;
  transition: opacity .8s var(--ease), transform .8s var(--ease), visibility 0s;
}

/* controls */
.hctl {
  position: absolute; left: 0; right: 0; bottom: calc(30px + var(--dock-h)); z-index: 4;
}
.hctl__in {
  max-width: calc(var(--wrap) + var(--gut) * 2); margin-inline: auto; padding-inline: var(--gut);
  display: flex; align-items: center; gap: 20px;
}
/* The dot is a 1.5px rule, but its TOUCH TARGET is 44px: the row is 44px tall
   and pulled back by an 11px negative block margin on each side, so the
   .hctl flex line — and every geometry measured against it — keeps the 22px
   height the design draws, while a thumb has the full 44px. */
.hdots {
  --dot-h: 44px;
  display: flex; gap: 10px; flex: 1 1 auto; max-width: 320px;
  margin-block: calc((22px - var(--dot-h)) / 2);
}
.hdot {
  flex: 1 1 auto; height: var(--dot-h); padding: 0; border: 0; background: none; cursor: pointer;
  position: relative;
}
.hdot::before {
  content: ''; position: absolute; left: 0; right: 0; top: calc(var(--dot-h) / 2 - .75px); height: 1.5px;
  background: rgba(255,252,246,.34);
}
.hdot::after {
  content: ''; position: absolute; left: 0; top: calc(var(--dot-h) / 2 - .75px); height: 1.5px; width: 0;
  background: var(--pearl);
  transition: width .35s var(--ease);
}
.hdot[aria-current="true"]::after { width: 100%; }
.hdot[aria-current="true"].is-timing::after { transition: width 6.6s linear; }

/* The arrows sit WITH the dots, not at the far right of the rail.
   margin-left:auto pushed them into the bottom-right corner, which is also
   where the fixed WhatsApp button lives — so on arrival the float covered
   harrow--next completely (46px of a 46px control) and clipped harrow--prev,
   at 1440x900, 1366x768, 1366x600, 1280x800, 1280x600, 1180x820, 1024x768
   and 768x600. Both controls were only recoverable by scrolling ~49px, which
   is not a fix for the arrival view. Grouping dots + arrows as one cluster
   leaves the corner to the floating CTA and reads as a deliberate control
   group rather than two things that happen to share a corner. */
.harrows { display: flex; gap: 8px; }
.harrow {
  width: 46px; height: 46px; padding: 0;
  border: 1px solid rgba(255,252,246,.42); border-radius: 50%;
  background: rgba(18,14,10,.20); color: #fff; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease), color var(--fast) var(--ease);
  backdrop-filter: blur(3px);
}
.harrow svg { width: 13px; height: 13px; }
.harrow:hover { background: var(--pearl); border-color: var(--pearl); color: var(--espresso); }

.hscroll {
  position: absolute; right: var(--gut); top: 50%; z-index: 3;
  transform: translateY(-50%) rotate(90deg); transform-origin: right center;
  font-size: .6rem; letter-spacing: .42em; text-transform: uppercase;
  color: rgba(255,252,246,.62); pointer-events: none;
}

/* ==========================================================================
   10. REVEAL — one motion language
   ========================================================================== */
/* v5.2: content is only held back for the reveal when JavaScript is running
   (the inline <head> script adds .js), so a browser without JavaScript still
   sees every section, including the enquiry form and its result panels. */
.js .reveal { opacity: 0; transform: translateY(22px); transition: opacity .95s var(--ease), transform .95s var(--ease); }
.js .reveal.is-in { opacity: 1; transform: none; }
.reveal--d1 { transition-delay: .09s; }
.reveal--d2 { transition-delay: .18s; }
.reveal--d3 { transition-delay: .27s; }

/* masked line reveal for display headings */
.maskline { display: block; overflow: hidden; }
.maskline > span { display: block; transform: translateY(102%); transition: transform 1.05s var(--ease); }
.is-in .maskline > span, .maskline.is-in > span { transform: none; }
.maskline:nth-child(2) > span { transition-delay: .1s; }

/* ==========================================================================
   11. SECTION PATTERNS
   ========================================================================== */

/* -- 11a. opening statement: oversized serif set against a tall image ---- */
.stmt { align-items: center; }
.stmt__fig { grid-column: 1 / span 5; position: relative; }
.stmt__body { grid-column: 7 / span 6; }
.stmt__q {
  font-family: var(--serif); font-weight: 300;
  font-size: clamp(1.6rem, 2.85vw, 2.65rem); line-height: 1.28;
  letter-spacing: -.008em; color: var(--ink); margin-bottom: .9em;
  text-wrap: balance;
}
.stmt__facts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 40px; padding-top: 26px; border-top: 1px solid var(--line); }
.fact__k { font-family: var(--serif); font-size: 1.55rem; color: var(--ink); line-height: 1.1; display: block; }
.fact__v { font-size: .715rem; letter-spacing: .13em; text-transform: uppercase; color: var(--muted); margin-top: 7px; display: block; }

/* -- 11b. section head: label left, heading + lede offset right --------- */
.shead { margin-bottom: clamp(34px, 4.5vw, 64px); gap: clamp(14px, 1.8vw, 24px) clamp(20px, 3vw, 44px); }
.shead__l { grid-column: 1 / -1; }
.shead__l .eyebrow { margin-bottom: .9em; }
.shead__r {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr);
  gap: clamp(18px, 3.4vw, 62px); align-items: end;
}
.shead__r .lede { margin-top: 0; max-width: 52ch; padding-bottom: .35em; }
.shead__act { grid-column: 1 / -1; margin-top: 6px; }

/* -- 11c. the atelier: a staggered editorial grid, not an equal card row - */
.atelier { display: grid; grid-template-columns: repeat(12, 1fr); gap: clamp(22px, 2.6vw, 42px) clamp(18px, 2.2vw, 36px); }
.mat { display: block; grid-column: span 4; }
.mat--s3 { grid-column: span 3; }
.mat--s4 { grid-column: span 4; }
.mat--s5 { grid-column: span 5; }
/* A single, small optical lift on the middle column keeps the grid from
   reading as a product table without opening a gap at the end of a row. */
.mat--lift { margin-top: clamp(14px, 2.2vw, 40px); }
.mat__body { display: flex; align-items: baseline; gap: 12px; margin-top: 15px; }
.mat__n {
  font-family: var(--serif); font-size: clamp(1.06rem, 1.35vw, 1.32rem);
  color: var(--ink); line-height: 1.2; font-weight: 400;
}
.mat__i { margin-left: auto; font-size: .66rem; letter-spacing: .16em; color: var(--bronze-text); text-transform: uppercase; }
.mat__note { display: block; margin-top: 5px; font-size: .8rem; line-height: 1.5; color: var(--muted); max-width: 34ch; }
.mat__more { margin-top: 11px; display: inline-flex; }
.mat__acts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 20px; margin-top: 13px; }

/* a text control that opens the lightbox — a real focusable button, so the
   second asset behind a card never has to be hidden off-screen to work */
.zoomlink {
  display: inline-flex; align-items: center; gap: .5em;
  padding: 0; border: 0; background: none; cursor: zoom-in;
  font-family: var(--sans); font-size: .755rem; font-weight: 500;
  letter-spacing: .17em; text-transform: uppercase; color: var(--ink);
  padding-bottom: 5px; position: relative;
}
.zoomlink::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor; transform: scaleX(.24); transform-origin: left;
  transition: transform var(--mid) var(--ease);
}
.zoomlink:hover::after, .zoomlink:focus-visible::after { transform: scaleX(1); }
.zoomlink__ic { position: relative; width: 10px; height: 10px; flex: 0 0 auto; }
.zoomlink__ic::before, .zoomlink__ic::after { content: ''; position: absolute; background: var(--bronze-text); }
.zoomlink__ic::before { left: 0; right: 0; top: 4.5px; height: 1px; }
.zoomlink__ic::after  { top: 0; bottom: 0; left: 4.5px; width: 1px; }
.dark .zoomlink { color: #E8E2D8; }


/* -- 11d. full-bleed band with an overlapping caption plate -------------- */
.bleed { position: relative; }
/* a genuinely edge-to-edge band. v5.4.1: 100vw includes a classic scrollbar,
   so the band was 15px wider than the page and cropped 7.5px each side. The
   band is a direct child of a full-width section, so 100% of it is exactly
   edge to edge at every width. */
.bleed--full > .bleed__media {
  width: 100%; margin-left: 0; transform: none;
}
.bleed .m { --m-bg: var(--limestone); }
.bleed__over {
  position: relative; z-index: 2;
  margin-top: clamp(-118px, -9vw, -46px);
  max-width: 480px;
  background: var(--pearl);
  padding: clamp(26px, 3vw, 42px);
  box-shadow: var(--shadow-md);
}
.bleed__over .eyebrow { margin-bottom: .8em; }
.bleed--r .bleed__over { margin-left: auto; }

/* -- 11e. offset pair: two figures at different sizes and baselines ------ */
.pair { display: grid; grid-template-columns: repeat(12, 1fr); gap: clamp(20px, 3vw, 46px); align-items: start; }
.pair__a { grid-column: 1 / span 7; }
.pair__b { grid-column: 9 / span 4; padding-top: clamp(40px, 8vw, 120px); }
.pair--flip .pair__a { grid-column: 6 / span 7; order: 2; }
.pair--flip .pair__b { grid-column: 1 / span 4; order: 1; }

/* -- 11f. gateway panels ------------------------------------------------- */
.gates { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(18px, 2.4vw, 34px); }
.gate { position: relative; display: block; overflow: hidden; background: var(--espresso); }
.gate .m { --m-bg: var(--espresso); }
.gate .m img { transition: transform 1.3s var(--ease); }
.gate:hover .m img, .gate:focus-visible .m img { transform: scale(1.05); }
.gate__scrim { position: absolute; inset: 0; background: linear-gradient(to top, rgba(16,12,9,.76) 0%, rgba(16,12,9,.32) 44%, rgba(16,12,9,.04) 78%); }
.gate__body { position: absolute; left: 0; right: 0; bottom: 0; padding: clamp(24px, 3vw, 42px); color: #fff; }
.gate__body h3 { font-family: var(--serif); font-weight: 300; font-size: clamp(1.6rem, 2.4vw, 2.25rem); color: #fff; line-height: 1.06; margin-bottom: .3em; }
.gate__body p { color: rgba(255,252,246,.88); font-size: .89rem; line-height: 1.6; max-width: 40ch; margin-bottom: 1.1em; }
.gate__go { display: inline-flex; align-items: center; gap: .55em; font-size: .715rem; letter-spacing: .18em; text-transform: uppercase; color: #fff; }
.gate__go svg { transition: transform var(--mid) var(--ease); }
.gate:hover .gate__go svg { transform: translateX(5px); }

/* -- 11g. horizontal rail ------------------------------------------------
   scroll-behavior must be auto here: `smooth` makes every programmatic
   scrollLeft animate on the compositor, which made v4's deterministic
   fallback inert in a hidden frame. JS animates instead.
------------------------------------------------------------------------ */
.rail { position: relative; }
.rail__track {
  display: flex; gap: clamp(14px, 1.8vw, 26px);
  overflow-x: auto; overflow-y: hidden;
  scroll-behavior: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 6px;
  scrollbar-width: thin; scrollbar-color: var(--sand) transparent;
}
.rail__track::-webkit-scrollbar { height: 3px; }
.rail__track::-webkit-scrollbar-thumb { background: var(--sand); }
.rail__item { flex: 0 0 auto; scroll-snap-align: start; width: clamp(258px, 27vw, 400px); }
.rail__item--wide { width: clamp(320px, 44vw, 620px); }
.rail__nav { display: flex; gap: 8px; }
.rbtn {
  width: 42px; height: 42px; padding: 0; border-radius: 50%;
  border: 1px solid var(--line); background: transparent; color: var(--ink);
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease), border-color var(--fast) var(--ease), opacity var(--fast) var(--ease);
}
.rbtn svg { width: 12px; height: 12px; }
.rbtn:hover { background: var(--espresso); border-color: var(--espresso); color: var(--pearl); }
.rbtn[disabled] { opacity: .3; cursor: default; }
.rbtn[disabled]:hover { background: transparent; color: var(--ink); border-color: var(--line); }
.dark .rbtn { border-color: var(--line-dark); color: #E8E2D8; }
.dark .rbtn:hover { background: var(--pearl); color: var(--espresso); border-color: var(--pearl); }

/* -- 11h. role list (trade pathways) ------------------------------------ */
.roles { border-top: 1px solid var(--line-dark); }
.role {
  display: grid; grid-template-columns: 2.2rem 1fr auto; align-items: center; gap: clamp(16px, 2.4vw, 40px);
  padding: clamp(20px, 2.6vw, 32px) 0; border-bottom: 1px solid var(--line-dark);
  transition: padding-left var(--mid) var(--ease);
}
.role:hover { padding-left: 10px; }
.role__n { font-size: .68rem; letter-spacing: .18em; color: var(--bronze-lite); }
.role__t { display: block; font-family: var(--serif); font-size: clamp(1.3rem, 2vw, 1.85rem); font-weight: 300; color: var(--pearl); line-height: 1.14; }
.role__d { display: block; font-size: .855rem; color: #A9A296; margin-top: 7px; max-width: 56ch; line-height: 1.6; }
.role__go { color: var(--bronze-lite); font-size: .68rem; letter-spacing: .17em; text-transform: uppercase; display: inline-flex; align-items: center; gap: .5em; white-space: nowrap; }
.role__go svg { transition: transform var(--mid) var(--ease); }
.role:hover .role__go svg { transform: translateX(5px); }

/* -- 11i. the enquire band ---------------------------------------------- */
.band-enq { background: var(--ivory); padding-block: clamp(56px, 7.5vw, 106px); border-top: 1px solid var(--line-soft); }
.band-enq--tint { background: var(--limestone); }
.enqb { display: grid; grid-template-columns: 1.15fr 1fr; gap: clamp(28px, 5vw, 80px); align-items: center; }
.enqb__lead .lede { margin-top: 16px; }
.enqb__act { display: flex; flex-direction: column; gap: 14px; align-items: flex-start; }
.enqb__row { display: flex; flex-wrap: wrap; gap: 10px; }

/* -- 11j. record plates (full slabs, shown whole) ------------------------ */
.plates { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(22px, 3vw, 46px); }
.plate { background: var(--ivory); padding: clamp(16px, 2vw, 26px); }
.plate .m { --m-bg: var(--ivory); }
.plate__b { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; margin-top: 14px; }
.plate__n { font-family: var(--serif); font-size: 1.16rem; color: var(--ink); }

/* -- 11k. contact / info rail ------------------------------------------- */
.info { display: grid; gap: 28px; }
.info__row { display: grid; grid-template-columns: 8.5rem 1fr; gap: 18px; padding-bottom: 22px; border-bottom: 1px solid var(--line); }
.info__k { font-size: .68rem; letter-spacing: .18em; text-transform: uppercase; color: var(--muted); padding-top: .35em; }
.info__v { font-size: 1rem; color: var(--ink); line-height: 1.62; overflow-wrap: anywhere; }
.info__v a { border-bottom: 1px solid var(--line); padding-bottom: 1px; }
.info__v a:hover { border-color: var(--bronze-text); color: var(--bronze-text); }

/* ==========================================================================
   12. GALLERY
   ========================================================================== */
.chips { display: flex; flex-wrap: wrap; gap: 9px; }
.chip {
  padding: 10px 18px; border: 1px solid var(--line); background: transparent;
  font-size: .69rem; letter-spacing: .15em; text-transform: uppercase; color: var(--ink);
  cursor: pointer; border-radius: 999px;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.chip:hover { border-color: var(--espresso); }
.chip[aria-pressed="true"] { background: var(--espresso); border-color: var(--espresso); color: var(--pearl); }

.mason { columns: 3; column-gap: clamp(16px, 2vw, 30px); }
.mason__i { break-inside: avoid; margin-bottom: clamp(16px, 2vw, 30px); display: block; }
.mason__i[hidden] { display: none; }
.gcap { margin-top: 10px; font-size: .74rem; line-height: 1.5; color: var(--muted); }
.gcap b { display: block; font-size: .655rem; letter-spacing: .17em; text-transform: uppercase; color: var(--ink); font-weight: 500; margin-bottom: 2px; }
.gempty { padding: 40px 0; color: var(--muted); }

/* ==========================================================================
   13. LIGHTBOX
   ========================================================================== */
/* v5.4.1 review round 1 (F4 / F5 / VV-05): the picture is sized from what the
   screen has left once the padding, the caption's RENDERED height (--lb-cap,
   measured by main.js) and the 14px gap are taken off, never from a fixed
   150 / 190 / 250px allowance: a long caption ran under the previous / next
   buttons (320x568) or below the screen (1366x529). The caption's width
   follows the viewport, so its height does not depend on the picture. Where
   the arrows sit beside the picture, the picture keeps 12px clear of them
   (--lb-side). If a caption still needs more room than the screen has, the
   viewer scrolls, and safe centring keeps its top reachable. */
.lb {
  --lb-pad: clamp(16px, 4vw, 54px);
  --lb-padt: var(--lb-pad);
  --lb-padb: var(--lb-pad);
  --lb-side: 80px;          /* 20px offset + 48px arrow + 12px air */
  --lb-cap: 40px;
  position: fixed; inset: 0; z-index: 140;
  background: rgba(16, 13, 10, .95);
  display: none; align-items: center; align-items: safe center; justify-content: center;
  padding: var(--lb-padt) var(--lb-pad) var(--lb-padb);
  overflow-y: auto; overscroll-behavior: contain;
}
.lb.is-open { display: flex; }
.lb__fig { margin: 0; max-width: 100%; display: flex; flex-direction: column; gap: 14px; }
.lb__img {
  max-width: min(100%, calc(100vw - 2 * var(--lb-side)));
  max-height: calc(100vh - var(--lb-padt) - var(--lb-padb) - var(--lb-cap) - 14px);
  max-height: max(120px, calc(100svh - var(--lb-padt) - var(--lb-padb) - var(--lb-cap) - 14px));
  width: auto; height: auto; object-fit: contain; display: block; margin-inline: auto;
}
.lb__cap { color: rgba(255,252,246,.72); font-size: .8rem; text-align: center; width: min(70ch, calc(100vw - 2 * var(--lb-pad))); margin-inline: auto; line-height: 1.55; }
/* fixed, not absolute: when a caption needs more room than a very small
   screen has (a 390px phone at 200 % zoom), the viewer scrolls and the
   buttons stay where they are, so the caption can be scrolled clear of them */
.lb__x, .lb__p, .lb__n {
  position: fixed; width: 48px; height: 48px; padding: 0;
  border: 1px solid rgba(255,252,246,.34); border-radius: 50%;
  background: rgba(255,252,246,.06); color: #fff; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.lb__x { top: max(20px, env(safe-area-inset-top, 0px)); right: max(20px, env(safe-area-inset-right, 0px)); }
.lb__x::before, .lb__x::after { content: ''; position: absolute; left: 15px; right: 15px; top: 23px; height: 1px; background: #fff; }
.lb__x::before { transform: rotate(45deg); } .lb__x::after { transform: rotate(-45deg); }
.lb__p { left: 20px; top: 50%; transform: translateY(-50%); }
.lb__n { right: 20px; top: 50%; transform: translateY(-50%); }
.lb__p svg, .lb__n svg { width: 14px; height: 14px; }
.lb__x:hover, .lb__p:hover, .lb__n:hover { background: var(--pearl); color: var(--espresso); border-color: var(--pearl); }

/* ==========================================================================
   14. FAQ
   ========================================================================== */
.faq { border-top: 1px solid var(--line); }
.faq__i { border-bottom: 1px solid var(--line); }
.faq__q {
  width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  padding: 22px 44px 22px 0; position: relative;
  font-family: var(--serif); font-size: clamp(1.08rem, 1.5vw, 1.32rem); font-weight: 400; color: var(--ink);
  line-height: 1.34;
}
.faq__ic { position: absolute; right: 4px; top: 50%; width: 13px; height: 13px; margin-top: -6px; }
.faq__ic::before, .faq__ic::after { content: ''; position: absolute; background: var(--bronze-text); transition: transform var(--mid) var(--ease), opacity var(--fast) var(--ease); }
.faq__ic::before { left: 0; right: 0; top: 6px; height: 1px; }
.faq__ic::after  { top: 0; bottom: 0; left: 6px; width: 1px; }
.faq__q[aria-expanded="true"] .faq__ic::after { transform: rotate(90deg); opacity: 0; }
/* v5.4.1: a long unbroken token (an email address, a phone line) may wrap
   rather than push the answer past a very narrow column */
.faq__a { padding: 0 0 24px; max-width: 74ch; overflow-wrap: anywhere; }
.faq__a p { color: var(--body); font-size: .95rem; line-height: 1.72; }

/* ==========================================================================
   15. FORM
   ========================================================================== */
/* v5.4.1: minmax(0, 1fr) and min-width 0, so a long option or error line can
   never widen a track past the form at 320px or under text zoom */
.form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 22px; }
.f { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.f--full { grid-column: 1 / -1; }
.f > label { font-size: .69rem; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.f > label .req { color: var(--bronze-text); }
.f input, .f select, .f textarea {
  font-family: var(--sans); font-size: .96rem; font-weight: 300; color: var(--ink);
  background: var(--pearl);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 13px 14px; width: 100%;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.f input:focus, .f select:focus, .f textarea:focus { border-color: var(--bronze-text); outline: none; background: #fff; }
.f textarea { min-height: 148px; resize: vertical; line-height: 1.6; }
.f select { appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%); background-position: calc(100% - 19px) 50%, calc(100% - 14px) 50%; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; padding-right: 38px; }
.f--hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form__foot { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 16px; align-items: center; justify-content: space-between; }
.form__note { font-size: .78rem; color: var(--muted); max-width: 46ch; line-height: 1.55; }
.form__msg { grid-column: 1 / -1; border: 1px solid var(--line); border-left: 2px solid var(--bronze); padding: 14px 16px; font-size: .88rem; color: var(--ink); background: var(--ivory); }

/* enquiry-type chooser */
.etypes { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; }
.etype { position: relative; }
.etype input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.etype span {
  display: block; text-align: center; padding: 15px 10px;
  border: 1px solid var(--line); border-radius: var(--radius);
  font-size: .715rem; letter-spacing: .09em; text-transform: uppercase; color: var(--ink);
  cursor: pointer; line-height: 1.35;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.etype span:hover { border-color: var(--espresso); }
.etype input:checked + span { background: var(--espresso); border-color: var(--espresso); color: var(--pearl); }
.etype input:focus-visible + span { outline: 2px solid var(--bronze-text); outline-offset: 3px; }

/* quick routes */
.routes { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(10px, 1.4vw, 16px); }
.route {
  display: flex; flex-direction: column; gap: 9px;
  padding: clamp(18px, 2.1vw, 26px);
  border: 1px solid var(--line); background: var(--pearl);
  transition: border-color var(--fast) var(--ease), transform var(--mid) var(--ease), box-shadow var(--mid) var(--ease);
}
.route:hover { border-color: var(--bronze); transform: translateY(-3px); box-shadow: var(--shadow-sm); }
.route svg { color: var(--bronze-text); width: 1.25rem; height: 1.25rem; }
.route__t { font-family: var(--serif); font-size: 1.22rem; color: var(--ink); line-height: 1.2; }
.route__d { font-size: .78rem; color: var(--muted); line-height: 1.5; overflow-wrap: anywhere; }

/* ==========================================================================
   16. PAGE HEAD
   ========================================================================== */
.phead { padding-top: clamp(38px, 5vw, 66px); padding-bottom: clamp(30px, 4vw, 52px); }
.crumbs { font-size: .67rem; letter-spacing: .17em; text-transform: uppercase; color: var(--muted); margin-bottom: clamp(22px, 3vw, 40px); }
.crumbs a { color: var(--bronze-text); }
.crumbs a:hover { text-decoration: underline; text-underline-offset: 3px; }
.crumbs span[aria-hidden] { padding: 0 .5em; opacity: .5; }
/* review round 1 (VV-09): the two columns start at the top. With
   align-items:end the heading dropped to the foot of its column beside a tall
   side column (245px of empty space above it on Visit at 1024x768), and a
   short lede sat low beside a tall heading (98-159px above it at 1180-1920px);
   any spare height is now below the shorter column */
.phead__grid { display: grid; grid-template-columns: 1.05fr 1fr; gap: clamp(24px, 4vw, 64px); align-items: start; }
.phead__side { padding-bottom: .4em; }
.phead__side .btnrow { margin-top: 22px; }

/* ==========================================================================
   17. MAP
   ========================================================================== */
.mapwrap { position: relative; background: var(--limestone); aspect-ratio: 16 / 9; overflow: hidden; }
.mapwrap iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; filter: grayscale(.32) contrast(1.02); }

/* ==========================================================================
   18. MOBILE DOCK + FLOATING WHATSAPP
   ========================================================================== */
.dock {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 96;
  display: none;
  background: rgba(252, 250, 246, .96);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  transition: transform var(--mid) var(--ease), visibility 0s linear 0s;
}
/* v5.4.1: the dock steps aside while the page head's (or the hero's) own
   calls to action sit in its band on arrival (main.js initDock); --dock-h is
   unchanged, so nothing on the page moves */
.dock.is-away {
  transform: translateY(100%); visibility: hidden; pointer-events: none;
  transition: transform var(--mid) var(--ease), visibility 0s linear var(--mid);
}
.dock a {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  padding: 10px 3px 11px;
  font-size: .61rem; letter-spacing: .05em; color: var(--ink);
  text-align: center;
}
.dock a svg { width: 18px; height: 18px; color: var(--bronze-text); }
.dock a span { display: block; width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dock a:active { background: var(--limestone); }

/* v5.4.1: the corner offsets add the device safe-area insets (0 until the
   page opts into viewport-fit=cover) */
.wafloat {
  position: fixed;
  right: calc(clamp(18px, 2.4vw, 34px) + env(safe-area-inset-right, 0px));
  bottom: calc(clamp(18px, 2.4vw, 34px) + env(safe-area-inset-bottom, 0px));
  z-index: 95;
  display: inline-flex; align-items: center; gap: .6em;
  padding: 13px 18px;
  background: var(--espresso); color: var(--pearl);
  border-radius: 999px; box-shadow: var(--shadow-md);
  font-size: .7rem; letter-spacing: .16em; text-transform: uppercase;
  transition: background var(--fast) var(--ease), transform var(--mid) var(--ease),
              opacity var(--mid) var(--ease), visibility 0s linear var(--mid);
}
.wafloat svg { width: 1.05rem; height: 1.05rem; color: var(--bronze-lite); }
.wafloat:hover { background: var(--charcoal); transform: translateY(-2px); }
/* withdrawn while the footer or a form is on screen, so a fixed button never
   sits on top of a link or a field */
.wafloat.is-away { opacity: 0; visibility: hidden; transform: translateY(14px); pointer-events: none; }
/* and never over the open menu (the drawer repeats its action) */
.drawer.is-open ~ .wafloat { opacity: 0; visibility: hidden; pointer-events: none; }

/* ==========================================================================
   19. FOOTER
   ========================================================================== */
.ftr { background: var(--espresso); color: #A9A296; padding-block: clamp(56px, 7vw, 92px) 30px; }
.ftr__top { display: grid; grid-template-columns: 1.7fr 1fr 1fr 1.25fr; gap: clamp(28px, 4vw, 64px); padding-bottom: clamp(38px, 5vw, 62px); border-bottom: 1px solid var(--line-dark); }
.brand__txt--ftr .brand__name { color: var(--pearl); font-size: 1.5rem; }
.brand__txt--ftr .brand__sub { color: #8C8478; }
.ftr__note { font-size: .82rem; line-height: 1.66; color: #948C80; margin-top: 18px; max-width: 40ch; }
.ftr__enq { display: inline-flex; align-items: center; gap: .55em; margin-top: 22px; font-size: .715rem; letter-spacing: .18em; text-transform: uppercase; color: var(--bronze-lite); }
.ftr__enq svg { transition: transform var(--mid) var(--ease); }
.ftr__enq:hover svg { transform: translateX(5px); }
.ftr__h { font-size: .67rem; letter-spacing: .2em; text-transform: uppercase; color: var(--pearl); margin-bottom: 18px; font-weight: 500; font-family: var(--sans); }
.ftr__col ul li { margin-bottom: 11px; }
.ftr__col a, .ftr address { font-size: .875rem; color: #A9A296; line-height: 1.6; overflow-wrap: anywhere; }
.ftr__col a:hover { color: var(--pearl); }
.ftr address { color: #A9A296; }
.ftr__base { display: flex; flex-wrap: wrap; gap: 14px 28px; justify-content: space-between; align-items: center; padding-top: 26px; font-size: .755rem; color: #877F73; }
.ftr__base a { color: #A9A296; }
.ftr__base a:hover { color: var(--pearl); }
.ftr__base-r { display: flex; flex-wrap: wrap; gap: 8px 22px; align-items: center; }
.ftr__credit { color: #766F64; }
.ftr__credit a { color: #8C8478; border-bottom: 1px solid rgba(255,252,246,.16); }

/* ==========================================================================
   20. UTILITY
   ========================================================================== */
.sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.tagline { display: block; width: fit-content; }
.nowrap { white-space: nowrap; }
/* review round 1 (VV-02): a keep-together group inside a page-head heading
   ("natural stone", "from behind."), so the balanced heading never leaves a
   single word on a line of its own; from 360px only, where the group always
   fits the column (below it the heading wraps freely) */
/* The group is only held together where it FITS. Unscoped, it overflowed a
   390x844 phone at 200 % browser zoom (a 195px CSS viewport): the contact
   heading's "Luxury Stones." measures 177px inside a 155px column, and the
   page gained 2px of sideways scroll. 300px is the floor with room to spare —
   its column is 260px — and below it the heading wraps freely, as it did
   before this patch.
   Repair round 1: that floor is written in em, because the group's width is
   set by the heading's own type (.h-xl bottoms out at 2.9rem) while 300px is
   a fixed column. 18.75em IS 300px at the default font, so nothing changes
   there; at a 24px browser font it is 450px, and the contact heading — 69.6px
   type, "Luxury Stones." 385px wide in a 335px column — wraps freely again
   instead of pushing 30px of sideways scroll onto a 375px phone. */
@media (min-width: 18.75em) { .hkeep { white-space: nowrap; } }
/* Repair round 3 (verify2 VR3-03 / contact-h1-hkeep-overflow): 18.75em still
   let the group in where it does not fit at a Large (20px) browser font. The
   heading is 2.9rem = 58px there, "Luxury Stones." measures about 6.5em
   (375px) with the fallback serif, and a 375px phone has a 335px column, so
   contact.html scrolled sideways by 20px at 375x812 and 5px at 390x844 (3px
   at 430x932 / 22px). A heading that holds a keep-together group is now also
   capped by its column, so the group always fits where it is held. The cap
   is the heading's own tier size (--hxl-fs) or the column, whichever is
   smaller, on every width where the group is held (from 18.75em): it only
   binds when the browser font or zoom is enlarged. At the default 16px it is
   48.5px at 360px and 42.4px at 320px against the 46.4px and 35.2px the
   heading already uses; at 390x844 and 125 % zoom (312px of CSS, where the
   very-narrow tier below puts the heading back at 46.4px) it is 41.2px, and
   "Luxury Stones." no longer pushes 8px of sideways scroll. */
@media (min-width: 18.75em) and (max-width: 759.98px) {
  .h-xl:has(.hkeep) { font-size: min(var(--hxl-fs), calc((100vw - 2 * var(--gut)) / 6.6)); }
}
/* Below 360px the group only fits once the display heading steps down: at
   320px .h-xl resolves to its 2.9rem floor (46.4px), where "Luxury Stones."
   measures 312px inside a 280px column, so keeping it together would have
   overflowed the page instead of fixing the orphan. 2.2rem brings it to
   about 226px, the group holds, and "Contact / Lumiere / Luxury Stones."
   reads as three deliberate lines rather than a stranded last word.
   (Round 1 scoped .hkeep to 360px and up for exactly this reason; the
   heading size is the part it did not change.) */
@media (max-width: 359.98px) { .h-xl { --hxl-fs: clamp(2.2rem, 11vw, 2.7rem); } }
/* review round 1 (VV-06): at 320-359px the bookmatched card's call to action
   takes the card's full width with slightly tighter tracking, so "Ask about
   bookmatched slabs" breaks over two lines instead of three */
@media (min-width: 320px) and (max-width: 359.98px) {
  .bleed__over .btn { width: 100%; letter-spacing: .1em; padding-inline: 12px; }
}
.vis-note {
  display: inline-block; margin-top: 8px;
  font-size: .66rem; letter-spacing: .13em; text-transform: uppercase;
  color: var(--muted); border-left: 2px solid var(--bronze-soft); padding-left: 9px; line-height: 1.5;
}
.dark .vis-note { color: #948C80; }
.legal { max-width: 74ch; overflow-wrap: anywhere; }
.legal h2 { font-family: var(--serif); font-size: 1.55rem; font-weight: 400; margin: 44px 0 14px; }
.legal h2:first-child { margin-top: 0; }
.legal p, .legal li { font-size: .95rem; line-height: 1.75; }
.legal ul { list-style: disc; padding-left: 1.3em; margin-bottom: 1.1em; }
.legal li { margin-bottom: .5em; }

/* ==========================================================================
   21. RESPONSIVE
   ========================================================================== */
@media (max-width: 1279.98px) {
  .stmt__fig { grid-column: 1 / span 5; }
  .stmt__body { grid-column: 7 / span 6; }
  .mason { columns: 3; }
}

/* v5.4.1 COMPACT HEADER — the one breakpoint (main.js NAV_COMPACT_MQ).
   The desktop row (brand, six links, the stacked WhatsApp / Office column,
   Enquire) was switched on at 1100px, where it needs about 1089px inside a
   990px content box: Enquire was clipped to "ENQ" up to 1170px and ate the
   right gutter up to 1250px. Measured with this stylesheet, the row fits with
   every gap at 16px or more from 1210px; 1280px adds a 70px margin for
   fallback fonts, text zoom and scrollbar differences. Nothing else in the
   layout changes here: the non-header rules keep their own breakpoints.
   Review round 1 (F3): the header's text is sized in rem, which follows the
   browser's font-size setting (Settings > Appearance > Font size), but the
   switch was in px, so at Large (20px) the desktop row came back at 1280px
   with Enquire clipped. Every header tier is now written in em: in a media
   query 1em is the browser's default font size, so 79.999em is 1279.98px at
   the default 16px, 1599.98px at 20px and 1919.98px at 24px, and the row
   switches on where its scaled text fits. The header's content box scales
   the same way (.hdr__in max-width, section 7). */
@media (max-width: 79.999em) {
  :root { --hdr-h: 68px; }
  .nav { display: none; }
  /* the nav carried margin-left:auto; with it hidden the actions need it */
  .hdr__act { margin-left: auto; }
  .burger { display: block; }
  .hdr__tels { flex-direction: row; }
  /* the Office line is display:none on the base rule at every width now
     (section 7), so this tier no longer has to hide it */
  /* the 44px target is on the base rule now (section 7) */
  .brand__mark { height: 34px; }
}

/* OWNER REVIEW: "the header consumes too much visual space". On a tall screen
   the 75px header is 8.0-8.3 % of the hero; on a 529px-tall laptop window it
   is 14.2 %, and that is where the complaint bites. The lever is the row
   height, not its contents, so short viewports get a shorter row. Every
   header control keeps its 44px minimum inside it, and --hdr-offset follows
   automatically because main.css derives it from --hdr-h and main.js
   re-measures the rendered header. A height query, so no header WIDTH tier is
   introduced: NAV_COMPACT_MQ is still the one width breakpoint. */
@media (max-height: 600px) {
  :root { --hdr-h: 64px; }
}
/* a landscape phone has 375-430px of height in total; 56px still clears the
   44px minimum every header control keeps, and gives the hero back 13px */
@media (max-height: 460px) {
  :root { --hdr-h: 56px; }
}

/* 480–1023.98px at the default font size: the primary line is a 44px icon
   button (its label and number stay in the DOM and in its aria-label). In em
   like every header tier (review round 1, F3): 63.999em is 1023.98px at 16px */
@media (max-width: 63.999em) {
  .hdr__tel span { display: none; }
  .hdr__tel { justify-content: center; min-width: 44px; padding: 11px; border: 1px solid var(--line); border-radius: 50%; }
  .hdr__tel svg { width: 1.05rem; height: 1.05rem; }
  .hdr--over .hdr__tel { border-color: rgba(255,252,246,.4); }
}

@media (max-width: 1099.98px) {
  .shead__r { grid-template-columns: 1fr; gap: 16px; align-items: start; }
  .shead__r .lede { padding-bottom: 0; }
  .stmt__fig { grid-column: 1 / span 6; }
  .stmt__body { grid-column: 7 / span 6; }
  .pair__a { grid-column: 1 / span 8; }
  .pair__b { grid-column: 9 / span 4; padding-top: clamp(30px, 6vw, 70px); }
  .pair--flip .pair__a { grid-column: 5 / span 8; }
  .pair--flip .pair__b { grid-column: 1 / span 4; }
  .enqb { grid-template-columns: 1fr; gap: 30px; }
  .ftr__top { grid-template-columns: 1fr 1fr; }
  .mason { columns: 2; }
  .etypes { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 899.98px) {
  .gates { grid-template-columns: 1fr; }
  .plates { grid-template-columns: 1fr; }
  .routes { grid-template-columns: repeat(2, 1fr); }
  /* minmax(0, 1fr) (repair round 3): one unbreakable heading word can no
     longer widen the column the lede and its buttons share */
  .phead__grid { grid-template-columns: minmax(0, 1fr); gap: 22px; align-items: start; }
  .mat--s3, .mat--s4, .mat--s5 { grid-column: span 6; }
  .mat--lift { margin-top: 0; }
}

/* the phone header tier (760px at the default font size), written in em like
   every header tier (review round 1, F3); the phone layout below keeps its
   px breakpoint */
@media (max-width: 47.499em) {
  .hdr__in { gap: 14px; }
  .hdr__act { gap: 12px; }
  .brand__name { font-size: 1.22rem; }
  .hdr__cta { padding: 13px 18px; font-size: .69rem; letter-spacing: .13em; }
  .brand__mark { height: 32px; }
}

@media (max-width: 759.98px) {

  /* The dock is only measured by JS after boot. Until then --dock-h was 0, so
     for one frame the hero controls sat under the dock. Seeding the designed
     height here makes the FIRST paint correct; JS then refines it for the
     safe-area inset and any user font scaling. */
  :root { --gut: 20px; --dock-h: 61px; }
  body { font-size: 15.5px; }
  .dock { display: flex; }
  .wafloat { display: none; }
  /* phones keep the full-height hero, without the 940px desktop cap */
  .hero { min-height: 100vh; min-height: 100svh; }
  /* the composition line on a phone is 24 % of the hero (the block is a
     bigger share of a narrow frame, so it starts higher than on a desktop),
     and the breathing zone under the 69px compact header is 54px (the phone
     header is 68px plus its 1px border) */
  .hero__body {
    --hero-air: 54px;
    --hero-line: 24svh;
    padding-top: max(calc(var(--hdr-offset) + var(--hero-air)), var(--hero-line));
    /* the dots sit 30px above the dock and are 22px tall, so the reserve is
       measured from the dock rather than taken as a flat 20vh — at 812px of
       height 20vh was 162px and pushed the in-flow hero past the viewport */
    padding-bottom: max(calc(var(--dock-h) + 76px), 13vh);
  }
  .hcopy { max-width: none; }
  /* the copy column is full width on a phone, so the same scrim is spread
     over twice the area and thins out behind the small eyebrow: measured over
     the first slide the eyebrow p10 fell to 2.2:1 at 430x932. The luminous
     frames carry a deeper wash here, and the eyebrow a stronger shadow. */
  .hslide-copy[data-tone="bright"] { --scrim: .72; }
  .hslide-copy[data-tone="deep"] { --scrim: .46; }
  .hcopy .eyebrow { text-shadow: 0 1px 2px rgba(12,9,6,.62), 0 0 16px rgba(12,9,6,.55); }
  /* two CTA rows, not three: three full-width buttons stacked to 142px, which
     is 17 % of an 844px hero spent on chrome. The primary action keeps the
     full width; the two secondary ones share a row.
     Repair round 3 (VR3-01 / NR3-01): that row is CONTENT-MEASURED. It was
     grid-template-columns: 1fr 1fr, and a 1fr track cannot shrink below its
     button's longest word, so at a 22-24px browser font the two tracks stayed
     193px wide and pushed the copy past a 360-412px screen. A wrapping flex
     row keeps the same picture wherever the two buttons fit side by side
     (each grows from half the row, so they are equal, and a two-line label
     stretches its neighbour to the same height, as the grid did), and when
     their words cannot fit in half the row the second one simply takes its
     own line. The flex items keep min-width:auto on purpose: that is what
     makes the break happen at the longest word instead of letting a label
     overflow its button. */
  .hcopy .btnrow { display: flex; flex-wrap: wrap; gap: 10px; }
  .hcopy .btnrow .btn { flex: 1 1 calc(50% - 6px); padding-inline: 12px; letter-spacing: .1em; line-height: 1.25; }
  .hcopy .btnrow .btn:first-child { flex-basis: 100%; }
  /* the headline's longest word ("Bookmatched," on slide 4) must fit the
     column: 2.7rem is 64.8px at a 24px browser font, about 380px of word on a
     320px column. The cap only binds when the word would not fit (below about
     308px of screen at the default font size, so no default phone changes). */
  .hcopy h1, .hcopy .hcopy__t { font-size: min(2.7rem, calc((100vw - 2 * var(--gut)) / 6.2)); overflow-wrap: break-word; }
  /* 30px of clearance above the dock, measured from the dock's own height so
     the gap survives a taller dock from a safe-area inset or user font
     scaling. 30 rather than 22 is a thumb-reach judgement: the slider dots
     are a 22px target sitting directly above a 61px fixed bar, and 22px of
     air between two tap targets invites mis-taps. (An earlier note here
     blamed URL-bar collapse for an audit failure at 320x568. That was wrong:
     the failure was in the audit harness, which probed while a smooth
     scroll-to-top was still animating and so read every rect displaced by the
     residual scroll. At rest the clearance is exactly this value.) */
  .hctl { bottom: calc(30px + var(--dock-h)); }
  .hdots { max-width: none; }
  .harrows { display: none; }
  .hscroll { display: none; }
  .stmt__fig { grid-column: 1 / -1; }
  .stmt__body { grid-column: 1 / -1; }
  .stmt__facts { grid-template-columns: 1fr; gap: 14px; }
  .stmt__facts .fact { display: flex; align-items: baseline; gap: 12px; }
  .fact__v { margin-top: 0; }
  .pair__a, .pair__b, .pair--flip .pair__a, .pair--flip .pair__b { grid-column: 1 / -1; padding-top: 0; order: 0; }
  .bleed__over { margin-top: -34px; margin-inline: var(--gut); max-width: none; }
  .bleed--r .bleed__over { margin-left: var(--gut); }
  .mason { columns: 1; }
  .form { grid-template-columns: 1fr; }
  .etypes { grid-template-columns: repeat(2, 1fr); }
  .ftr__top { grid-template-columns: 1fr; gap: 32px; }
  .info__row { grid-template-columns: 1fr; gap: 6px; }
  .info__k { padding-top: 0; }
  .role { grid-template-columns: 1.8rem 1fr; }
  .role__go { grid-column: 2; margin-top: 10px; }
  .lb__p { left: 10px; } .lb__n { right: 10px; }
  /* the picture keeps clear of arrows 10px from the edge: 10 + 48 + 12px air */
  .lb { --lb-side: 70px; }
}

@media (max-width: 479.98px) {
  /* v5.4.1: the phone header rules were written twice, here and in the
     479.98px block after section 25; only that later copy (after .btn, which
     would otherwise restyle the Enquire pill) is kept. */
  .routes { grid-template-columns: 1fr; }
  .mat--s3, .mat--s4, .mat--s5 { grid-column: 1 / -1; }
  .drawer__foot { grid-template-columns: 1fr; }
  .btn { padding: 13px 20px; font-size: .715rem; letter-spacing: .15em; }
}

/* short viewports — the hero must never push copy into the header.
   v5.4.1: the hero grows with its copy, so these rules only keep the copy
   compact; none of them sets a hero height.
   Owner review: the composition line drops to 26 % of the hero here, with a
   40px breathing zone under the (now 65px) header, because a 529px-tall hero  
   cannot spend 30 % above the eyebrow and still leave the CTA group clear of
   the slider controls. 1366x529 slide 1 is the reference frame for the whole
   patch: clearance 84px, block top 30 %, block centre 56 %. */
@media (max-height: 700px) and (min-width: 760px) {
  .hero__body {
    --hero-air: 40px;
    --hero-line: 26svh;
    padding-top: max(calc(var(--hdr-offset) + var(--hero-air)), var(--hero-line));
    padding-bottom: 96px;
  }
  .hcopy h1, .hcopy .hcopy__t { font-size: clamp(2rem, min(4.4vw, 7.5vh), 3.4rem); margin-bottom: clamp(16px, 3.4vh, 26px); }
  .hcopy .eyebrow { margin-bottom: clamp(10px, 1.8vh, 16px); }
  .hcopy p { font-size: .95rem; margin-bottom: clamp(20px, 3.8vh, 30px); }
  .hctl { bottom: 22px; }
}
/* short phones (portrait, up to 700px tall): the copy tightens and the three
   CTAs take two rows, so eyebrow, heading and CTAs sit between the header and
   the slide dots, and the dots stay 30px clear of the dock. The old
   calc(104px + dock) bottom padding left a 263px box for about 400px of copy.
   Owner review: the line is 19.5 % of the hero with a 42px breathing zone —
   at 320x568 that is a 111px composition line, 42px of clear photo under the
   header, and 26px still left between the CTA grid and the dots. */
@media (max-width: 759.98px) and (max-height: 700px) {
  .hero__body {
    --hero-air: 42px;
    --hero-line: 19.5svh;
    padding-top: max(calc(var(--hdr-offset) + var(--hero-air)), var(--hero-line));
    padding-bottom: calc(var(--dock-h) + 62px);
  }
  .hcopy .eyebrow { margin-bottom: 8px; }
  .hcopy h1, .hcopy .hcopy__t { font-size: min(clamp(1.9rem, 7.5vw, 2.4rem), calc((100vw - 2 * var(--gut)) / 6.2)); margin-bottom: 10px; }
  .hcopy p { font-size: .86rem; line-height: 1.5; margin-bottom: 14px; }
  /* the same content-measured row as the phone tier, a notch tighter */
  .hcopy .btnrow { display: flex; flex-wrap: wrap; gap: 8px; }
  .hcopy .btnrow .btn { flex: 1 1 calc(50% - 5px); padding-inline: 10px; letter-spacing: .1em; line-height: 1.2; }
  .hcopy .btnrow .btn:first-child { flex-basis: 100%; }
}
/* landscape phones (up to 480px tall): one CTA row, kept clear of the corner
   WhatsApp button by a 12rem right margin.
   Owner review: 375-430px of height has to carry a 57px header, five copy
   elements and the slider dots, so the composition line is 20 % with a 40px
   breathing zone and the type steps down again; the slider ARROWS step aside
   here (swipe, dots and the arrow keys all still work) so the dots band is
   22px instead of 46px and the CTA group keeps its clearance. */
@media (max-height: 480px) and (orientation: landscape) {
  .hero__body {
    --hero-air: 40px;
    --hero-line: 20svh;
    padding-top: max(calc(var(--hdr-offset) + var(--hero-air)), var(--hero-line));
    padding-bottom: 56px;
  }
  .hcopy { max-width: min(52rem, 100% - 12rem); }
  .hcopy h1, .hcopy .hcopy__t { font-size: clamp(1.35rem, 6.8vh, 2.1rem); margin-bottom: 8px; }
  .hcopy .eyebrow { font-size: .66rem; line-height: 1.45; margin-bottom: 6px; }
  /* 44ch, not 60ch: ch is the "0" advance, and in this sans it runs about a
     third wider than the average character, so 60ch measured 78-84 characters
     a line — well past the 60-character ceiling the rest of the site holds to */
  .hcopy p { font-size: .78rem; line-height: 1.45; max-width: 44ch; margin-bottom: 10px; }
  .hcopy .btnrow { display: flex; gap: 8px; }
  .hcopy .btnrow .btn { flex: 0 0 auto; padding-inline: 16px; letter-spacing: .12em; line-height: 1; }
  .hcopy .btnrow .btn:first-child { flex-basis: auto; }
  .harrows { display: none; }
  .hctl { bottom: 16px; }
}
/* Landscape phones under 760px wide keep the dock. Round 1 replaced it here
   with the corner WhatsApp button, because a 61px dock covered the hero CTAs
   of a 320px-tall screen on arrival — but that traded four persistent contact
   routes for one, and the corner button then withdrew itself (it is guarded
   against covering anything), so a 1366x768 laptop at 200 % browser zoom —
   683x384 of CSS — arrived with NO quick-contact control at all except the one
   in the header, on all ten pages: 80 reachability rows that v5.4 has and this
   release did not. The covering problem is solved properly now: main.js
   initDock steps the dock aside for any control it would cover on the arrival
   screen and brings it back as soon as they scroll out of its band, which is
   the same guard the corner button uses. So the dock comes back here, the
   corner button stays off (one bottom affordance, not two), and the hero keeps
   the slightly deeper bottom reserve this tier was given. */
@media (max-height: 480px) and (orientation: landscape) and (max-width: 759.98px) {
  .hero__body { padding-bottom: 62px; }
  .hctl { bottom: 30px; }
}
/* SHORT LANDSCAPE (375-400px of CSS height — an 812x375 or 844x390 phone on
   its side, and a 1366x768 laptop at 200 % zoom is 683x384). 375px carries a
   57px header, five copy elements and the slider dots, so the breathing zone
   is 28px: 40px of air and 24px between the CTA group and the dots cannot
   both be had here, and the measured choice is to protect the gap the
   visitor's thumb needs. */
@media (max-height: 400px) and (orientation: landscape) {
  .hero__body {
    --hero-air: 28px;
    --hero-line: 18svh;
    padding-bottom: 44px;
  }
  .hcopy h1, .hcopy .hcopy__t { font-size: clamp(1.2rem, 6.2vh, 1.8rem); margin-bottom: 6px; }
  .hcopy .eyebrow { font-size: .62rem; line-height: 1.4; margin-bottom: 5px; }
  .hcopy p { font-size: .74rem; line-height: 1.4; margin-bottom: 8px; }
  .hdots { --dot-h: 30px; }
  .hctl { bottom: 14px; }
}
/* THE SHORTEST LANDSCAPE (340px and under — a 1136x640 phone on its side is
   568x320). The round-1 build overflowed the viewport by 151px here with the
   slider dots below the fold on every slide. Everything steps down one more
   notch and the CTA group goes back to the two-row grid, which brings the
   hero inside the viewport and the dots back on screen. The breathing zone is
   12px and the gap to the dots about 8px: at 320px of total height that is
   the arithmetic, not a choice, and it is what v5.3 and v5.4 do too. */
@media (max-height: 340px) and (orientation: landscape) {
  .hero__body {
    --hero-air: 12px;
    --hero-line: 14svh;
    padding-bottom: 26px;
  }
  .hcopy h1, .hcopy .hcopy__t { margin-bottom: 4px; }
  .hcopy .eyebrow { margin-bottom: 3px; }
  .hcopy p { line-height: 1.3; margin-bottom: 4px; }
  .hcopy .btnrow { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
  .hcopy .btnrow .btn:first-child { grid-column: 1 / -1; }
  .hctl { bottom: 6px; }
}

/* below 360px CSS width (a 320px phone, or a 390px phone zoomed to 125–200%):
   every 12-column grid is already a single column here, so its eleven column
   gaps only added a fixed 198–220px minimum that overflowed a 195–260px page */
@media (max-width: 359.98px) {
  .g12, .atelier, .pair { column-gap: 0; }
}
/* lightbox on portrait phones and tablets: previous / next sit in a row under
   the image and caption instead of on top of the picture */
@media (orientation: portrait) and (max-width: 1099.98px) {
  /* the arrows live in the bottom band, below the caption, never beside the
     picture; the picture's max-height (section 13) subtracts both bands and
     the caption's measured height */
  .lb { --lb-padt: 80px; --lb-padb: calc(84px + env(safe-area-inset-bottom, 0px)); --lb-side: 0px; }
  .lb__p, .lb__n { top: auto; bottom: calc(18px + env(safe-area-inset-bottom, 0px)); transform: none; }
  .lb__p { left: calc(50% - 58px); }
  .lb__n { right: calc(50% - 58px); }
}

/* ==========================================================================
   22. REDUCED MOTION
   --------------------------------------------------------------------------
   Written as ONE universal rule rather than a list of selectors. v4.1 shipped
   a reduced-motion block that enumerated ".reveal .m img" and missed the eight
   hoverable cards that sat outside any .reveal. A universal rule cannot be
   outrun by a component added later.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0s !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0s !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
  /* anything that animates INTO view must simply be in view */
  .reveal { opacity: 1 !important; transform: none !important; }
  .maskline > span { transform: none !important; }
  .m img, .hoverable:hover .m img, .hoverable:focus-within .m img,
  .gate:hover .m img { transform: none !important; }
  .hslide.is-on .m img { animation: none !important; }
  .hdot[aria-current="true"].is-timing::after { width: 100%; }
}

/* ==========================================================================
   23. PRINT
   ========================================================================== */
@media print {
  .hdr, .drawer, .dock, .wafloat, .hctl, .lb, .rail__nav, .chips { display: none !important; }
  body { background: #fff; color: #000; padding: 0; }
  .hero { height: auto; max-height: none; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .7em; }
}

/* ==========================================================================
   24. LATE COMPONENTS
   ========================================================================== */

/* trade role blocks — a number/heading rail with the body offset beside it */
.trole { display: grid; grid-template-columns: 1fr 1.6fr; gap: clamp(18px, 3vw, 54px); padding: clamp(26px, 3.4vw, 44px) 0; border-bottom: 1px solid var(--line); }
.trole:last-child { border-bottom: 0; }
.trole__h { display: flex; align-items: baseline; gap: 14px; }
.trole__n { font-size: .68rem; letter-spacing: .18em; color: var(--bronze-text); }
.trole__b .lede { max-width: 58ch; }

/* checked list */
.ticks { display: grid; gap: 9px; }
.ticks li { position: relative; padding-left: 22px; font-size: .93rem; line-height: 1.62; color: var(--body); }
.ticks li::before {
  content: ''; position: absolute; left: 0; top: .62em;
  width: 9px; height: 1px; background: var(--bronze);
}
.dark .ticks li { color: #B4ACA0; }

/* the hero figure never renders a caption */
.fig--hero { height: 100%; }
.fig--hero .fig__cap { display: none; }

@media (max-width: 899.98px) {
  .trole { grid-template-columns: 1fr; gap: 14px; }
}

/* ==========================================================================
   25. GRID COLUMN UTILITIES
   --------------------------------------------------------------------------
   These replace inline `style="grid-column: …"`. An inline declaration cannot
   be overridden by a media query without !important, so pages written that way
   kept a two-column split at 390px — which on the Enquire page left the
   supporting rail one word wide. Classes collapse; inline styles do not.
   ========================================================================== */
.col-1-4  { grid-column: 1 / span 4; }
.col-1-5  { grid-column: 1 / span 5; }
.col-1-6  { grid-column: 1 / span 6; }
.col-1-7  { grid-column: 1 / span 7; }
.col-6-7  { grid-column: 6 / span 7; }
.col-7-6  { grid-column: 7 / span 6; }
.col-8-5  { grid-column: 8 / span 5; }
.col-9-4  { grid-column: 9 / span 4; }

@media (max-width: 1099.98px) {
  .col-1-7 { grid-column: 1 / span 7; }
  .col-9-4 { grid-column: 9 / span 4; }
  .col-1-4 { grid-column: 1 / span 5; }
  .col-6-7 { grid-column: 6 / span 7; }
}
@media (max-width: 899.98px) {
  .col-1-4, .col-1-5, .col-1-6, .col-1-7,
  .col-6-7, .col-7-6, .col-8-5, .col-9-4 { grid-column: 1 / -1; }
}

/* Quick-route cards go horizontal on a phone: four stacked vertical cards
   pushed the enquiry form most of a screen further down. */
/* review round 1 (F3): the small-phone header tier (480px at the default
   font size) is written in em like every header tier; at Very large (24px)
   the px tier left the burger half off a 320px screen */
@media (max-width: 29.999em) {
  /* The header carried brand + phone + Enquire pill + burger, which measured
     398px of content at EVERY phone width — so the burger sat outside a 320,
     360 or 390px viewport and the menu could not be opened. It was invisible
     to an overflow check because body has overflow-x: hidden, which clips
     scrollWidth. Below 480px the phone icon is dropped (Call is in the dock),
     the wordmark loses its sub-label, and the pill tightens. */
  .hdr__in { gap: 12px; padding-inline: max(16px, env(safe-area-inset-left, 0px)) max(16px, env(safe-area-inset-right, 0px)); }
  /* v5.4.1: the whole phone column goes, not only its links: an empty
     .hdr__tels still cost the header a 10px gap (1.8px too many at 195px) */
  .hdr__tels, .hdr__tel { display: none; }
  .hdr__act { gap: 10px; }
  .brand { gap: 9px; }
  /* v5.4.1: height only (36.7 x 30), never a square box; the burger keeps
     its 44px target (it was 38px here) */
  .brand__mark { height: 30px; }
  .brand__name { font-size: 1.14rem; letter-spacing: .07em; }
  .brand__sub { display: none; }
  .hdr__cta { padding: 12px 14px; font-size: .655rem; letter-spacing: .11em; }
}

@media (max-width: 479.98px) {
  .route { flex-direction: row; align-items: center; gap: 14px; padding: 15px 16px; }
  .route svg { width: 1.15rem; height: 1.15rem; }
  .route__t { font-size: 1.06rem; }
  .route__d { font-size: .74rem; margin-left: auto; text-align: right; max-width: 55%; }
}

/* v5.4.1: the narrowest header tier (a 320px phone, or a 390px phone at 150%
   or 200% zoom, which is 260px / 195px of CSS width): the brand steps down and
   the header padding tightens. Placed after the 479.98px header block above,
   which would otherwise restore the 16px padding. */
@media (max-width: 19.999em) {
  .hdr__in { gap: 10px; padding-inline: max(12px, env(safe-area-inset-left, 0px)) max(12px, env(safe-area-inset-right, 0px)); }
  .brand__name { font-size: 1.06rem; }
}
/* Dropping the Enquire pill is the one decision in this tier that is about the
   width in PIXELS as well as the text size: below 320px of CSS width the brand
   and the menu button need the whole bar (Enquire stays in the menu, in the
   dock and in every page body). Repair round 1 (matrix m3): on the em query
   alone, 19.999em is 400px at a 20px browser font and 480px at 24px, so
   ordinary phones lost the pill although it fits — measured with it restored,
   360x800 at 20px leaves 61px of slack to the brand and 10px to the burger,
   and 375x812 / 390x844 / 430x932 at 24px leave 47 / 62 / 102px, with no
   overflow in any case. Both conditions are kept, so the pill leaves when the
   bar is narrow in px AND narrow for its own text (at a small browser font it
   can stay down to 240px), which is what the header's em tiers express. */
@media (max-width: 19.999em) and (max-width: 319.98px) {
  .hdr__cta { display: none; }
}
/* and the text-size half of the same decision, measured rather than assumed:
   at a 24px browser font the pill does fit on a 360px phone (47-102px of
   slack at 375-430px) but NOT on a 320px one — restoring it there put the
   burger 5.6px outside the header's content edge on all four pages, and at
   22px the same 320px phone failed the header-gutter check by a hair. 14.55em
   is 320px at a 22px font and 349px at 24px, so the pill leaves a 320px phone
   from 22px upward and a 340px one at 24px; at 16px (233px) and 20px (291px)
   it sits inside the 320px rule above, so this query only ever adds the
   very-large-font cases and the px rule governs the rest. */
@media (max-width: 14.55em) {
  .hdr__cta { display: none; }
}
/* the rest of the very narrow layout keeps its px breakpoint */
@media (max-width: 319.98px) {
  /* display headings scale with the very narrow viewport ("Wholesale" and
     "appointment" were wider than a 155px column at 46px and 35px) */
  .h-xl { --hxl-fs: clamp(2rem, 16vw, 2.9rem); }
  .h-lg { font-size: clamp(1.6rem, 12vw, 2.2rem); }
  /* a button label may break as a last resort rather than widen the page */
  .btn { padding-inline: 14px; letter-spacing: .08em; overflow-wrap: anywhere; }
  .bleed__over { margin-inline: 12px; padding: 20px; }
}

/* ---- v5.2: enquiry form states --------------------------------------------
   Inline field errors, the disabled button while sending, the failure note
   with call / WhatsApp / email routes, and the success panel that replaces
   the form without a page reload. */
.form__req { grid-column: 1 / -1; margin: -8px 0 0; }
.f > label .opt { text-transform: none; letter-spacing: .02em; }
.f input[aria-invalid="true"], .f select[aria-invalid="true"], .f textarea[aria-invalid="true"] { border-color: #9B3B2E; }
.f__err { margin: 0; font-size: .8rem; line-height: 1.45; color: #9B3B2E; }
.form .btn[disabled] { opacity: .6; cursor: progress; }
.form__msg--ok { border-left-color: var(--bronze); }
.form__msg--err { border-left-color: #9B3B2E; }
.form__alt { display: flex; flex-wrap: wrap; gap: 8px 20px; margin-top: 10px; }
.form__alt a { border-bottom: 1px solid var(--line); padding-bottom: 1px; }
.form__alt a:hover { border-color: var(--bronze-text); color: var(--bronze-text); }
.form__done { margin-top: 30px; padding: clamp(20px, 2.6vw, 30px); border: 1px solid var(--line); border-left: 2px solid var(--bronze); background: var(--ivory); }
.form__done:focus { outline: 2px solid var(--bronze-text); outline-offset: 3px; }
.form__done p { font-family: var(--serif); font-size: 1.32rem; line-height: 1.4; color: var(--ink); }
.form[hidden] { display: none; }
.form__msg p { margin: 0; }
.form__done .small, .form__state .small { font-family: var(--sans); font-size: .84rem; line-height: 1.62; color: var(--muted); margin: 8px 0 0; }
.form__done p:last-child, .form__state p:last-child { margin-bottom: 0; }

/* no-JavaScript result panels: the server redirects to #enquiry-sent or
   #enquiry-error and :target reveals the matching panel */
.form__state { display: none; margin-top: 30px; padding: clamp(20px, 2.6vw, 30px); border: 1px solid var(--line); border-left: 2px solid var(--bronze); background: var(--ivory); scroll-margin-top: calc(var(--hdr-h) + 18px); }
.form__state--err { border-left-color: #9B3B2E; }
.form__state:target { display: block; }
.form__state:focus { outline: 2px solid var(--bronze-text); outline-offset: 3px; }
.form__state-t { font-family: var(--serif); font-size: 1.32rem; line-height: 1.4; color: var(--ink); margin: 0; }
#enquiry-sent:target ~ .form { display: none; }
.nojs-token { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.form__alt a { overflow-wrap: anywhere; }
.form__done .form__alt, .form__state .form__alt { font-family: var(--sans); font-size: .88rem; line-height: 1.5; margin: 12px 0 0; }

/* v5.2: public hours in the footer */
.ftr__hours { font-size: .875rem; color: #A9A296; line-height: 1.6; margin: 12px 0 0; }

/* ==========================================================================
   26. v5.3 — two phone lines, trust strip, featured trio, contact strip,
   weekend block, wholesale trio, material-interest note
   ========================================================================== */

/* labelled call buttons: "Call  WHATSAPP / ASHISH  +1 (561) 938-1796". The
   label may wrap onto a second line inside the button on a phone. */
.btn__k { font-size: .66em; letter-spacing: .14em; opacity: .78; }
.btn:has(.btn__k) { flex-wrap: wrap; line-height: 1.25; row-gap: .2em; }
.alt .btn__k { font-size: .72em; letter-spacing: .1em; text-transform: uppercase; opacity: .8; }

/* header phone lines: v5.4.1 moved these rules into section 7, and the Office
   line's own min-width:1280px / max-width:1099.98px tiers into the one compact
   header query in section 21 */

/* mobile drawer: both call buttons full width */
.drawer__foot .btn--wide { grid-column: 1 / -1; }

/* trust strip under the home hero */
.trust { background: var(--ivory); border-bottom: 1px solid var(--line-soft); }
.trust__list { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(14px, 2vw, 28px); padding-block: clamp(18px, 2.4vw, 30px); }
.trust__list li { display: flex; flex-direction: column; gap: 4px; padding-left: 14px; border-left: 1px solid var(--line); }
.trust__k { font-family: var(--serif); font-size: 1.14rem; color: var(--ink); line-height: 1.2; }
.trust__v { font-size: .78rem; color: var(--muted); line-height: 1.5; }
.trust__v a { color: var(--bronze-text); display: inline-flex; align-items: center; gap: .4em; }
.trust__v a svg { width: .8em; height: .8em; }
@media (max-width: 899.98px) { .trust__list { grid-template-columns: 1fr 1fr; } }
@media (max-width: 479.98px) { .trust__list { grid-template-columns: 1fr; } }

/* featured: Crystallo · Patagonia, three equal 3/2 cards */
.feat { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(18px, 2.4vw, 34px); }
.feat__card { display: block; }
.feat__body { display: block; margin-top: 14px; }
.feat__n { display: block; font-family: var(--serif); font-size: 1.5rem; color: var(--ink); line-height: 1.15; }
.feat__note { display: block; font-size: .88rem; color: var(--muted); margin-top: 6px; line-height: 1.55; }
.feat__go { display: inline-flex; align-items: center; gap: .5em; margin-top: 10px; font-size: .69rem; letter-spacing: .17em; text-transform: uppercase; color: var(--bronze-text); }
.feat__go svg { transition: transform var(--mid) var(--ease); }
.feat__card:hover .feat__go svg { transform: translateX(5px); }
@media (max-width: 899.98px) { .feat { grid-template-columns: 1fr 1fr; } }
@media (max-width: 599.98px) { .feat { grid-template-columns: 1fr; } }

/* contact strip: every route in one labelled row */
.cstrip { display: flex; flex-wrap: wrap; gap: 12px 28px; margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--line); }
.cstrip--tight { margin-top: 16px; }
.cstrip li { display: flex; flex-direction: column; gap: 3px; font-size: .9rem; }
.cstrip__k { font-size: .62rem; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.cstrip a { color: var(--ink); border-bottom: 1px solid var(--line); width: fit-content; overflow-wrap: anywhere; }
.cstrip a:hover { color: var(--bronze-text); border-color: var(--bronze-text); }

/* quick routes: six cards, three per row */
.routes { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 899.98px) { .routes { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 479.98px) { .routes { grid-template-columns: 1fr; } }

/* footer contact labels */
.ftr__k { display: block; font-size: .6rem; letter-spacing: .16em; text-transform: uppercase; color: #8C8478; margin-bottom: 2px; }

/* visit: weekend block */
.wkend { display: grid; grid-template-columns: 1.15fr 1fr; gap: clamp(28px, 5vw, 80px); align-items: center; }
.wkend__lead .lede { margin-top: 16px; }
.wkend__act { display: flex; flex-direction: column; gap: 14px; align-items: flex-start; }
@media (max-width: 1099.98px) { .wkend { grid-template-columns: 1fr; gap: 30px; } }

/* trade: wholesale trio */
.trio { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(18px, 2.6vw, 40px); }
.trio__i { padding: clamp(20px, 2.4vw, 30px); border: 1px solid var(--line); background: var(--pearl); }
.trio__k { font-size: .68rem; letter-spacing: .18em; text-transform: uppercase; color: var(--bronze-text); margin-bottom: 12px; }
.trio__i p { font-size: .95rem; line-height: 1.65; }
.trio__i .ticks { margin-top: 12px; }
.trio__i .ticks .tlink { font-size: .7rem; padding-bottom: 3px; }
@media (max-width: 899.98px) { .trio { grid-template-columns: 1fr; } }

/* page head positioning line */
.phead__eyebrow { margin-bottom: 14px; }

/* enquiry: the one-line note for ?topic=weekend-visit */
.form__topic { grid-column: 1 / -1; margin: -6px 0 0; padding: 12px 16px; border: 1px solid var(--line); border-left: 2px solid var(--bronze); background: var(--ivory); font-size: .9rem; line-height: 1.55; color: var(--ink); }
.form__topic[hidden] { display: none; }

/* c13 (CRO-1, 7 Oct 2026): five optional selects sit in one closed disclosure after Message (enquire.js). Same ids and names;
   its grid breaks to one column at the form's own 759.98px breakpoint. The chevron is drawn, so no icon file and no motion. */
.f-more { grid-column: 1 / -1; }
.f-more > summary { display: flex; align-items: center; justify-content: space-between; min-height: 44px; cursor: pointer; list-style: none; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); font-size: .69rem; letter-spacing: .16em; text-transform: uppercase; color: var(--bronze-text); }
.f-more > summary::-webkit-details-marker { display: none; }
.f-more > summary::after { content: ""; width: 7px; height: 7px; margin: -4px 4px 0 12px; border: solid currentColor; border-width: 0 1.5px 1.5px 0; transform: rotate(45deg); }
.f-more[open] > summary::after { margin-top: 4px; transform: rotate(-135deg); }
.f-more__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 22px; margin-top: 20px; }
@media (max-width: 759.98px) { .f-more__grid { grid-template-columns: 1fr; } }

/* ==========================================================================
   27. v5.4 — facts strip, fact list, two-line hours, footer social profiles
   ========================================================================== */

/* facts strip: West Palm Beach Showroom · U.S. Shipping Available · … */
.facts { display: flex; flex-wrap: wrap; align-items: center; row-gap: 8px; font-size: .68rem; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); line-height: 1.5; }
.facts__i { display: inline-flex; align-items: center; }
.facts__i + .facts__i::before { content: ''; flex: none; width: 4px; height: 4px; margin: 0 14px; border-radius: 50%; background: var(--bronze); }
/* review UX-01: the weekend link is underlined, so it is not told apart from
   the plain facts by colour alone (WCAG 1.4.1); hover/focus thicken it */
.facts a { color: var(--bronze-text); border-bottom: 1px solid currentColor; padding-bottom: 1px; }
.facts a:hover, .facts a:focus-visible { border-bottom-width: 2px; padding-bottom: 0; }
@media (max-width: 599.98px) {
  .facts { letter-spacing: .12em; }
  .facts__i + .facts__i::before { margin: 0 10px; }
}

/* fact list: the confirmed shipping, payment and access sentences */
.factlist { display: grid; gap: 10px; }
.factlist__i { position: relative; padding-left: 20px; font-size: .95rem; line-height: 1.6; color: var(--body); }
.factlist__i::before { content: ''; position: absolute; left: 0; top: .8em; width: 10px; height: 1px; background: var(--bronze); }

/* hours: "Monday–Friday: 8:00 AM–5:00 PM." then "Weekend visits available by appointment." */
.hours__d, .hours__w { display: block; }

/* footer: Instagram, Facebook, LinkedIn */
.ftr__h--social { margin-top: 26px; }
.ftr__col .ftr__social { display: flex; flex-wrap: wrap; gap: 6px 18px; }
.ftr__col .ftr__social li { margin-bottom: 0; }
