/* =============================================================================
   TEMPLATE — structure and components.
   Reusable across clients; everything colour/size/typeface-shaped lives in
   tokens.css, everything content-shaped lives in site.config.js.
   ========================================================================== */

/* ---------------------------------------------------------------- reset --- */
*, *::before, *::after { box-sizing: border-box; }
html {
  font-size: 62.5%;              /* 10px root: 1rem === 10px, like the reference */
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-body);
  font-weight: var(--fw-ui, 300);
  color: var(--t-text);
  background: var(--c-warm-white);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img, video, svg, picture { display: block; max-width: 100%; }
img, video { height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
ul, ol { list-style: none; margin: 0; padding: 0; }
h1, h2, h3, h4, h5, p, figure, blockquote { margin: 0; }
input, textarea, select { font: inherit; }
:focus-visible { outline: 2px solid var(--t-primary); outline-offset: 3px; border-radius: 3px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- Lenis. Required, not optional: without the scroll-behavior override the
   browser re-animates every per-frame scrollTo Lenis makes, and the wheel goes
   rubbery. Inlined rather than pulled from the CDN (stylesheets are one more
   request that can fail). ------------------------------------------------- */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }
.lenis.lenis-smooth iframe { pointer-events: none; }

/* --------------------------------------------------------------- layout --- */
.container-h {
  position: relative;
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--layout-padding);
}
.row {
  display: flex;
  flex-wrap: wrap;
  margin-inline: calc(var(--gutter) / -2);
}
.col { flex: 1; min-width: 0; padding-inline: calc(var(--gutter) / 2); }
.col--auto { flex: 0 0 auto; }
/* 12-column spans. col--N === N of 12. */
.col--1{flex:0 0 8.3333%;max-width:8.3333%}   .col--2{flex:0 0 16.6667%;max-width:16.6667%}
.col--3{flex:0 0 25%;max-width:25%}           .col--4{flex:0 0 33.3333%;max-width:33.3333%}
.col--5{flex:0 0 41.6667%;max-width:41.6667%} .col--6{flex:0 0 50%;max-width:50%}
.col--7{flex:0 0 58.3333%;max-width:58.3333%} .col--8{flex:0 0 66.6667%;max-width:66.6667%}
.col--9{flex:0 0 75%;max-width:75%}           .col--10{flex:0 0 83.3333%;max-width:83.3333%}
.col--12{flex:0 0 100%;max-width:100%}
.off--1{margin-left:8.3333%} .off--2{margin-left:16.6667%} .off--3{margin-left:25%}
.off--4{margin-left:33.3333%} .off--6{margin-left:50%} .off--7{margin-left:58.3333%}
.off--8{margin-left:66.6667%}

.section { position: relative; }
.section--clip { overflow: hidden; }
/* 100svh, not 100vh: on phones vh is the *large* viewport and hides the
   bottom of a full-height block behind the browser chrome. */
.section--screen { min-height: 100svh; }
.stack { position: relative; }
.stack__pin { position: sticky; top: 0; height: 100svh; overflow: hidden; }

/* ----------------------------------------------------------- typography --- */
.d1, .d2, .d3, .d4, .d5 { font-family: var(--font-display); font-weight: var(--fw-display, 300); color: var(--t-heading); }
.d1 { font-size: var(--fs-d1); line-height: var(--lh-d1); letter-spacing: var(--ls-d1); }
.d2 { font-size: var(--fs-d2); line-height: var(--lh-d2); letter-spacing: var(--ls-d2); }
.d3 { font-size: var(--fs-d3); line-height: var(--lh-d3); letter-spacing: var(--ls-d3); }
.d4 { font-size: var(--fs-d4); line-height: var(--lh-d4); letter-spacing: var(--ls-d4); }
.d5 { font-size: var(--fs-d5); line-height: var(--lh-d5); letter-spacing: var(--ls-d5); font-weight: var(--fw-display-alt, 400); }
.body-l { font-size: var(--fs-body); line-height: var(--lh-body); letter-spacing: var(--ls-body); }
.small  { font-size: var(--fs-small); line-height: var(--lh-small); letter-spacing: var(--ls-small); }
.micro  { font-size: var(--fs-micro); line-height: var(--lh-micro); letter-spacing: var(--ls-micro);
          text-transform: uppercase; }
.eyebrow { font-size: var(--fs-small); line-height: 1.4; letter-spacing: 0.01em; color: var(--t-secondary); }
.t-heading { color: var(--t-heading); }
.t-secondary { color: var(--t-secondary); }
.t-primary { color: var(--t-primary); }
.t-center { text-align: center; }
.serif { font-family: var(--font-display); font-weight: var(--fw-display, 300); }
/* Trims the half-leading so a display line sits flush to its box. */
.trim { display: block; }
.trim::before, .trim::after { content: ''; display: block; height: 0; }
.trim::before { margin-bottom: calc((1em - 1lh) * 0.42); }
.trim::after  { margin-top:    calc((1em - 1lh) * 0.42); }

/* -------------------------------------------------------------- buttons --- */
.btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  gap: 10px; min-height: 44px; padding: 0 24px; border-radius: 999px;
  font-size: var(--fs-small); letter-spacing: -0.02em; color: var(--t-heading);
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
  cursor: pointer;
}
.btn--outline { border: 1px solid color-mix(in srgb, currentColor 45%, transparent); }
.btn--outline:hover { border-color: currentColor; background: color-mix(in srgb, currentColor 8%, transparent); }
.btn--primary { background: var(--t-primary); color: var(--t-on-primary); padding: 0 34px; min-height: 56px; }
.btn--primary:hover { opacity: .86; }
.btn--round { width: 44px; min-height: 44px; padding: 0; border-radius: 50%; }
.btn--ellipse { width: 60px; min-height: 44px; padding: 0; border-radius: 999px; }
.btn--play {
  width: 84px; height: 84px; min-height: 84px; padding: 0; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.55); color: #fff; backdrop-filter: blur(2px);
}
.btn--play:hover { background: rgba(255,255,255,.14); }
@media (min-width: 768px) { .btn--play { width: 120px; height: 120px; min-height: 120px; } }
.link-underline { position: relative; display: inline-block; }
.link-underline::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: 100% 50%;
  transition: transform .5s var(--ease);
}
.link-underline:hover::after,
.link-underline.is-on::after { transform: scaleX(1); transform-origin: 0 50%; }

/* ------------------------------------------------------------ media box --- */
.media { position: relative; overflow: hidden; }
.media > img, .media > video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;
}
.media--fill { position: absolute; inset: 0; }
/* Overscan for parallax. Written in vh, NOT rem: the root is fixed at 10px so
   a rem-based overscan would not track the viewport (see README caveat). */
.media--over { top: -6vh; height: 112vh; }
.media--round { border-radius: var(--radius-lg); }
.media--oval { border-radius: 50%; }

/* --------------------------------------------------------------- header --- */
.header {
  position: absolute; top: 30px; left: 0; width: 100%; z-index: 40;
  transition: transform var(--dur-loader) var(--ease-inout);
}
.header--fixed { position: fixed; }
.header__bar {
  display: flex; align-items: center; justify-content: space-between;
  height: var(--header-h); border-radius: var(--radius-md);
  margin-inline: -40px; padding-inline: 40px;
  transition: background-color .6s var(--ease), color .6s var(--ease);
}
.header__logo { font-family: var(--font-display); font-size: 2.4rem; letter-spacing: -0.02em;
  color: var(--t-heading); line-height: 1; }
.header__actions { display: flex; align-items: center; gap: 35px; }
/* Menu mark. Measured from the reference: a 50x50 hit circle with 5px of
   padding, so the two rules are 40px wide, 7px apart. Each rule is a
   zero-height box with a 0.75px box-shadow spread — a 1.5px hairline that
   stays crisp at any DPR, which a 1px background does not. */
.header__burger {
  width: 50px; height: 50px; padding: 5px; margin-right: -5px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  border-radius: 50%; color: var(--t-heading);
  transition: color var(--dur-ui) var(--ease);
}
.header__burger span {
  display: block; width: 100%; height: 0;
  box-shadow: 0 0 0 .75px currentColor;
  transition: transform var(--dur-ui) var(--ease), opacity var(--dur-ui) var(--ease);
}
.header__burger span:first-child { margin-bottom: 7px; }
/* Sizes to its label rather than a fixed 80px, so a real CTA ("Get a Free
   Estimate") fits on one line instead of wrapping inside the pill. */
.header__buy { color: var(--t-heading); width: auto; min-height: 40px;
  padding: 0 20px; white-space: nowrap; }
@media (max-width: 767px) {
  .header__buy { min-height: 44px; padding: 0 12px;
    font-size: var(--fs-micro); letter-spacing: .01em; }
  .header__actions { gap: 10px; }
}
@media (max-width: 767px) {
  .header { top: 10px; }
  .header__bar { margin-inline: -14px; padding-inline: 14px; }
  .header__logo { font-size: 2.1rem; }
  .header__burger { width: 50px; height: 50px; padding: 10px; margin-right: -10px; }
}

/* Floating buy button that arrives once the hero is behind you. */
.buy-dock {
  position: fixed; right: var(--layout-padding); bottom: 40px; z-index: 35;
  opacity: 0; transform: translateY(20px) scale(.9); pointer-events: none;
  transition: opacity .6s var(--ease-op), transform .6s var(--ease);
}
.buy-dock.is-on { opacity: 1; transform: none; pointer-events: auto; }
.buy-dock .btn {
  width: 78px; height: 78px; min-height: 78px; padding: 0; border-radius: 50%;
  flex-direction: column; gap: 2px; background: var(--c-warm-brown); color: #fff;
  font-size: var(--fs-micro); box-shadow: 0 10px 40px rgba(55,56,76,.28);
}
@media (max-width: 767px) {
  .buy-dock { right: 16px; bottom: 16px; }
  .buy-dock .btn { width: 62px; height: 62px; min-height: 62px; }
}

/* ---------------------------------------------------------------- menu ---- */
.menu {
  position: fixed; inset: 0; z-index: 60; display: none;
  background: var(--t-menu-bg); color: var(--t-menu-text);
}
.menu.is-open { display: block; }
.menu__inner {
  height: 100%; display: flex; flex-direction: column; justify-content: center;
  padding-block: 120px 60px; overflow-y: auto; -webkit-overflow-scrolling: touch;
}
.menu__list li + li { margin-top: 6px; }
.menu__link {
  display: block; font-family: var(--font-display); font-weight: var(--fw-display, 300);
  font-size: clamp(3.2rem, 6vw, 5.4rem); line-height: 1.25; letter-spacing: -0.02em;
  color: var(--t-menu-text); padding-block: 4px;
  transition: opacity .4s var(--ease);
}
.menu.is-open .menu__list:hover .menu__link { opacity: .45; }
.menu.is-open .menu__list .menu__link:hover { opacity: 1; }
.menu__close {
  position: absolute; top: 30px; right: var(--layout-padding); width: 50px; height: 50px;
  display: grid; place-items: center; border-radius: 50%; color: var(--t-menu-text);
  border: 1px solid color-mix(in srgb, currentColor 40%, transparent);
}
.menu__foot { margin-top: 48px; display: flex; flex-wrap: wrap; gap: 24px;
  color: color-mix(in srgb, currentColor 70%, transparent); }
@media (max-width: 767px) { .menu__close { top: 10px; right: 16px; } }

/* ============================================================ REVEALS =====
   Class-driven, matching the reference's vocabulary. Elements start in the
   *--off state; the observer removes it. All transitions, no JS tweening.
   ========================================================================== */
[data-anim] { --li: 0; --lt: 1; }

/* word-split title / text */
.a-title, .a-text, .a-title-sm, .a-text-sm { display: block; }
.word { display: inline-block; vertical-align: top; overflow: hidden; }
.word-wrap { display: inline-block; }
.a-title .word-wrap  { transition: transform var(--dur-title) var(--ease), opacity var(--dur-title) var(--ease-op); transition-delay: calc(var(--li) * var(--stagger)); }
.a-text  .word-wrap  { transition: transform var(--dur-text)  var(--ease), opacity var(--dur-text)  var(--ease-op); transition-delay: calc(var(--li) * var(--stagger)); }
.a-title-sm .word-wrap { transition: transform var(--dur-title) var(--ease), opacity var(--dur-title) var(--ease-op); transition-delay: calc(var(--li) * var(--stagger)); }
.a-text-sm  .word-wrap { transition: transform var(--dur-text)  var(--ease), opacity var(--dur-text)  var(--ease-op); transition-delay: calc(var(--li) * var(--stagger)); }
.a-title--off .word-wrap, .a-text--off .word-wrap       { transform: translateY(10vh); opacity: 0; }
.a-title-sm--off .word-wrap, .a-text-sm--off .word-wrap { transform: translateY(5vh);  opacity: 0; }

/* block slide-in */
.a-slide     { transition: transform var(--dur-text) var(--ease), opacity var(--dur-text) var(--ease-op);
               transition-delay: var(--d, 0ms); }
.a-slide--off{ transform: translateY(10vh); opacity: 0; }
.a-slide-alt { transition: transform var(--dur-title) var(--ease), opacity var(--dur-title) var(--ease-op);
               transition-delay: var(--d, 0ms); }
.a-slide-alt--off { transform: translateY(10vh); opacity: 0; }

/* fade */
.a-fade      { transition: opacity var(--dur-block) var(--ease-op); transition-delay: var(--d, 0ms); }
.a-fade--off { opacity: 0; }

/* diagonal clip wipe on media + a slow scale settle */
.a-clip      { transition: clip-path var(--dur-block) var(--ease); }
.a-clip img, .a-clip video { transition: transform var(--dur-block) var(--ease); transform: scale(1); }
.a-clip--off { clip-path: polygon(0 52%, 100% calc(52% + 34vw), 100% calc(52% + 34vw), 0 52%); }
.a-clip--off img, .a-clip--off video { transform: scale(1.2); }

/* svg line draw */
.a-line { stroke-dasharray: var(--len, 1) var(--len, 1); stroke-dashoffset: 0;
          transition: stroke-dashoffset var(--dur-line) var(--ease-line); transition-delay: var(--d, 0ms); }
.a-line--off { stroke-dashoffset: var(--len, 1); }

/* hero entrance */
.a-hero-line { transition: transform var(--dur-intro) var(--ease-intro); }
.a-hero-line:nth-child(2) { transition-delay: 40ms; }
.a-hero-line:nth-child(3) { transition-delay: 80ms; }
.a-hero-line:nth-child(4) { transition-delay: 120ms; }
.a-hero--off .a-hero-line:nth-child(1) { transform: translateY(20vh); }
.a-hero--off .a-hero-line:nth-child(2) { transform: translateY(25vh); }
.a-hero--off .a-hero-line:nth-child(3) { transform: translateY(30vh); }
.a-hero--off .a-hero-line:nth-child(4) { transform: translateY(35vh); }
.a-rise      { transition: transform var(--dur-intro) var(--ease-intro); transition-delay: var(--d, 0ms); }
.a-rise--off { transform: translateY(45vh); }
.a-drop      { transition: transform var(--dur-loader) var(--ease-inout); }
.a-drop--off { transform: translateY(-150%); }
.a-push      { transition: transform var(--dur-loader) var(--ease-inout); }
.a-push--off { transform: translateY(-25%); }

/* ------------------------------------------------------------ preloader --- */
.preloader {
  position: fixed; inset: 0; z-index: 100; overflow: hidden;
  transition: transform var(--dur-loader) var(--ease-inout);
}
.preloader__panel {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: var(--c-cool-dark-blue); color: var(--c-warm-white);
  transition: transform var(--dur-loader) var(--ease-inout);
}
.preloader.is-out { transform: translateY(-100%); }
.preloader.is-out .preloader__panel { transform: translateY(100%); }
.preloader.is-gone { display: none; }
.preloader__mark { font-family: var(--font-display); font-size: clamp(3rem, 6vw, 5rem); letter-spacing: -0.03em; }
.preloader__bar { position: absolute; left: 0; bottom: 0; height: 2px; width: 100%;
  background: var(--c-warm-brown); transform: scaleX(var(--p, 0)); transform-origin: 0 50%;
  transition: transform .3s linear; }

/* =========================================================== SECTIONS ===== */

/* ---- 1. hero stack ------------------------------------------------------- */
.hero { position: relative; }
.hero__pin { position: sticky; top: 0; height: 100svh; overflow: hidden; }
.hero__bg { position: absolute; inset: 0; }
.hero__bg img { position: absolute; left: 0; top: -6vh; width: 100%; height: 112vh; object-fit: cover; }
.hero__scrim { position: absolute; inset: 0; background:
  linear-gradient(180deg, rgba(28,24,23,.42) 0%, rgba(28,24,23,.06) 34%, rgba(28,24,23,.40) 100%); }
.hero__inner { position: relative; height: 100%; display: flex; align-items: center; justify-content: center; }
.hero__title { text-align: center; color: #fff; max-width: 100%; }
.hero__title .a-hero-line { display: block; }
.hero__card {
  position: absolute; right: var(--layout-padding); bottom: var(--hero-card-bottom, 21%);
  width: 340px; aspect-ratio: 340 / 190;
  border-radius: var(--radius-md); overflow: hidden; background: #000; display: block;
}
/* Hero banner stack: eyebrow, display lines, locator, CTA. All four are
   optional — with none of them the hero is the master's centred title alone.
   Each reveals on its own delay and carries its own parallax, so the group
   drifts apart slightly as it leaves rather than moving as one flat block. */
.hero__stack { display: flex; flex-direction: column; align-items: center; width: 100%; }
.hero__eyebrow {
  display: flex; align-items: center; justify-content: center; gap: 16px;
  color: #fff; margin-bottom: 22px; text-transform: uppercase;
  letter-spacing: .14em; font-size: var(--fs-micro);
  /* The flex row centres the span as a box, but text inside it stays
     left-aligned — so a wrapped eyebrow ragged-lefts on phones. */
  text-align: center;
}
/* Rules that draw outward from the text rather than sitting there flat. */
.hero__eyebrow::before, .hero__eyebrow::after {
  content: ''; height: 1px; width: clamp(24px, 6vw, 64px);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.75));
  transform-origin: right center; animation: heroRule var(--dur-line) var(--ease-line) both .5s;
}
.hero__eyebrow::after { background: linear-gradient(90deg, rgba(255,255,255,.75), transparent);
  transform-origin: left center; }
@keyframes heroRule { from { scale: 0 1; opacity: 0; } to { scale: 1 1; opacity: 1; } }

.hero__sub {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  color: #fff; margin-top: 26px; font-size: var(--fs-body);
  line-height: var(--lh-body); opacity: .92;
}
.hero__sub svg { width: 20px; height: 20px; flex: none; opacity: .8; }
/* The icon only adds width on the left, which pushes the text off the centre
   the display lines above are centred on. A matching invisible spacer on the
   right makes the row symmetric, so the TEXT centres, not the row. */
.hero__sub::after { content: ''; width: 20px; flex: none; }

.hero__cta {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; gap: 14px;
  margin-top: 40px; padding: 0 32px; min-height: 56px;
  border-radius: 999px; color: #fff; background: var(--c-warm-brown);
  font-size: var(--fs-small); letter-spacing: .04em; text-transform: uppercase;
  box-shadow: 0 10px 30px -12px rgba(0,0,0,.55);
  transition: background-color var(--dur-ui) var(--ease),
              translate var(--dur-ui) var(--ease), box-shadow var(--dur-ui) var(--ease);
}
.hero__cta-rule { width: 26px; height: 1px; background: currentColor; opacity: .85;
  transition: width var(--dur-ui) var(--ease); flex: none; }
.hero__cta svg { width: 18px; height: 18px; flex: none;
  transition: translate var(--dur-ui) var(--ease); }
/* A slow sheen crossing the pill — the "not flat" part. */
.hero__cta::after {
  content: ''; position: absolute; inset: 0 auto 0 -60%; width: 45%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.28), transparent);
  translate: -120% 0; transition: translate 0s;
}
.hero__cta:hover { translate: 0 -2px; box-shadow: 0 16px 36px -12px rgba(0,0,0,.6); }
.hero__cta:hover .hero__cta-rule { width: 14px; }
.hero__cta:hover svg { translate: 5px 0; }
.hero__cta:hover::after { translate: 420% 0; transition: translate 1.1s var(--ease); }
@media (max-width: 767px) {
  .hero__cta { margin-top: 30px; padding: 0 24px; min-height: 52px; }
  .hero__sub { margin-top: 20px; }
  .hero__eyebrow { margin-bottom: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .hero__eyebrow::before, .hero__eyebrow::after { animation: none; }
  .hero__cta::after { display: none; }
}

.hero__cue { position: absolute; left: var(--layout-padding); bottom: 60px; color: #fff; }
@media (max-width: 767px) {
  .hero__card { right: auto; left: 50%; translate: -50% 0; bottom: 16%; width: 62vw; max-width: 260px; }
  .hero__cue { left: 50%; transform: translateX(-50%); bottom: 24px; }
}

/* ---- 2. intro / morphing panel ------------------------------------------- */
.morph__pin { position: sticky; top: 0; height: 100svh; overflow: hidden;
  display: grid; place-items: center; }
.morph__card {
  position: relative; width: 520px; height: 560px; border-radius: var(--radius-lg);
  background: var(--c-cool-light-gray); overflow: hidden; will-change: width, height, border-radius;
}
.morph__art { position: absolute; inset: 0; display: grid; place-items: center; }
.morph__art img { width: 62%; max-width: 620px; height: auto; }
.morph__body { position: absolute; inset: 0; }
.morph__head { position: absolute; top: 12vh; left: 0; width: 100%; }
.morph__meta { position: absolute; bottom: 12vh; left: 0; width: 100%; }
.morph__meta .row { align-items: flex-end; }
.morph__rule { height: 1px; background: var(--t-line); margin-bottom: 26px; }

/* Variant: the panel carries a full-bleed medium instead of a centred cut-out.
   Additive — nothing above changes. The morph-art scrub still drives scale, so
   the medium comes in at 1.55, settles to 1 as the panel reaches full bleed,
   and shrinks to 0.4 as it collapses. A <video> here is muted/looped and is
   started and stopped by the shared [data-autoplay] observer in app.js, which
   never plays under prefers-reduced-motion. */
.morph__art--fill { display: block; }
/* Must out-specify `.morph__art img` above, which sets width 62% / height auto
   for the centred cut-out case — a `> *` selector loses that tie. */
.morph__art.morph__art--fill img,
.morph__art.morph__art--fill video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  max-width: none; object-fit: cover; display: block;
}
/* Marks the panel as film, and toggles it. Sits above the medium but inside
   the card, so it is clipped and scaled with everything else. */
.morph__play {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%; z-index: 2;
  width: 64px; height: 64px; min-height: 0; padding: 0;
  display: grid; place-items: center; cursor: pointer;
  color: #fff; background: rgba(0, 0, 0, .28);
  border: 1px solid rgba(255, 255, 255, .6); border-radius: 50%;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  transition: background-color var(--dur-ui) var(--ease), scale var(--dur-ui) var(--ease);
}
.morph__play:hover { background: rgba(0, 0, 0, .45); scale: 1.06; }
.morph__play [hidden] { display: none; }
@media (max-width: 767px) { .morph__play { width: 54px; height: 54px; } }

@media (max-width: 767px) {
  .morph__card { width: min(78vw, 320px); height: min(58vh, 400px); }
  .morph__head { top: 13vh; }
  .morph__meta { bottom: 8vh; }
}

/* ---- 3. benefits split --------------------------------------------------- */
.benefits__pin { position: sticky; top: 0; height: 100svh; overflow: hidden; }
.benefits__grid { display: grid; grid-template-columns: 1fr 1fr; height: 100%; }
.benefits__side { position: relative; display: flex; flex-direction: column; justify-content: center;
  padding-inline: clamp(30px, 9vw, 140px); background: var(--c-warm-white); }
.benefits__icon { width: 44px; height: 44px; color: var(--t-secondary); margin-bottom: 40px; }
.benefits__slots { position: relative; }
.benefits__slot { position: absolute; inset: 0; opacity: 0; pointer-events: none;
  transition: opacity .7s var(--ease-op), transform .9s var(--ease); transform: translateY(6vh); }
.benefits__slot.is-on { opacity: 1; transform: none; position: relative; pointer-events: auto; }
.benefits__media { position: relative; overflow: hidden; }
.benefits__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity .9s var(--ease-op), transform 1.6s var(--ease); transform: scale(1.08); }
.benefits__media img.is-on { opacity: 1; transform: none; }
.benefits__counter {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%;
  width: 160px; height: 160px; border-radius: var(--radius-lg); background: var(--c-warm-white);
  display: grid; place-items: center; will-change: width, height, border-radius;
}
.benefits__counter-num { font-family: var(--font-display); font-size: 4.4rem; line-height: 1;
  color: var(--t-heading); }
.benefits__counter-den { font-size: var(--fs-micro); color: var(--t-secondary); }

/* mobile variant: a plain stacked list, no pin */
.benefits-list__item + .benefits-list__item { margin-top: 56px; }
.benefits-list__media { aspect-ratio: 4 / 5; border-radius: var(--radius-md); overflow: hidden;
  margin-top: 22px; }
.benefits-list__media img { width: 100%; height: 100%; object-fit: cover; }

/* ---- 4. with-you stacked cards ------------------------------------------- */
.withyou { position: relative; }
.withyou__pin { position: sticky; top: 0; height: 100svh; overflow: hidden; }
.withyou__art { position: absolute; left: 50%; top: 46%; translate: -50% -50%; width: 79%; opacity: .95; }
.withyou__head { position: relative; padding-top: 12vh; }
.withyou__foot { position: absolute; left: 0; bottom: 9vh; width: 100%; }
.withyou__cards { position: relative; pointer-events: none; }
.withyou__card-slot { position: sticky; top: 0; height: 100svh; display: flex;
  align-items: center; justify-content: flex-end; }
.withyou__card {
  position: relative; width: 694px; max-width: calc(100% - var(--layout-padding));
  height: 720px; max-height: 80svh; border-radius: var(--radius-lg);
  background: var(--c-warm-white); overflow: hidden; pointer-events: auto;
  will-change: transform;
}
.withyou__card-overlay { position: absolute; inset: 0; background: rgba(55,56,76,.3);
  border-radius: inherit; z-index: 2; pointer-events: none; }
.card-head { position: relative; display: flex; align-items: center; gap: 40px;
  padding: 35px 40px 0; }
.card-head::after { content: ''; position: absolute; left: 40px; right: 40px; bottom: -32px;
  height: 1px; background: var(--c-cool-light-gray); }
.card-head__icon { width: 40px; height: 40px; color: var(--t-secondary); flex: 0 0 auto; }
.card-body { padding: 70px 40px 40px; text-align: center; }
.card-body__media { width: 322px; max-width: 70%; aspect-ratio: 322 / 221; margin: 0 auto 34px;
  border-radius: 50%; overflow: hidden; }
.card-body__media img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 767px) {
  .withyou__card { width: 100%; height: auto; max-height: none; }
  .withyou__card-slot { position: relative; height: auto; display: block; }
  .withyou__card-slot + .withyou__card-slot { margin-top: 20px; }
  .card-head { padding: 22px 22px 0; gap: 20px; }
  .card-head::after { left: 22px; right: 22px; bottom: -18px; }
  .card-body { padding: 42px 22px 30px; }
}

/* ---- 5. marquee band ----------------------------------------------------- */
.band { position: relative; }
.band__pin { position: sticky; top: 0; height: 100svh; overflow: hidden; }
.band__bg { position: absolute; inset: 0; }
.band__bg img { position: absolute; left: 0; top: -20vh; width: 100%; height: 140vh; object-fit: cover; }
.band__marquee { position: absolute; top: 43%; left: 0; width: 100%; white-space: nowrap;
  will-change: transform; }
.band__marquee span { font-family: var(--font-display); font-weight: var(--fw-display, 300);
  font-size: var(--fs-d1); line-height: var(--lh-d1); letter-spacing: var(--ls-d1);
  color: #fff; padding-right: 0.28em; }
.band__card { position: absolute; right: var(--layout-padding); top: 43%; width: 250px;
  aspect-ratio: 250 / 316; border-radius: var(--radius-md); overflow: hidden; background: #000; }
.band__foot { position: absolute; left: 0; bottom: 6vh; width: 100%; }
.band__rule { height: 1px; background: rgba(255,255,255,.4); margin-bottom: 34px; }
@media (max-width: 767px) {
  .band__card { right: 50%; translate: 50% 0; top: auto; bottom: 22vh; width: 150px; }
  .band__foot { bottom: 4vh; }
}

/* ---- 6. panel card (beige stack) ----------------------------------------- */
.panel { position: relative; padding-inline: 20px; }
.panel__top { border-radius: var(--radius-lg) var(--radius-lg) 0 0; background: var(--c-warm-light-beige);
  padding: 14vh 0 10vh; }
.panel__bottom { border-radius: 0 0 var(--radius-lg) var(--radius-lg); background: var(--c-soft-light);
  padding: 10vh 0 14vh; position: relative; overflow: hidden; }
.panel__quote { max-width: 15em; }
/* inline media chips inside a display paragraph — a signature of the reference */
.chip { display: inline-block; width: 1.02em; height: 0.62em; border-radius: 999px;
  overflow: hidden; vertical-align: baseline; translate: 0 0.03em; margin-inline: .06em .02em; }
.chip img { width: 100%; height: 100%; object-fit: cover; }
.panel__card { position: relative; margin-inline: 20px; margin-top: -8vh; }
.panel__card-inner { background: var(--c-warm-white); border-radius: var(--radius-lg);
  padding: clamp(28px, 4vw, 56px); display: grid; gap: 30px;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); align-items: center; }
.panel__card-art { border-radius: var(--radius-md); overflow: hidden; aspect-ratio: 16 / 10;
  background: var(--c-cool-light-gray); display: grid; place-items: center; }
.panel__card-art img { width: 76%; }
@media (max-width: 767px) {
  .panel { padding-inline: 12px; }
  .panel__card { margin-inline: 0; }
  .panel__card-inner { grid-template-columns: 1fr; gap: 24px; }
}

/* ---- 7. horizontal card track -------------------------------------------- */
.track { position: relative; }
.track__pin { position: sticky; top: 0; height: 100svh; overflow: hidden; }
.track__bg { position: absolute; inset: 0; }
.track__bg img { position: absolute; left: 0; top: -12vh; width: 100%; height: 124vh; object-fit: cover; }
.track__title { position: absolute; left: 0; top: 12vh; width: 100%; color: #fff; }
.track__rail { position: absolute; left: 0; top: 50%; translate: 0 -50%;
  display: flex; gap: 20px; padding-left: var(--layout-padding); will-change: transform; }
.track__card { flex: 0 0 340px; background: var(--c-warm-white); border-radius: var(--radius-lg);
  padding: 28px; height: 440px; display: flex; flex-direction: column; }
.track__card-art { flex: 1; border-radius: var(--radius-md); overflow: hidden;
  background: var(--c-cool-light-gray); margin-bottom: 22px; }
.track__card-art img { width: 100%; height: 100%; object-fit: cover; }
.track__num { font-family: var(--font-display); font-size: 2rem; color: var(--t-secondary); }
@media (max-width: 767px) {
  /* No pin on touch: the rail becomes a real swipeable row. */
  .track__pin { position: relative; height: auto; padding-block: 12vh 8vh; }
  .track__title { position: relative; top: 0; margin-bottom: 32px; }
  .track__rail { position: relative; top: 0; translate: none; overflow-x: auto;
    scroll-snap-type: x mandatory; padding-right: var(--layout-padding); padding-bottom: 8px;
    -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .track__rail::-webkit-scrollbar { display: none; }
  .track__card { flex-basis: 74vw; max-width: 300px; height: 380px; scroll-snap-align: start; }
  .track__bg img { top: 0; height: 100%; }
}

/* ---- 8. split-title section ---------------------------------------------- */
.split { position: relative; }
.split__pin { position: sticky; top: 0; height: 100svh; overflow: hidden;
  display: flex; flex-direction: column; justify-content: center; }
.split__title { position: relative; z-index: 2; text-align: center; pointer-events: none; }
.split__title span { display: block; will-change: transform; }
.split__art { position: absolute; left: 50%; top: 52%; translate: -50% -50%; width: 34%;
  max-width: 520px; z-index: 1; }
.split__meta { position: relative; z-index: 2; margin-top: 8vh; }
@media (max-width: 767px) {
  .split__art { width: 66%; top: 56%; }
  .split__meta { margin-top: 4vh; }
}

/* ---- 9. video block ------------------------------------------------------ */
.videoblock { position: relative; height: 100svh; overflow: hidden; }
.videoblock__bg { position: absolute; inset: 0; }
.videoblock__bg img, .videoblock__bg video { position: absolute; left: 0; top: -8vh;
  width: 100%; height: 116vh; object-fit: cover; }
.videoblock__scrim { position: absolute; inset: 0; background: rgba(30,26,25,.28); }
.videoblock__cta { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 28px; color: #fff; text-align: center; }

/* ---- 10. spec / hotspots ------------------------------------------------- */
.spec { position: relative; }
.spec__pin { position: sticky; top: 0; height: 100svh; overflow: hidden; }
.spec__head { position: absolute; left: 0; top: 12vh; width: 100%; }
.spec__stage { position: absolute; left: 50%; top: 56%; translate: -50% -50%;
  width: min(78vw, 900px); aspect-ratio: 1000 / 760; }
.spec__stage img { width: 100%; height: 100%; object-fit: contain; }
.hotspot { position: absolute; translate: -50% -50%; }
.hotspot__dot { width: 22px; height: 22px; border-radius: 50%; background: var(--c-warm-white);
  box-shadow: 0 2px 14px rgba(55,56,76,.28); display: grid; place-items: center; cursor: pointer; }
.hotspot__dot::after { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--c-cool-dark-blue); }
.hotspot__dot::before { content: ''; position: absolute; inset: -8px; border-radius: 50%;
  border: 1px solid var(--c-warm-white); opacity: .5; transform: scale(.6);
  transition: transform .5s var(--ease), opacity .5s var(--ease); }
.hotspot.is-open .hotspot__dot::before { transform: scale(1); opacity: 1; }
.hotspot__card {
  position: absolute; left: 28px; top: -16px; width: 260px; background: var(--c-warm-white);
  border-radius: var(--radius-md); padding: 22px 24px; opacity: 0; transform: translateY(10px) scale(.97);
  transition: opacity .5s var(--ease-op), transform .5s var(--ease); pointer-events: none;
  box-shadow: 0 18px 50px rgba(55,56,76,.14);
}
.hotspot.is-open .hotspot__card { opacity: 1; transform: none; pointer-events: auto; }
.hotspot--flip .hotspot__card { left: auto; right: 28px; }
@media (max-width: 767px) {
  /* Hover-gated content must not be hover-gated on touch: the spec list is
     rendered inline underneath instead, and the dots stay decorative. */
  .spec__pin { position: relative; height: auto; padding-block: 12vh 6vh; }
  .spec__head { position: relative; top: 0; }
  .spec__stage { position: relative; left: 0; translate: none; width: 100%; margin: 30px auto 0; }
  .hotspot { display: none; }
}
.spec__list { display: grid; gap: 12px; margin-top: 34px; }
.spec__list li { background: color-mix(in srgb, var(--c-warm-white) 70%, transparent);
  border-radius: var(--radius-md); padding: 18px 20px; }
@media (min-width: 768px) { .spec__list { display: none; } }

/* ---- 11. expanding use panels -------------------------------------------- */
.uses__panel { position: sticky; border-radius: var(--radius-lg); overflow: hidden; }
.uses__panel-inner { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: 40px;
  align-items: center; padding: 60px 0; }
.uses__panel-art { width: 200px; height: 200px; border-radius: 50%; overflow: hidden; }
.uses__panel-art img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 767px) {
  .uses__panel { position: relative; }
  .uses__panel-inner { grid-template-columns: 1fr; gap: 20px; padding: 34px 0; }
  .uses__panel-art { width: 130px; height: 130px; }
}

/* ---- 12. how-to-buy ------------------------------------------------------ */
.htb { position: relative; }
.htb__bg { position: sticky; top: 0; height: 100svh; overflow: hidden; margin-bottom: -100svh; }
.htb__bg img { position: absolute; left: 0; top: -8vh; width: 100%; height: 116vh; object-fit: cover; }
.htb__title { position: absolute; left: 0; bottom: 14vh; width: 100%; color: #fff; z-index: 2; }
.htb__list { position: relative; z-index: 3; padding-block: 12vh; }
.htb__list li + li { margin-top: 20px; }
.htb__card { background: var(--c-cool-light-gray); border-radius: var(--radius-lg);
  padding: 34px; height: 360px; display: flex; flex-direction: column; justify-content: space-between; }
@media (max-width: 767px) {
  .htb__bg { height: 62svh; margin-bottom: 0; position: relative; }
  .htb__title { bottom: 6vh; }
  .htb__list { padding-block: 8vh; }
  .htb__card { height: auto; padding: 24px; gap: 26px; }
}

/* ---- 13. product cards --------------------------------------------------- */
.picker__cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px;
  margin-top: 180px; }
.picker__card { position: relative; background: var(--c-cool-light-gray);
  border-radius: var(--radius-lg); padding: 40px; min-height: 640px;
  display: flex; flex-direction: column; }
.picker__card-art { position: absolute; left: 50%; top: -160px; translate: -50% 0;
  width: 320px; }
.picker__card-top { margin-top: 190px; }
.picker__features { margin-top: auto; padding-top: 26px; }
.picker__features li { display: flex; gap: 14px; padding-block: 7px;
  border-top: 1px solid color-mix(in srgb, var(--t-line) 70%, transparent); }
.picker__features li span:first-child { flex: 0 0 42%; color: var(--t-secondary); }
.picker__bottom { display: flex; align-items: center; gap: 18px; margin-top: 26px; }
.picker__badge { font-size: var(--fs-micro); letter-spacing: .08em; text-transform: uppercase;
  color: var(--t-secondary); }
@media (max-width: 991px) {
  .picker__cards { grid-template-columns: 1fr; gap: 150px; margin-top: 150px; }
  .picker__card { min-height: 0; padding: 26px; }
  .picker__card-art { width: 220px; top: -120px; }
  .picker__card-top { margin-top: 120px; }
}

/* ---- 14. reviews arc ----------------------------------------------------- */
.reviews { position: relative; overflow: hidden; }
.reviews__stage { position: relative; height: 490px; margin-top: 60px; }
.reviews__arc { position: absolute; left: 50%; top: 0; translate: -50% 0; width: 1400px; height: 900px;
  pointer-events: none; opacity: .5; }
.reviews__slide { position: absolute; left: 0; top: 0; width: 100%; opacity: 0; pointer-events: none;
  transition: opacity .6s var(--ease-op); display: grid; grid-template-columns: 200px minmax(0, 1fr);
  gap: 60px; align-items: center; }
.reviews__slide.is-on { opacity: 1; pointer-events: auto; }
.reviews__photo { width: 200px; aspect-ratio: 3 / 4; border-radius: var(--radius-sm); overflow: hidden;
  rotate: -4deg; }
.reviews__photo img { width: 100%; height: 100%; object-fit: cover; }
.reviews__nav { display: flex; gap: 12px; margin-top: 34px; }
.reviews__nav .btn { width: 44px; height: 44px; min-height: 44px; padding: 0; border-radius: 50%;
  border: 1px solid color-mix(in srgb, currentColor 40%, transparent); }
@media (max-width: 767px) {
  .reviews__stage { height: auto; }
  .reviews__slide { position: absolute; grid-template-columns: 1fr; gap: 24px; }
  .reviews__slide.is-on { position: relative; }
  .reviews__photo { width: 150px; }
}

/* ---- 15. kit bento ------------------------------------------------------- */
.kit { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; }
.kit__hero { background: var(--c-soft-light); border-radius: var(--radius-md); padding: 40px;
  display: flex; flex-direction: column; justify-content: space-between; min-height: 580px; }
.kit__hero img { width: 88%; margin: auto auto 0; }
.kit__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px;
  align-content: start; }
.kit__card { background: var(--c-warm-white); border-radius: var(--radius-md); padding: 24px;
  min-height: 180px; display: flex; flex-direction: column; justify-content: space-between; }
.kit__card--wide { grid-column: 1 / -1; }
.kit__icon { width: 34px; height: 34px; color: var(--t-secondary); }
@media (max-width: 767px) {
  .kit { grid-template-columns: 1fr; }
  .kit__hero { min-height: 320px; padding: 24px; }
  .kit__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kit__card { min-height: 140px; padding: 18px; }
}

/* ---- 16. partner --------------------------------------------------------- */
.partner { position: relative; }
.partner__bg { position: absolute; inset: 0; overflow: hidden; }
.partner__bg img { position: absolute; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover; }
.partner__title { position: relative; padding-top: 14vh; color: #fff; }
.partner__panel { position: relative; margin-top: 46vh; display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 20px; }
.partner__copy { background: var(--c-warm-white); border-radius: var(--radius-lg);
  padding: clamp(28px, 3vw, 50px); }
.partner__form { background: var(--c-cool-dark-blue); border-radius: var(--radius-lg);
  padding: clamp(28px, 3vw, 50px); }
.field { display: block; margin-bottom: 22px; }
.field input, .field textarea {
  width: 100%; background: none; border: 0; border-bottom: 1px solid rgba(255,255,255,.28);
  color: #fff; padding: 10px 0; font-size: 1.6rem; /* never below 16px: iOS zooms on focus */
}
.field input::placeholder { color: rgba(255,255,255,.5); }
.field input:focus { outline: none; border-bottom-color: #fff; }
@media (max-width: 767px) {
  .partner__panel { grid-template-columns: 1fr; margin-top: 30vh; }
  .partner__title { padding-top: 10vh; }
}

/* ---- 17. footer ---------------------------------------------------------- */
.footer { padding-block: 40px; background: var(--c-warm-white); }
.footer__top { display: flex; align-items: center; justify-content: space-between; gap: 24px;
  flex-wrap: wrap; }
.footer__bottom { display: flex; align-items: center; justify-content: space-between; gap: 20px;
  flex-wrap: wrap; margin-top: 160px; color: var(--t-secondary); }
.footer__links { display: flex; gap: 28px; flex-wrap: wrap; }

/* Optional locator band: where we are on the left, a map on the right.
   Omitted entirely when `footer.location` is absent, so the master is
   unaffected. */
.footer__mid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  gap: 40px; align-items: end;
  margin-top: 56px; padding-top: 56px; border-top: 1px solid var(--t-line);
}
.footer__place-label { margin-bottom: 14px; }
.footer__address {
  display: block; font-family: var(--font-display);
  font-weight: var(--fw-display-alt, 400);
  font-size: var(--fs-d4); line-height: var(--lh-d4); letter-spacing: var(--ls-d4);
  color: var(--t-heading);
}
.footer__address span {
  display: block; width: fit-content;
  border-bottom: 1px solid color-mix(in srgb, currentColor 35%, transparent);
  transition: border-color var(--dur-ui) var(--ease);
}
.footer__address:hover span { border-bottom-color: currentColor; }
.footer__map {
  aspect-ratio: 16 / 9; border-radius: var(--radius-md); overflow: hidden;
  background: var(--c-cool-light-gray);
}
.footer__map iframe { width: 100%; height: 100%; border: 0; display: block;
  filter: grayscale(1) contrast(.95); }

@media (max-width: 900px) {
  .footer__mid { grid-template-columns: 1fr; gap: 28px; align-items: start; }
}
@media (max-width: 767px) {
  .footer__bottom { margin-top: 60px; }
  .footer__top { flex-direction: column; align-items: flex-start; gap: 20px; }
  .footer__mid { margin-top: 40px; padding-top: 40px; }
}

/* ---- FAQ accordion ------------------------------------------------------- */
.faq__grid { display: grid; grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(40px, 6vw, 110px); align-items: start; }
.faq__intro { position: sticky; top: calc(var(--header-h) + 40px); }
.faq__title-alt { display: block; color: var(--t-secondary); }
.faq__cta { margin-top: 40px; }

.faq__item { border-top: 1px solid var(--t-line); }
.faq__item:last-child { border-bottom: 1px solid var(--t-line); }
.faq__q {
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  padding-block: 26px; cursor: pointer; list-style: none;
  color: var(--t-heading);
  transition: color var(--dur-fast) var(--ease);
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q:hover { color: var(--t-secondary); }
/* The +/− mark, drawn rather than typed so it stays crisp and rotates. */
.faq__mark { position: relative; flex: none; width: 34px; height: 34px;
  border-radius: 50%; border: 1px solid color-mix(in srgb, currentColor 35%, transparent); }
.faq__mark::before, .faq__mark::after {
  content: ''; position: absolute; left: 50%; top: 50%; translate: -50% -50%;
  background: currentColor;
}
.faq__mark::before { width: 12px; height: 1.5px; }
.faq__mark::after  { width: 1.5px; height: 12px;
  transition: scale var(--dur-ui) var(--ease), opacity var(--dur-ui) var(--ease); }
.faq__item[open] .faq__mark::after { scale: 1 0; opacity: 0; }

.faq__a { overflow: hidden; padding-bottom: 26px; max-width: 58ch; color: var(--t-text); }
.faq__item[open] .faq__a { animation: faqOpen var(--dur-text) var(--ease) both; }
@keyframes faqOpen {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

@media (max-width: 900px) {
  .faq__grid { grid-template-columns: 1fr; gap: 36px; }
  .faq__intro { position: static; }
  .faq__cta { margin-top: 28px; }
}
@media (max-width: 767px) {
  .faq__q { padding-block: 20px; gap: 16px; }
  .faq__mark { width: 30px; height: 30px; }
}
@media (prefers-reduced-motion: reduce) {
  .faq__item[open] .faq__a { animation: none; }
}

/* ---- decorative arcs ----------------------------------------------------- */
.arcs { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.arcs svg { position: absolute; left: 50%; top: 50%; translate: -50% -50%;
  width: 205%; height: 286%; opacity: .3; }
.arcs path { fill: none; stroke: currentColor; stroke-width: 1; }

/* ---- rhythm helpers ------------------------------------------------------ */
.pt-s{padding-top:60px}   .pt-m{padding-top:110px}  .pt-l{padding-top:150px}
.pb-s{padding-bottom:60px}.pb-m{padding-bottom:110px}.pb-l{padding-bottom:150px}
.mt-s{margin-top:24px}.mt-m{margin-top:40px}.mt-l{margin-top:70px}
.maxw-s{max-width:38ch}.maxw-m{max-width:52ch}
@media (max-width: 767px) {
  .pt-s{padding-top:40px}.pt-m{padding-top:64px}.pt-l{padding-top:80px}
  .pb-s{padding-bottom:40px}.pb-m{padding-bottom:64px}.pb-l{padding-bottom:80px}
  .mt-l{margin-top:44px}
  .row--stack-sm { display: block; }
  .row--stack-sm > .col { max-width: 100%; flex-basis: auto; margin-left: 0; }
  .row--stack-sm > .col + .col { margin-top: 26px; }
}

/* ================================================= NO-JS AND MOTION ======== */
/* No-JS: nothing may stay hidden if the scripts never arrive. */
.no-js [class*="--off"], .no-js [data-anim] { opacity: 1 !important; transform: none !important;
  clip-path: none !important; }
.no-js .preloader { display: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; transition-delay: 0ms !important;
  }
  .preloader { display: none !important; }
  [class*="--off"] { opacity: 1 !important; transform: none !important; clip-path: none !important; }
  .a-clip--off img { transform: none !important; }
  /* Scrubbed values are pinned to their end state by the engine. */
}


/* ---- breakpoint visibility ----------------------------------------------- */
.is-mobile { display: none; }
@media (max-width: 767px) {
  .is-desktop { display: none !important; }
  .is-mobile  { display: block; }
}

/* ============================================== SECTION REFINEMENTS ========
   Everything from here down deliberately overrides the base rules above, and
   is grouped by concern rather than by selector. Read the file in order:
     reset → layout → typography → components → sections → these refinements
     → mobile → short landscape → reduced-motion layout.
   A selector that appears twice is not a mistake; the later one wins.
   ========================================================================== */

/* Inline SVG icons: without this an SVG with only a viewBox falls back to
   300x150 and max-width:100% squashes it into a giant rectangle. */
.benefits__icon svg, .card-head__icon svg, .kit__icon svg,
.btn svg, .hotspot svg { width: 100%; height: 100%; display: block; }
.btn svg { width: 18px; height: 18px; }
.btn--play svg { width: 26px; height: 26px; }

/* ---- the hero → intro → benefits handoff is one continuous sticky stack.
   Each layer starts a viewport early so the panel that grows to full bleed
   always has the next layer already painted behind it.                     */
.morph { margin-top: -100svh; z-index: 3; background: none; }
.morph__card { background: var(--t-background); }
.benefits { margin-top: -160svh; z-index: 1; }
.morph__pin, .benefits__pin { z-index: inherit; }
@media (max-width: 767px) {
  .morph { margin-top: -100svh; }
  .benefits-alt { position: relative; z-index: 2; }
}

/* ---- withyou: the product is a prop, not the subject --------------------- */
.withyou__art { width: 46%; max-width: 620px; top: 44%; }
.withyou__head { padding-top: 13vh; }
.withyou__card { height: 72svh; max-height: 720px; }
.card-body { padding: 64px 40px 34px; }
.card-body__media { width: 46%; max-width: 322px; aspect-ratio: 322/221; margin-bottom: 30px; }
.card-body p { max-width: 34ch; margin-inline: auto; }
@media (max-width: 767px) {
  .withyou__art { width: 72%; top: 46%; }
  .withyou__card { height: auto; max-height: none; }
  .card-body__media { width: 62%; }
}

/* ---- benefits: give the slot stack a floor so it cannot collapse --------- */
.benefits__slots { min-height: 46vh; }
.benefits__side { padding-right: clamp(30px, 5vw, 80px); }
.benefits__slot .maxw-s { max-width: 34ch; }

/* ---- legibility scrims over full-bleed media ---------------------------- */
.track__bg::after, .htb__bg::after, .partner__bg::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(28,24,23,.42) 0%, rgba(28,24,23,.10) 45%, rgba(28,24,23,.46) 100%);
}
.videoblock__scrim { background: rgba(28,24,23,.42); }
.band__bg::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(28,24,23,.30) 0%, rgba(28,24,23,.06) 40%, rgba(28,24,23,.40) 100%);
}
.track__rail { top: 56%; }

/* ---- panel: clear the fixed header -------------------------------------- */
.panel__top { padding-top: 18vh; }
@media (max-width: 767px) { .panel__top { padding-top: 14vh; } }

/* ---- picker art must not depend on a reveal that may never fire ---------- */


/* ---- icon spans must be block boxes, or width/height do not apply and the
   inline SVG falls back to its 300x150 default ---------------------------- */
.benefits__icon, .card-head__icon, .kit__icon { display: block; flex: 0 0 auto; }
.benefits__icon { width: 44px; height: 44px; }

/* ---- benefits side: icon top, title centred, note at the foot ------------ */
.benefits__side { justify-content: space-between; text-align: center;
  padding-block: 14vh 12vh; align-items: center; }
.benefits__icon { margin-bottom: 0; }
.benefits__slots { position: relative; width: 100%; min-height: 34vh;
  display: flex; align-items: center; justify-content: center; }
.benefits__slot { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; }
.benefits__slot.is-on { position: absolute; }
.benefits__slot .maxw-s { max-width: 30ch; margin-inline: auto; }
.benefits__foot { min-height: 1px; }
.benefits__counter { box-shadow: 0 14px 44px rgba(55,56,76,.14); }

/* ---- the morph card carries the product from the first frame ------------- */
.morph__art img { opacity: 1; }

/* ---- header must not swallow hit-tests (its own controls still do) ------- */
.header { pointer-events: none; }
.header__bar > *, .header a, .header button { pointer-events: auto; }

/* ---- benefits column: icon top, title upper-middle, note at the foot ----- */
.benefits__side { display: block; position: relative; padding-block: 12vh; }
.benefits__side > .benefits__icon { margin: 0 auto; }
.benefits__slots { position: absolute; left: clamp(30px, 5vw, 80px);
  right: clamp(30px, 5vw, 80px); top: 22vh; bottom: 8vh; min-height: 0; }
.benefits__slot { justify-content: space-between; }
.benefits__slot .maxw-s { max-width: 32ch; }
.benefits { margin-top: -140svh; }

/* =========================================================== MOBILE ======= */
@media (max-width: 767px) {
  /* Never below 14px, and tap targets get real height. */
  :root { --fs-micro: 1.4rem; --ls-micro: 0.06em; }
  .header__logo { min-height: 44px; display: inline-flex; align-items: center; }
  .footer .link-underline, .menu__foot .link-underline { min-height: 44px;
    display: inline-flex; align-items: center; }
  .footer__links { gap: 10px 24px; }

  /* Sections carry an inline height sized for the desktop pin. On touch a pin
     longer than about one viewport reads as a frozen page, so they are cut
     back — and the two sections that stop pinning altogether go to auto. */
  .hero   { height: 150svh !important; }
  .morph  { height: 200svh !important; }
  .band   { height: 190svh !important; }
  .split  { height: 165svh !important; }
  .track  { height: auto !important; }
  .spec   { height: auto !important; }

  /* withyou stops pinning: the title becomes a normal block above the cards. */
  .withyou__pin { position: relative; height: auto; padding-block: 14vh 8vh; overflow: visible; }
  .withyou__art { position: relative; left: 0; top: 0; translate: none;
    width: 74%; margin: 24px auto 8px; }
  .withyou__head { position: relative; padding-top: 0; }
  .withyou__foot { position: relative; bottom: auto; margin-top: 28px; }
  .withyou__cards { padding-bottom: 8vh; }

  /* the marquee band is shorter, so the type is sized to the phone */
  .band__marquee { top: 38%; }
  .band__marquee span { font-size: clamp(5.2rem, 17vw, 8.4rem); }
  .band__foot { position: relative; bottom: auto; padding-top: 62svh; }
  .band__pin { display: flex; flex-direction: column; justify-content: flex-end; }

  /* split: the two cards stack, the art sits behind the second line */
  .split__pin { height: auto; position: relative; padding-block: 14vh 8vh; }
  .split__title { position: relative; }
  .split__art { position: absolute; top: 30%; }
  .split__meta { margin-top: 34vh; }

  /* video block reads at a phone size */
  .videoblock__cta { padding-inline: var(--layout-padding); }
}

/* ---- reduced motion: the off-states hide CHILDREN too, so those have to be
   reset as well or the page renders with invisible text ------------------- */
@media (prefers-reduced-motion: reduce) {
  [class*="--off"] .word-wrap,
  [class*="--off"] .a-hero-line,
  [class*="--off"] img,
  .a-hero--off .a-hero-line {
    opacity: 1 !important; transform: none !important; clip-path: none !important;
  }
}
/* Same guarantee if the scripts never run. */
.no-js .word-wrap, .no-js .a-hero-line { opacity: 1 !important; transform: none !important; }

/* ---- mobile refinements -------------------------------------------------- */
@media (max-width: 767px) {
  /* the marquee band: type sized to the phone, foot on a legible ground */
  .band__pin { justify-content: space-between; padding-block: 16vh 0; }
  .band__marquee { position: relative; top: 0; }
  .band__foot { padding-top: 0; padding-bottom: 8vh; }
  .band__foot .row { row-gap: 18px; }
  .band__rule { margin-bottom: 22px; }

  /* the split title travels less: half a viewport is a long way on a phone */
  .split__title span { will-change: transform; }

  /* the card rail gets a visible affordance that it scrolls */
  .track__rail::after { content: ''; flex: 0 0 var(--layout-padding); }
  .track__hint { display: block; }

  /* benefits list: tighter rhythm, image first at a phone-friendly ratio */
  .benefits-list__item + .benefits-list__item { margin-top: 64px; }
  .benefits-list__media { aspect-ratio: 5 / 6; }
}
.track__hint { display: none; font-size: var(--fs-micro); color: inherit; opacity: .7;
  margin-top: 14px; }

/* Body text keeps the theme colour; headings and helpers opt back out. */
.d1, .d2, .d3, .d4, .d5, .t-heading { color: var(--t-heading); }
.t-secondary, .eyebrow, .picker__badge, .track__num { color: var(--t-secondary); }
@media (max-width: 767px) { .track__hint { display: block !important; } }
.videoblock__cta h2 { font-size: var(--fs-d4); line-height: var(--lh-d4);
  letter-spacing: var(--ls-d4); font-weight: var(--fw-display, 300); max-width: 14em; }

/* A white card on a dark section needs its own theme, or it inherits the dark
   section's text colour and renders white-on-white. */
.withyou__card, .track__card, .htb__card, .hotspot__card, .panel__card-inner,
.kit__card, .kit__hero, .partner__copy { background: var(--t-background); }
.withyou__card.ui-light { background: var(--c-warm-white); }

/* Hotspot dots keep a 44px hit area without growing the visible dot. */
.hotspot__dot { position: relative; }
.hotspot__dot::after { position: relative; z-index: 1; }
.hotspot__dot { padding: 11px; margin: -11px; width: 44px; height: 44px;
  background: none; box-shadow: none; }
.hotspot__dot > .sr-only { position: absolute; }
.hotspot__dot::before { inset: 11px; border: 0; background: var(--c-warm-white);
  box-shadow: 0 2px 14px rgba(55,56,76,.28); transform: none; opacity: 1;
  border-radius: 50%; }
.hotspot.is-open .hotspot__dot::before { transform: scale(1.25); }

/* Tap-target floors that apply at every width, not only on phones. */
.field input, .field textarea { min-height: 48px; }
.header__logo { min-height: 44px; display: inline-flex; align-items: center; }
.link-underline { padding-block: 10px; }
.footer__links a, .menu__foot a { min-height: 44px; display: inline-flex; align-items: center; }
.footer__links a, .menu__foot a { min-width: 44px; }

/* ---- short viewports (a phone held sideways) ----------------------------- */
/* Width-based breakpoints call an 844x390 phone a tablet; height puts the
   display scale back where it belongs and keeps the pins short.            */
@media (max-height: 560px) and (orientation: landscape) {
  :root {
    --fs-d1: clamp(4.2rem, 15vh, 7.2rem);  --lh-d1: 0.92;
    --fs-d2: clamp(3.6rem, 13vh, 6rem);    --lh-d2: 0.98;
    --fs-d3: clamp(2.8rem,  9vh, 4rem);    --lh-d3: 1.1;
    --fs-d4: 2.4rem; --lh-d4: 1.2;
    --fs-d5: 2rem;
    --fs-body: 1.6rem; --lh-body: 1.45;
    --fs-micro: 1.4rem;
    --layout-padding: clamp(24px, 6vw, 60px);
  }
  .hero__card { width: 210px; bottom: 14%; }
  .hero__cue { bottom: 18px; }
  .withyou__card { height: 84svh; }
  .card-body { padding: 30px 26px 22px; }
  .card-body__media { width: 30%; margin-bottom: 16px; }
  .card-head { padding: 18px 26px 0; }
  .card-head::after { left: 26px; right: 26px; bottom: -14px; }
  .morph__head { top: 16vh; }
  .morph__meta { bottom: 8vh; }
  .track__card { height: 74svh; flex-basis: 300px; }
  .picker__card { min-height: 0; }
  .benefits__slots { top: 26vh; bottom: 6vh; }
}
@media (max-height: 560px) and (orientation: landscape) {
  .morph__head { top: 24vh; }
  .benefits__side { padding-block: 22vh 8vh; }
  .benefits__slots { top: 30vh; bottom: 6vh; }
  .benefits__counter { width: 110px; height: 110px; }
  .benefits__counter-num { font-size: 3.2rem; }
  .spec__head { top: 20vh; }
  .track__title { top: 16vh; }
  .band__foot { bottom: 4vh; }
}

/* =============================================== REDUCED MOTION LAYOUT ====
   The scrub engine does not run under reduce, so anything whose resting look
   depended on a scrubbed value has to be laid out statically here. The page
   becomes a plain linear document: no pins, no morph, no marquee travel.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .hero, .morph, .benefits, .band, .track, .split, .spec { height: auto !important; }
  .morph, .benefits { margin-top: 0 !important; }

  .hero__pin { position: relative; height: 100svh; }
  .hero__bg img { top: 0; height: 100%; }

  /* the intro panel is simply a full-width panel */
  .morph__pin { position: relative; height: auto; display: block;
    padding-block: 16vh; background: var(--t-background); }
  .morph__card { position: relative; width: 100%; height: auto; aspect-ratio: 16 / 7;
    margin-bottom: 8vh; }
  .morph__art img { width: 34%; }
  .morph__body { position: relative; }
  .morph__head, .morph__meta { position: relative; top: auto; bottom: auto; left: auto; }
  .morph__meta { margin-top: 6vh; }

  /* benefits falls back to the stacked list, which needs no pin */
  .benefits { display: none !important; }
  .benefits-alt { display: block !important; }

  /* the marquee becomes a single centred line */
  .band__pin { position: relative; height: auto; padding-block: 16vh 10vh; }
  .band__bg img { top: 0; height: 100%; }
  .band__marquee { position: relative; top: auto; text-align: center; }
  .band__marquee span:not(:first-child) { display: none; }
  .band__card { position: relative; right: auto; top: auto; margin: 6vh auto; }
  .band__foot { position: relative; bottom: auto; }

  /* pinned tracks become plain scrollable rows */
  .track__pin, .split__pin, .spec__pin { position: relative; height: auto;
    padding-block: 14vh 10vh; }
  .track__title, .spec__head { position: relative; top: auto; margin-bottom: 5vh; }
  .track__hint { display: block !important; }
  .track__rail { position: relative; top: auto; translate: none; overflow-x: auto;
    padding-right: var(--layout-padding); }
  .track__bg img { top: 0; height: 100%; }
  .split__art { position: relative; left: auto; top: auto; translate: none;
    margin: 4vh auto; width: 40%; }
  .split__meta { margin-top: 4vh; }
  .spec__stage { position: relative; left: auto; top: auto; translate: none;
    width: 100%; margin: 4vh auto 0; }
  .hotspot { display: none; }
  .spec__list { display: grid !important; grid-template-columns: repeat(2, minmax(0,1fr)); }

  /* stacked cards unstack; the sticky background sits above its list */
  .withyou__pin { position: relative; height: auto; padding-block: 14vh 6vh; }
  .withyou__art { position: relative; left: auto; top: auto; translate: none;
    margin: 3vh auto; width: 40%; }
  .withyou__head, .withyou__foot { position: relative; top: auto; bottom: auto; }
  .withyou__foot { margin-top: 4vh; }
  .withyou__card-slot { position: relative; height: auto; display: block; }
  .withyou__card-slot + .withyou__card-slot { margin-top: 24px; }
  .withyou__card { height: auto; max-height: none; width: 100%; }
  .withyou__card-overlay { display: none; }
  .htb__bg { position: relative; margin-bottom: 0; height: 70svh; }
  .htb__bg img { top: 0; height: 100%; }
  .uses__panel { position: relative; top: auto !important; }
}
@media (prefers-reduced-motion: reduce) and (min-width: 768px) {
  .benefits-list__item { display: grid; grid-template-columns: 1fr 1fr; gap: 50px;
    align-items: center; }
  .benefits-list__item > .benefits__icon { grid-column: 1; }
  .benefits-list__media { grid-row: 1 / span 4; grid-column: 2; margin-top: 0;
    aspect-ratio: 4 / 3; }
}
/* the menu dim is a hover affordance and must not fire on touch */
@media (hover: none) {
  .menu.is-open .menu__list:hover .menu__link { opacity: 1; }
}

/* ---- section heights trimmed to the reference's scroll budget ------------ */
@media (min-width: 768px) {
  .withyou__card-slot:last-child { height: 53svh; align-items: flex-start; }
  .uses__panel-inner { padding: 72px 0; }
  .picker__card { min-height: 700px; }
  .reviews__stage { height: 430px; }
  .kit__hero { min-height: 520px; }
  .partner__panel { margin-top: 40vh; }
}
@media (min-width: 768px) {
  .picker__cards { margin-top: 220px; }
  .picker__card { min-height: 760px; }
  .picker__card-art { top: -190px; }
  .picker__card-top { margin-top: 220px; }
  .reviews__stage { height: 380px; }
  .kit__hero { min-height: 460px; }
  .kit__card { min-height: 150px; }
}

/* The hero → intro handoff overlaps by a full viewport on desktop: the panel
   grows over the still-pinned hero photo. A phone cannot afford that — the
   hero pin is shorter, so the overlap puts the panel on screen at first paint,
   and any solid ground behind it cuts a hard line across the hero. On phones
   the intro is therefore an ordinary section: its own ground from its own top
   edge, and the panel grows against that instead of over the hero. */
@media (max-width: 767px) {
  .morph { margin-top: 0; background: var(--c-warm-white); }
  .morph__card { background: var(--c-cool-light-gray); }
}

/* ===========================================================================
   SNAG FIXES — the phone film panel, and the empty cream run after it.
   Scoped to a morph section that actually carries a full-bleed medium
   (`:has(.morph__art--fill)`), so the master's centred cut-out panel is
   untouched at every width.

   The panel now grows to the CLIP's aspect on phones rather than the screen's
   (see PATTERNS['morph-card'] in app.js), so at full bleed it is a 100vw band
   about 56vw tall. Centred inside a 100svh pin that left ~310px of bare ground
   above and below it, and the pin's own tail — the half viewport it travels
   after releasing, by which point the card has shrunk away — added another
   ~290px. Together that is the "large empty light/cream area" on the snag
   list. A shorter pin wraps the band instead of floating it, and a shorter
   section removes the dead scroll behind it.
   ========================================================================== */
@media (max-width: 767px) {
  .morph:has(.morph__art--fill) { height: 168svh !important; }
  /* The pin is sized to the band rather than to the screen, and offset down so
     the band still sits on the screen's centre line. Sizing it this way also
     cuts the pin's own tail from about half a viewport to ~160px. */
  .morph:has(.morph__art--fill) .morph__pin { height: 64svh; top: 18svh; }
}

/* ---------------------------------------------------------------------------
   Snag 1 — the benefits heading was clipped by the photo half around 1024px.

   `.benefits__slots` is given `width: 100%` while it is in flow, and is then
   re-declared `position: absolute` with a `left` and a `right` — but nothing
   clears the width. An absolutely positioned box with left + right + width all
   set is over-constrained, so `right` is dropped and the box runs past the
   column by the width of its own left inset (51px at 1024, 72px at 1440).
   The heading, centred inside that box, overhangs the seam and the photo
   column paints over it.

   Clearing the width lets left/right size the box again. The insets are set to
   the column's own padding so the heading now centres on the same axis as the
   icon above it, which it did not before.
   --------------------------------------------------------------------------- */
.benefits__slots {
  width: auto;
  left: clamp(30px, 9vw, 140px);
  right: clamp(30px, 5vw, 80px);
}

/* ---------------------------------------------------------------------------
   Snag 2 — the last "We work with you" card lost its bottom line.

   The card is 72svh tall, but the slot holding it is trimmed to 53svh to keep
   the section's scroll budget down. The card overflows its slot by 19svh, the
   section ends at the slot, and the section that follows paints over the
   difference — which lands in the middle of the card's last line of copy.
   Letting the last slot take its height from the card keeps the trim for every
   viewport where the card is shorter, and stops the clip everywhere else.
   --------------------------------------------------------------------------- */
@media (min-width: 768px) {
  .withyou__card-slot:last-child { height: auto; min-height: 53svh; }
}

/* ===========================================================================
   CONTACT — the section type added for this client (renderer: SECTIONS.contact
   in app.js). Additive: the master's `partner` styles above are untouched.

   Dark ground, two columns. The ways to reach the business sit on the left as
   a 2x2 grid of tiles; the form sits on the right in a white card. The card
   carries its own `ui-light` because a white card on a dark section otherwise
   inherits the section's white heading colour and renders white on white.
   ========================================================================== */
.contact { position: relative; overflow: hidden; }
.contact__inner { position: relative; z-index: 1; }
.contact__grid {
  display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: clamp(40px, 5vw, 90px); align-items: start;
}
.contact__title { margin-top: 18px; }
/* The reference sets its second line in an italic serif. Our display face is a
   bold geometric sans with no italic worth faking, so the contrast is carried
   by colour — the same move the FAQ title already makes. */
/* --t-secondary on ui-dark is #eef0ea against a #ffffff heading, which reads
   as no change at all. The knob lives in tokens.css so the contrast stays a
   per-client brand decision; without it this falls back to the FAQ's rule. */
.contact__title-alt { color: var(--contact-title-alt, var(--t-secondary)); }
.contact__text { margin-top: 30px; max-width: 46ch; }

.contact__tiles {
  list-style: none; margin: clamp(40px, 5vw, 64px) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(28px, 3vw, 44px) clamp(18px, 2vw, 28px);
}
.contact__tile { display: block; min-width: 0; }
.contact__tile-icon {
  display: grid; place-items: center; width: 52px; height: 52px; margin-bottom: 18px;
  border: 1px solid var(--t-line); border-radius: 50%; color: var(--t-icon);
}
.contact__tile-icon svg { width: 24px; height: 24px; }
.contact__tile-label {
  display: block; margin-bottom: 6px; color: var(--t-secondary);
  text-transform: uppercase; letter-spacing: .12em;
}
.contact__tile-value {
  display: inline-block; color: var(--t-heading);
  /* 16px, not --fs-body: at 18px the email address does not fit a half column
     and breaks mid-word. Still above the 14px floor on every viewport. */
  font-size: 1.6rem;
  line-height: 1.45; word-break: break-word;
  /* the tiles are the primary call to action on a phone: keep them thumb-sized */
  min-height: 44px;
}
a.contact__tile-value::after { background: currentColor; }

/* ---- the form card ------------------------------------------------------- */
.contact__card {
  background: var(--c-warm-white); border-radius: var(--radius-lg);
  padding: clamp(28px, 3vw, 50px);
}
.ffield { display: block; }
.ffield + .ffield { margin-top: 26px; }
.ffield__label {
  display: block; margin-bottom: 8px; font-size: var(--fs-small);
  line-height: 1.4; color: var(--t-secondary);
}
.ffield__input {
  display: block; width: 100%; background: none; border: 0;
  border-bottom: 1px solid var(--t-line); border-radius: 0;
  color: var(--t-heading); font-family: inherit;
  padding: 8px 0 10px;
  /* never below 16px: iOS Safari zooms the page on focus otherwise */
  font-size: 1.6rem; line-height: 1.5;
  /* 16px + this padding lands at 42px, which fails the 44px tap-target floor
     on a phone. The floor is a hard acceptance target, so set it outright. */
  min-height: 44px;
  transition: border-color var(--dur-ui) var(--ease);
}
.ffield__input:focus { outline: none; border-bottom-color: var(--t-heading); }
.ffield textarea.ffield__input { resize: vertical; min-height: 84px; }
/* a native select keeps its own arrow on every platform; only the box is ours */
.ffield select.ffield__input { appearance: none; -webkit-appearance: none;
  padding-right: 28px; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 12px) calc(50% + 2px), calc(100% - 7px) calc(50% + 2px);
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
.contact__note { margin-top: 26px; color: var(--t-secondary); text-transform: none;
  letter-spacing: 0; line-height: 1.5; }
.contact__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
.contact__send { flex: 1 1 auto; }
.contact__call { flex: 0 1 auto; gap: 10px; min-height: 56px; padding: 0 24px; }
.contact__call-icon { display: grid; place-items: center; width: 18px; height: 18px; }
.contact [data-form-msg]:empty { display: none; }
.contact [data-form-msg] { margin-top: 16px; color: var(--t-secondary); }

@media (max-width: 1199px) {
  .contact__grid { gap: 40px; }
}
@media (max-width: 899px) {
  .contact__grid { grid-template-columns: 1fr; }
  .contact__card { margin-top: 8px; }
}
@media (max-width: 767px) {
  .contact__tiles { gap: 26px 20px; }
  .contact__tile-icon { width: 44px; height: 44px; margin-bottom: 14px; }
  .contact__tile-icon svg { width: 20px; height: 20px; }
  .contact__actions { flex-direction: column; align-items: stretch; }
  .contact__call { justify-content: center; }
}

/* ---------------------------------------------------------------------------
   Hero, left-aligned (`align: 'left'` in the hero's config → `.hero--left`).

   The centred stack read flat at large widths once the offset poster card was
   removed: three centred display lines, a centred locator and a centred CTA
   on a symmetric photograph leave nothing to push against. Flush to the page
   gutter gives the composition a spine, and it is what the client's own site
   does with the same headline.

   Additive: a hero with no `align` is unchanged, so the master still centres.
   Nothing here touches font-size — the type scale still measures the same.
   --------------------------------------------------------------------------- */
.hero--left .hero__inner { justify-content: flex-start; }
.hero--left .hero__stack { align-items: flex-start; }
.hero--left .hero__title { text-align: left; }
.hero--left .hero__eyebrow { justify-content: flex-start; text-align: left; }
/* The rules drew outward from a centred eyebrow. Flush left, only the trailing
   one still reads as a rule rather than an indent. */
.hero--left .hero__eyebrow::before { display: none; }
/* The invisible spacer exists to balance the pin icon so the TEXT centres.
   Left-aligned there is nothing to balance, and it only adds trailing space. */
.hero--left .hero__sub::after { display: none; }

/* ---------------------------------------------------------------------------
   About ("Angel Cordero") — give the photograph its own room.

   The master's `split__art` is an abstract line drawing, so parking it absolutely
   in the middle of the pin and letting the display title and the two cards cross
   it is the intended effect. This client's art is a photograph of a family: the
   title crossed their heads and the two white cards cut the picture in half.

   The photograph becomes a flex item between the title and the cards instead of
   an absolute layer behind them, and takes whatever height is left over — so it
   is as large as the viewport allows at every height and never underneath
   anything. `contain` keeps it whole when that leftover band is short.
   --------------------------------------------------------------------------- */
@media (min-width: 768px) {
  .split__pin { justify-content: space-between; padding-block: 6vh 5vh; }
  /* The image is first in the markup because it was an absolute layer. In flow
     it has to sit between the title and the cards, so the column is ordered
     explicitly rather than by source position. */
  .split__title { flex: 0 0 auto; order: 1; }
  .split__art {
    position: static; translate: none;
    flex: 1 1 0; min-height: 0;
    width: 100%; max-width: none; height: auto;
    object-fit: contain; object-position: center;
    /* A negative top margin lets the display title cross the top of the frame,
       which is the section's character and is how it read before — the damage
       was only ever the two cards cutting through the middle of the picture.
       It also hands that overlap back to the image as height. */
    margin-block: -7vh 2vh; order: 2;
  }
  .split__meta { flex: 0 0 auto; margin-top: 0; order: 3; }
}

/* ---------------------------------------------------------------------------
   Descenders cut off the bottom of revealed headings.

   Each word in a `data-anim` heading is wrapped in a `.word` mask with
   `overflow: hidden`, which is what hides it while it slides up into place.
   That mask is exactly one line box tall — and at the display line-heights
   here (1.0 to 1.16) a line box is shorter than the face's own ascent plus
   descent, so Urbanist's deep descenders are clipped. "Everything you are
   looking at was a decision." lost the tails of every y and g, and the bottom
   of the last line with them.

   Padding the mask down and pulling the same amount back off the margin grows
   the clipped region without moving anything: the word still starts fully
   outside the mask, so the reveal is unchanged.
   --------------------------------------------------------------------------- */
.word { padding-bottom: 0.2em; margin-bottom: -0.2em; }

/* ---------------------------------------------------------------------------
   "How a project runs" cards — one image size, not four.

   `.track__card-art` is `flex: 1`, so the picture took whatever height was
   left after that card's own text. Four cards with four different lengths of
   copy therefore had four different picture heights, and the row read as
   ragged. A fixed ratio makes every frame identical and lets the text below
   it vary instead, which is where variation belongs.
   --------------------------------------------------------------------------- */
.track__card-art { flex: 0 0 auto; aspect-ratio: 4 / 3; }
/* With the picture no longer absorbing the slack, the copy needs somewhere to
   go, so the fixed card height becomes a floor. Flex stretches every card to
   the tallest, so the row still ends level. */
.track__card { height: auto; align-self: stretch; }
/* The old fixed heights were sized around a picture that grew to fill them.
   With the picture fixed they only left a block of empty card under the copy,
   and on desktop a 74svh card also rode up over the section's own heading.
   Letting the content set the height and flex level the row does both jobs. */
@media (min-width: 768px) { .track__card { min-height: 0; } }
@media (max-width: 767px) { .track__card { min-height: 0; } }

/* ---------------------------------------------------------------------------
   MENU — the three ways to reach them, under the nav list.

   The overlay was a list of section links and two small text links. Nothing in
   it let a visitor act, which for a trade business is the whole point of
   opening it. Additive: the block renders only when the config carries a CTA
   or a phone number, so the master's menu is unchanged without them.
   --------------------------------------------------------------------------- */
.menu__cta {
  margin-top: clamp(32px, 5vh, 56px);
  display: flex; flex-wrap: wrap; gap: 12px;
}
.menu__cta-btn {
  gap: 12px; min-height: 56px; padding: 0 28px;
  color: var(--t-menu-text);
}
.menu__cta-btn.btn--primary {
  background: var(--c-warm-brown); color: var(--c-warm-white);
  border: 1px solid transparent;
}
.menu__cta-btn.btn--outline { border-color: color-mix(in srgb, currentColor 35%, transparent); }
.menu__cta-btn.btn--outline:hover { border-color: currentColor; }
.menu__cta-icon { display: grid; place-items: center; width: 20px; height: 20px; flex: none; }
.menu__cta-icon svg { width: 20px; height: 20px; }

/* ---- the overlay has to be scrollable, and its top has to be reachable ---
   Two separate faults, both showing as "can't scroll":

   1. The scroller was `.menu__inner`, a flex column with `height: 100%` and
      `justify-content: center`. Centring content that is TALLER than its
      container overflows it in both directions, and the overflow above the
      start edge cannot be scrolled to — so the first nav item and the close
      button collided with no way to reach either. Moving the scroll to
      `.menu` and letting the inner GROW (min-height, not height) keeps the
      centring when it fits and stops trapping anything when it does not.
   2. Lenis swallowed the wheel — see the data-lenis-prevent note in app.js. */
.menu { overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.menu__inner { height: auto; min-height: 100%; overflow: visible; }
/* The close button is fixed to the overlay, not to the scrolling content, so
   it stays put while the panel moves under it. */
.menu__close { position: fixed; z-index: 2; }

/* ---- the overlay's two columns ------------------------------------------ */
/* The wordmark gives the overlay a top-left anchor, so the composition has
   corners instead of floating in the middle of the screen. */
.menu__mark {
  position: absolute; top: 44px; left: var(--layout-padding);
  font-family: var(--font-display); font-weight: var(--fw-display, 300);
  font-size: var(--fs-d5); letter-spacing: -0.01em; color: var(--t-menu-text);
  min-height: 44px; display: inline-flex; align-items: center;
}
.menu__grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 330px);
  gap: clamp(40px, 5vw, 80px); align-items: stretch; width: 100%;
}
.menu__main { min-width: 0; display: flex; flex-direction: column; justify-content: center; }
/* A hairline down the left edge ties the panel to the nav instead of leaving
   it adrift on the right of a wide screen. */
.menu__aside {
  min-width: 0; padding-top: 6px; padding-left: clamp(24px, 3vw, 46px);
  border-left: 1px solid color-mix(in srgb, currentColor 18%, transparent);
}
.menu__aside-title {
  color: color-mix(in srgb, currentColor 55%, transparent);
  text-transform: uppercase; letter-spacing: .14em; margin-bottom: 28px;
}
.menu__details { display: grid; gap: 22px; }
.menu__detail { display: block; }
.menu__detail-label {
  display: block; margin-bottom: 4px;
  color: color-mix(in srgb, currentColor 55%, transparent);
  text-transform: uppercase; letter-spacing: .12em;
}
.menu__detail-value {
  display: inline-block; font-size: var(--fs-body); line-height: 1.45;
  color: var(--t-menu-text); word-break: break-word;
}
/* the 44px floor is for the things you can actually tap; the service area is
   a line of text and does not need to reserve a thumb's worth of height */
a.menu__detail-value { min-height: 44px; display: inline-flex; align-items: center; }
a.menu__detail-value::after { background: currentColor; }

@media (max-width: 899px) {
  /* one column, and the details become a grid of their own so they do not
     turn into a tall ladder on a phone. The hairline turns horizontal with
     them — a left edge means nothing once the panel is full width. */
  .menu__grid { grid-template-columns: 1fr; gap: 34px; }
  .menu__aside {
    padding-top: 30px; padding-left: 0;
    border-left: 0; border-top: 1px solid color-mix(in srgb, currentColor 18%, transparent);
  }
  .menu__details { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 24px; }
  .menu__mark { display: none; }
}
/* Short screens: the list is what gives, not the contact panel. */
@media (min-width: 900px) and (max-height: 820px) {
  .menu__link { font-size: clamp(2.8rem, 4.6vh, 4.2rem); line-height: 1.18; }
  .menu__inner { padding-block: 100px 44px; }
  .menu__cta { margin-top: clamp(24px, 4vh, 40px); }
  .menu__details { gap: 18px; }
}
@media (max-width: 767px) {
  /* The overlay now carries the nav, three actions and four contact blocks.
     Stacked at the master's sizes that is taller than a phone screen, so the
     list tightens a step and the two secondary actions sit side by side —
     which also reads better, since they are a pair. */
  .menu__inner { padding-block: 80px 28px; justify-content: flex-start; }
  .menu__link { font-size: clamp(2.8rem, 8vw, 3.6rem); line-height: 1.2; }
  .menu__list li + li { margin-top: 0; }
  .menu__cta {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px;
    margin-top: clamp(20px, 3vh, 28px);
  }
  .menu__cta-btn { justify-content: center; padding: 0 14px; min-height: 48px; }
  .menu__cta-btn.btn--primary { grid-column: 1 / -1; }
  /* The rule above the panel already says "new block"; on a phone the label
     as well is one line of nothing, and lines are the scarce thing here. */
  .menu__aside-title { display: none; }
  .menu__details { gap: 14px 20px; }
  .menu__grid { gap: 26px; }
  .menu__aside { padding-top: 24px; }
  .menu__detail--wide { grid-column: 1 / -1; }
}
/* a short landscape phone has no room for the big list AND the details */
@media (max-height: 560px) and (orientation: landscape) {
  .menu__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 260px); gap: 40px; }
  .menu__details { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 20px; }
  .menu__inner { padding-block: 80px 30px; justify-content: flex-start; }
}

/* ---------------------------------------------------------------------------
   PHONE ACTION BAR — estimate / call / text, pinned to the bottom.

   About 85% of this client's traffic is mobile, and the three things a visitor
   actually wants are otherwise a long scroll away. The floating dot that
   serves desktop is too small to carry three actions, so phones get this bar
   and the dot is hidden; they never appear together.

   It arrives and retreats on exactly the same rule as the dock (see dockOn()
   in app.js), so it is out of the way at the top of the page and gets out of
   the footer's way at the bottom.
   --------------------------------------------------------------------------- */
.action-bar { display: none; }
@media (max-width: 767px) {
  .buy-dock { display: none; }
  .action-bar {
    display: grid; grid-template-columns: 1.5fr 1fr 1fr;
    position: fixed; z-index: 40;
    left: 12px; right: 12px; bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    padding: 6px; gap: 6px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--c-cool-dark-blue) 92%, transparent);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    box-shadow: 0 10px 34px rgba(34, 51, 24, .34);
    opacity: 0; transform: translateY(18px); pointer-events: none;
    transition: opacity .5s var(--ease-op), transform .5s var(--ease);
  }
  .action-bar.is-on { opacity: 1; transform: none; pointer-events: auto; }
  .action-bar__item {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    min-height: 48px; padding: 0 10px; border-radius: 999px;
    color: var(--c-warm-white); font-size: var(--fs-micro);
    letter-spacing: .04em; text-transform: uppercase; white-space: nowrap;
    transition: background-color var(--dur-ui) var(--ease);
  }
  .action-bar__item--primary { background: var(--c-warm-brown); }
  .action-bar__item:not(.action-bar__item--primary):active { background: rgba(255, 255, 255, .12); }
  .action-bar__icon { display: grid; place-items: center; width: 18px; height: 18px; flex: none; }
  .action-bar__icon svg { width: 18px; height: 18px; }
  /* the bar floats over the page, so the footer needs somewhere to end */
  .footer { padding-bottom: calc(40px + 72px + env(safe-area-inset-bottom, 0px)); }
}

/* ===========================================================================
   SERVICES — a swipeable rail (renderer: SECTIONS.services in app.js).
   Additive: the master's `picker` styles are untouched.
   ========================================================================== */
.services { position: relative; overflow: hidden; }
.services__head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 40px; margin-bottom: clamp(32px, 4vw, 56px);
}
.services__head-copy { min-width: 0; }
.services__intro { margin-top: 20px; max-width: 46ch; }
.services__nav { display: flex; gap: 12px; flex: none; }
.services__arrow {
  width: 56px; height: 56px; border-radius: 50%; display: grid; place-items: center;
  color: var(--t-heading); background: none;
  border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
  cursor: pointer;
  transition: background-color var(--dur-ui) var(--ease), border-color var(--dur-ui) var(--ease),
              opacity var(--dur-ui) var(--ease);
}
.services__arrow svg { width: 20px; height: 20px; }
.services__arrow--prev svg { transform: rotate(180deg); }
.services__arrow:hover:not(:disabled) { border-color: currentColor;
  background: color-mix(in srgb, currentColor 8%, transparent); }
.services__arrow:disabled { opacity: .3; cursor: default; }

/* The rail is padded by the page gutter rather than sitting inside a container,
   so a card can run off the right edge of the screen — which is what tells you
   there is another one. */
.services__rail {
  display: flex; gap: clamp(16px, 2vw, 28px);
  padding-inline: var(--layout-padding);
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
  scroll-padding-left: var(--layout-padding);
  /* The cards cast a soft shadow, and this container clips. Four pixels of
     room cut it into a hard horizontal edge across the section; the shadow
     needs its whole spread or it reads as banding. */
  padding-block: 10px 46px;
  margin-bottom: -30px;
}
.services__rail::-webkit-scrollbar { display: none; }
/* Mouse users get to drag the rail; the cursor is what tells them so. Touch
   keeps its own native swipe, which is why the grab cursor is hover-gated. */
@media (hover: hover) and (pointer: fine) {
  .services__rail { cursor: grab; }
  .services__rail.is-dragging { cursor: grabbing; user-select: none; scroll-behavior: auto; }
  .services__rail.is-dragging img { pointer-events: none; }
}
.services__rail::after { content: ''; flex: 0 0 calc(var(--layout-padding) - clamp(16px, 2vw, 28px)); }

.services__card {
  flex: 0 0 clamp(300px, 34%, 460px); scroll-snap-align: start;
  display: flex; flex-direction: column;
  background: var(--c-warm-white); border-radius: var(--radius-lg);
  padding: clamp(18px, 1.4vw, 22px);
  box-shadow: 0 18px 50px -34px rgba(34, 51, 24, .45);
}
.services__art {
  position: relative; border-radius: var(--radius-md); overflow: hidden;
  aspect-ratio: 3 / 2; margin-bottom: 24px;
}
.services__art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.services__badge {
  position: absolute; left: 14px; top: 14px;
  padding: 7px 14px; border-radius: 999px;
  background: color-mix(in srgb, var(--c-cool-dark-blue) 88%, transparent);
  color: var(--c-warm-white); text-transform: uppercase; letter-spacing: .1em;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
.services__name { margin-bottom: 12px; }
.services__text { color: var(--t-text); margin-bottom: 24px; }
.services__specs { margin: 0 0 28px; }
.services__spec {
  display: flex; align-items: baseline; justify-content: space-between; gap: 20px;
  padding-block: 11px; border-top: 1px solid var(--t-line);
}
.services__spec:last-child { border-bottom: 1px solid var(--t-line); }
.services__spec dt { color: var(--t-secondary); }
.services__spec dd { margin: 0; color: var(--t-heading); text-align: right; }
/* the button sits on the card's floor whatever the copy above it does */
.services__cta { margin-top: auto; align-self: flex-start; gap: 12px; }

.services__dots { display: flex; gap: 4px; margin-top: clamp(22px, 2.6vw, 34px); }
/* The mark is a 4px bar; the BUTTON is a 44px target around it. Sizing the
   button to the bar would have failed the phone tap-target floor, and padding
   it out with a pseudo-element would have passed by eye while still measuring
   4px tall to anything checking. */
.services__dot {
  width: 54px; height: 44px; padding: 0; border: 0; background: none; cursor: pointer;
  display: grid; place-items: center;
}
.services__dot::before {
  content: ''; display: block; width: 34px; height: 4px; border-radius: 999px;
  background: color-mix(in srgb, var(--t-heading) 22%, transparent);
  transition: background-color var(--dur-ui) var(--ease), width var(--dur-ui) var(--ease);
}
.services__dot.is-on::before { width: 54px; background: var(--c-warm-brown); }

@media (max-width: 899px) {
  .services__head { flex-direction: column; align-items: flex-start; gap: 24px; }
  .services__nav { order: -1; display: none; }
}
@media (max-width: 767px) {
  .services__card { flex-basis: min(82vw, 380px); padding: 14px; }
  .services__art { margin-bottom: 18px; }
  .services__specs { margin-bottom: 22px; }
  .services__cta { align-self: stretch; justify-content: center; }
}

/* ---------------------------------------------------------------------------
   FILM ON PHONES — a control in the hero and a lightbox, instead of a section.

   The scrolling film panel stays as it is on desktop. On a phone it cost most
   of a screen of scroll to show a clip that, at phone width and its own
   aspect, is only a shallow band — so the section is hidden there and the hero
   offers the film instead. The clip's source is attached on first open, so a
   visitor who never asks for it never pays for it.
   --------------------------------------------------------------------------- */
.hero__film { display: none; }

.filmbox {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center;
  opacity: 0; transition: opacity .26s var(--ease-op);
}
.filmbox.is-on { opacity: 1; }
.filmbox[hidden] { display: none; }
.filmbox__scrim { position: absolute; inset: 0; background: rgba(12, 18, 9, .92); }
.filmbox__stage {
  position: relative; width: min(94vw, 1100px);
  transform: scale(.97); transition: transform .3s var(--ease);
}
.filmbox.is-on .filmbox__stage { transform: none; }
.filmbox__video {
  width: 100%; max-height: 80svh; display: block;
  border-radius: var(--radius-md); background: #000;
}
.filmbox__close {
  position: absolute; top: max(16px, env(safe-area-inset-top, 0px)); right: 16px;
  width: 48px; height: 48px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  color: var(--c-warm-white); background: rgba(255, 255, 255, .12);
  border: 1px solid rgba(255, 255, 255, .4);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  font-size: 1.6rem; line-height: 1;
}

@media (max-width: 767px) {
  /* the section goes; the hero control takes its place */
  .morph:has(.morph__art--fill) { display: none !important; }
  .hero__film {
    display: inline-flex; align-items: center; gap: 14px;
    margin-top: 22px; padding: 0; background: none; border: 0;
    color: #fff; cursor: pointer;
    /* 44px exactly lands on the tap-target floor and rounds under it at some
       widths; 48 clears it at every one. */
    min-height: 48px;
  }
  .hero__film-dot {
    display: grid; place-items: center; width: 44px; height: 44px; flex: none;
    border-radius: 50%; border: 1px solid rgba(255, 255, 255, .55);
    background: rgba(0, 0, 0, .22);
    backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  }
  .hero__film-dot svg { width: 16px; height: 16px; }
  .hero__film-label {
    font-size: var(--fs-micro); letter-spacing: .1em; text-transform: uppercase;
    opacity: .92;
  }
  .filmbox__stage { width: 100vw; }
  .filmbox__video { border-radius: 0; max-height: 72svh; }
}

/* ---------------------------------------------------------------------------
   The "anatomy of a finished yard" section's empty left column.

   The heading sits top-left and the medallion right-of-centre, which left the
   bottom-left quarter of the screen empty at rest — the hotspot cards only
   appear there on hover, and nothing told you the dots were interactive.

   The markup already carries the four points as a plain list; it is the phone
   fallback and was simply hidden above 768px. Showing it in that column turns
   the gap into an index of what the dots point at. Titles only — the dots'
   own cards carry the detail, so nothing is said twice.
   --------------------------------------------------------------------------- */
@media (min-width: 768px) {
  /* The list's own wrapper is position: relative with auto height, so a
     percentage top on the list resolves against a box of no height and lands
     at zero. Position the WRAPPER against the pin and let the list sit in it
     normally — the wrapper already carries the page gutter. */
  /* Anchored to the FOOT of the pin, not to a percentage from the top: the
     heading above it grows and shrinks with the viewport, and a percentage
     top eventually walks into it. From the bottom the index keeps its own
     corner at every height. */
  .spec__pin > .container-h:last-child {
    position: absolute; left: 0; right: 0; bottom: 13%;
  }
  .spec__list {
    display: grid !important;
    position: static; width: min(38%, 420px);
    gap: 0; margin-top: 0; counter-reset: spec;
    pointer-events: none;
  }
  .spec__list li {
    counter-increment: spec;
    display: flex; align-items: baseline; gap: 16px;
    /* the phone styling gives these a filled, rounded card; here they are
       rules, so the radius has to go with the fill */
    background: none; border-radius: 0; padding: 14px 0;
    border-top: 1px solid color-mix(in srgb, var(--t-heading) 14%, transparent);
  }
  .spec__list li:last-child {
    border-bottom: 1px solid color-mix(in srgb, var(--t-heading) 14%, transparent);
  }
  .spec__list li::before {
    content: '0' counter(spec);
    font-family: var(--font-display); font-size: var(--fs-micro);
    color: var(--t-secondary); flex: none;
  }
  /* the index is titles; the hotspot cards are the detail */
  .spec__list li p { display: none; }
  .spec__list li h3 { font-size: var(--fs-body); line-height: 1.3; }
}
/* Only a genuinely short screen — a laptop at 680px still has room for it,
   and hiding it there was leaving exactly the gap this was meant to fill. */
@media (min-width: 768px) and (max-height: 560px) {
  .spec__list { display: none !important; }
}

/* ---------------------------------------------------------------------------
   GLASS HEADER

   The header is transparent and re-themes from whatever is painted beneath it,
   which reads well over the hero but left the wordmark and the CTA sitting
   directly on top of whatever text happened to pass under them — the footer's
   email address, a section heading, the seam between a dark and a light block.

   A glass ground fixes it without giving up the theming: the tint is
   `--t-background`, which the header's own theme class is already setting, so
   it follows the section beneath rather than fighting it. Transparent at the
   top of the page, where the hero should be uninterrupted.
   --------------------------------------------------------------------------- */
.header { --header-top: 30px; }
@media (max-width: 767px) { .header { --header-top: 10px; } }
.header::before {
  content: ''; position: absolute; z-index: 0;
  /* The header sits 30px down the page, so a pane drawn only behind the bar
     left a bare strip above it with the page showing through. The glass
     starts at the very top of the viewport instead. */
  /* Symmetric about the bar. Reaching up to the viewport top but stopping
     at the bar's own bottom edge left twice as much glass above the wordmark
     as below it. */
  inset: calc(-1 * var(--header-top)) 0 calc(-1 * var(--header-top)) 0;
  /* White glass rather than a tint taken from the section beneath: one
     surface that sits over the dark green, the cream and the photographs
     alike, instead of changing character at every section boundary. */
  background: rgba(255, 255, 255, .72);
  backdrop-filter: blur(16px) saturate(1.5);
  -webkit-backdrop-filter: blur(16px) saturate(1.5);
  border-bottom: 1px solid rgba(255, 255, 255, .5);
  opacity: 0; pointer-events: none;
  transition: opacity .35s var(--ease-op);
}
.header.is-stuck::before { opacity: 1; }
/* the bar sits ON the glass, not under it */
.header .container-h { position: relative; z-index: 1; }
/* White glass means the ink can no longer follow the section beneath — over
   a dark section the header would otherwise paint white on white. Overriding
   the heading token covers the wordmark, the CTA and the burger at once,
   since all three already read from it. */
.header.is-stuck { --t-heading: var(--c-cool-dark-blue); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .header::before { background: rgba(255, 255, 255, .93); }
}

/* ---------------------------------------------------------------------------
   "Three ways to reach us" — each route now offers the thing it describes.
   --------------------------------------------------------------------------- */
.htb__do {
  display: inline-flex; align-items: center; min-height: 44px;
  margin-top: 10px; color: var(--t-heading);
  font-size: var(--fs-body); line-height: 1.4; word-break: break-word;
}
a.htb__do::after { background: currentColor; }

@media (max-width: 767px) {
  /* Three icon-title-paragraph blocks stacked down a white page read as a
     wall. Giving each one a card and tightening the rhythm makes them three
     things rather than one long column. */
  .htb__list li + li { margin-top: 14px; }
  .htb__card {
    display: grid; grid-template-columns: 44px minmax(0, 1fr);
    gap: 16px; align-items: start;
    padding: 22px; border-radius: var(--radius-md);
    background: var(--c-warm-light-beige);
  }
  .htb__card .benefits__icon { width: 44px; height: 44px; margin: 0; }
  .htb__card h3 { font-size: var(--fs-d5); }
  /* the email is the longest value and the icon column leaves it ~240px */
  .htb__do { font-size: var(--fs-small); }
}

/* ---------------------------------------------------------------------------
   The spec medallion on phones.

   Its canvas deliberately parks the medallion right-of-centre so the display
   heading in the LEFT column is not covered — which is right on desktop and
   pointless on a phone, where there is no left column and the offset is just
   an empty third of the screen. The hotspot dots are hidden at this width and
   the points render as a list instead, so the artwork can be cropped to the
   medallion without moving anything that is still positioned against it.
   --------------------------------------------------------------------------- */
@media (max-width: 767px) {
  .spec__stage { aspect-ratio: 1 / 1; position: relative; overflow: hidden; margin-top: 18px; }
  .spec__stage img {
    position: absolute; max-width: none; object-fit: fill;
    /* the medallion occupies x 420–1000, y 95–660 of the 1000x760 canvas */
    width: 172.4%; height: auto; left: -72.4%; top: -16.4%;
  }
}

/* ---------------------------------------------------------------------------
   The header steps out of the way of the full-bleed film.

   `translate` rather than `transform`, because the header's entry animation
   already owns `transform` and the two would clobber each other.
   --------------------------------------------------------------------------- */
.header {
  transition: transform var(--dur-loader) var(--ease-inout),
              opacity .3s var(--ease-op),
              translate .45s var(--ease);
}
.header.is-away { opacity: 0; translate: 0 -130%; pointer-events: none; }
.header.is-away * { pointer-events: none; }

/* ---------------------------------------------------------------------------
   The floating estimate button, made to read as live.

   It sat in the corner looking like another static element. A ring pulsing
   out of it, and a very small breath on the button itself, are enough to
   catch the eye without becoming a distraction on a page this long. The ring
   lives on the wrapper, not the button, so nothing clips it — and it only
   runs once the dock is actually on screen.
   --------------------------------------------------------------------------- */
.buy-dock::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  border: 1.5px solid var(--c-warm-brown);
  opacity: 0; pointer-events: none;
}
/* The ring is the whole effect. A matching breath on the BUTTON was tried and
   removed: the button carries a 40px box-shadow, and scaling that repaints the
   shadow every frame. The ring is a 1.5px border with no shadow, so it
   composites instead. */
.buy-dock.is-on::after { animation: dockRing 2.9s var(--ease-op) infinite; }
@keyframes dockRing {
  0%   { transform: scale(1);    opacity: .6; }
  65%  { transform: scale(1.62); opacity: 0; }
  100% { transform: scale(1.62); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .buy-dock.is-on::after { animation: none; }
  .header { transition: opacity .3s var(--ease-op); }
}

/* ---------------------------------------------------------------------------
   The header condenses as you scroll.

   At rest it is generous — 30px of air above a 60px bar, 120px of glass in
   all. That is right over the hero and too much to carry down a long page, so
   once the glass comes on the bar tightens and the whole pane drops to 78px.

   `top` and `height` are what transition, not the custom properties feeding
   them: an unregistered custom property does not animate, but the lengths it
   resolves to do. Phones keep their proportions — the header is already small
   there and condensing it further only makes the tap targets tighter.
   --------------------------------------------------------------------------- */
.header { top: var(--header-top); }
.header, .header__bar, .header::before {
  transition-property: opacity, top, bottom, height, transform, translate,
                       background-color, color;
  transition-duration: .35s;
  transition-timing-function: var(--ease);
}
@media (min-width: 768px) {
  .header.is-stuck { --header-top: 14px; }
  .header.is-stuck .header__bar { height: 50px; }
  .header.is-stuck .header__logo { font-size: 2.1rem; }
}

/* ---------------------------------------------------------------------------
   The about panel's display line, and the photographs set into it.
   Scoped to this section so the panel layout itself is unchanged.
   --------------------------------------------------------------------------- */
#about .panel__quote {
  font-size: var(--fs-d3); line-height: var(--lh-d3); letter-spacing: var(--ls-d3);
}
#about .chip { width: 1.3em; height: 0.8em; }

/* ---------------------------------------------------------------------------
   HERO ROTATOR — phones show one service at a time.

   Desktop and tablets get the headline as written. Below 768px the three
   services are four lines of display type before the page has said anything
   else, so they take turns in a single slot instead. The written headline is
   not deleted, only hidden from sight: it stays in the H1 as the accessible
   text, which is what a screen reader and a search engine should still get.

   Under reduced motion nothing rotates, so the written headline comes back —
   a slot showing one of three services with no way to see the others would be
   worse than the four lines it replaced.
   --------------------------------------------------------------------------- */
.hero__rotator { display: none; }

@media (max-width: 767px) {
  .hero__title-lines {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .hero__rotator {
    display: block; position: relative;
    /* The height is set per item in app.js and glides between them, so a
       one-line service does not leave a dead line under it and a two-line
       one does not jog the stack. This is only the floor before that runs. */
    min-height: calc(var(--lh-d2) * 1em);
    transition: height .5s var(--ease);
  }
  .hero__rot {
    position: absolute; left: 0; top: 0; width: 100%;
    opacity: 0; translate: 0 .34em;
    transition: opacity .55s var(--ease-op), translate .7s var(--ease);
  }
  .hero__rot.is-on { opacity: 1; translate: none; }
}

@media (max-width: 767px) and (prefers-reduced-motion: reduce) {
  .hero__title-lines {
    position: static; width: auto; height: auto; margin: 0;
    overflow: visible; clip: auto; white-space: normal;
  }
  .hero__rotator { display: none; }
}

/* ---------------------------------------------------------------------------
   Brand mark before the wordmark (SITE.brand.markHtml). Additive: with no
   mark configured the span is never rendered. Colour is a per-client token
   with a fallback, so the master is unaffected.
   --------------------------------------------------------------------------- */
.logo-mark { display: inline-block; width: 2.2em; margin-right: .5em; vertical-align: -0.02em;
  color: var(--logo-mark, currentColor); }
.logo-mark svg { display: block; width: 100%; height: auto; overflow: visible; }
.header.is-stuck .logo-mark { color: var(--logo-mark-stuck, var(--logo-mark, currentColor)); }
.header__logo, .menu__mark { white-space: nowrap; }

/* ---------------------------------------------------------------------------
   Phones hide the written headline only when a rotator replaces it. Without
   `rotate` in the hero config the headline used to vanish with nothing in its
   place.
   --------------------------------------------------------------------------- */
@media (max-width: 767px) {
  .hero__title:not(:has(.hero__rotator)) .hero__title-lines {
    position: static; width: auto; height: auto; margin: 0;
    overflow: visible; clip: auto; white-space: normal;
  }
}

/* ---------------------------------------------------------------------------
   A hero followed directly by benefits, with no morph panel between them.
   The master's -140svh on .benefits is measured to tuck under the morph
   panel's tail; straight after the hero it lands 450px down the first screen.
   Here the benefits panel instead rises over the pinned hero like a curtain,
   starting at the foot of the first screen. Phones do the same with the
   stacked list, which otherwise left the hero's 90svh tail as empty ground.
   --------------------------------------------------------------------------- */
.hero + .benefits { margin-top: -90svh; }
/* Phones cut the hero to 150svh (see the touch block), so the list rises
   from the foot of the first screen at -50svh. A full screen of hero, always. */
@media (max-width: 767px) {
  .hero + .benefits + .benefits-alt { margin-top: -50svh; }
}
/* Reduced motion has no pin and no curtain: a plain linear document. */
@media (prefers-reduced-motion: reduce) {
  .hero + .benefits, .hero + .benefits + .benefits-alt { margin-top: 0 !important; }
}

/* ---------------------------------------------------------------------------
   Phone header: wordmark and burger only. The estimate pill duplicated the
   bottom action bar, which already carries estimate, call and text, and at
   390px it collided with a two-word wordmark.
   --------------------------------------------------------------------------- */
@media (max-width: 767px) {
  .header .header__buy { display: none; }
  .header .header__logo { font-size: 1.9rem; }
}

/* ---------------------------------------------------------------------------
   Panel card holding a photograph rather than a cut-out (card.fill: true).
   The master's art sits at 76% width on a grey tile, which suits a centred
   cut-out; a photograph clipped that way left grey showing round it. Here it
   covers the tile edge to edge instead.
   --------------------------------------------------------------------------- */
.panel__card-art--fill { background: none; }
.panel__card-art--fill img { width: 100%; height: 100%; object-fit: cover; }

/* ---------------------------------------------------------------------------
   Stacked logo lockup (SITE.brand.wordmark). Mark centred over the lines.
   Sizes are in em off the logo's own font-size, so the header, the condensed
   header and the menu all scale it from the one value they already set.
   --------------------------------------------------------------------------- */
.logo-lockup { display: inline-flex; flex-direction: column; align-items: center; line-height: 1; }
.logo-lockup .logo-mark { width: 3.1em; margin: 0 0 .2em; }
.logo-line--1 { font-family: var(--font-ui); font-weight: 500; font-size: .48em; text-transform: uppercase;
  letter-spacing: .5em; margin-top: .38em; padding-left: .5em; /* balances the trailing tracking */ }

/* The hero scrim as a per-client knob. Falls back to the master's gradient. */
.hero__scrim { background: var(--hero-scrim, linear-gradient(180deg, rgba(28,24,23,.42) 0%, rgba(28,24,23,.06) 34%, rgba(28,24,23,.40) 100%)); }
.hero__title, .hero__eyebrow, .hero__sub { text-shadow: var(--hero-text-shadow, none); }

/* ---------------------------------------------------------------------------
   Custom select (app.js): a styled button + listbox over a hidden native
   select. The button reuses .ffield__input, so the closed state is unchanged.
   --------------------------------------------------------------------------- */
.cselect { position: relative; }
.cselect__native { position: absolute; left: 0; bottom: 0; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.cselect__btn { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  text-align: left; cursor: pointer; }
.cselect__value.is-placeholder { color: var(--t-secondary); }
.cselect__chev { display: grid; place-items: center; transition: transform var(--dur-ui) var(--ease); }
.cselect.is-open .cselect__chev { transform: rotate(180deg); }
.cselect.is-open .cselect__btn { border-bottom-color: var(--t-heading); }
.cselect.is-invalid .cselect__btn { border-bottom-color: var(--c-error); }
.cselect__list {
  position: absolute; left: -10px; right: -10px; top: calc(100% + 8px); z-index: 20;
  margin: 0; padding: 8px; list-style: none; max-height: 280px; overflow-y: auto;
  background: var(--c-warm-white); border-radius: var(--radius-md);
  box-shadow: 0 24px 50px -18px rgba(0, 0, 0, .35), 0 0 0 1px var(--t-line);
  transform-origin: 50% 0; animation: cselIn .28s var(--ease) both; outline: none;
}
.cselect__list[hidden] { display: none; }
@keyframes cselIn { from { opacity: 0; transform: translateY(-6px) scale(.98); } }
.cselect__opt {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 46px; padding: 10px 14px; border-radius: calc(var(--radius-md) - 6px);
  font-size: 1.6rem; line-height: 1.3; color: var(--t-heading); cursor: pointer;
  transition: background .15s;
}
.cselect__opt.is-active { background: var(--c-warm-light-beige); }
.cselect__tick { color: var(--c-warm-brown); opacity: 0; flex: none; }
.cselect__opt[aria-selected="true"] { font-weight: 500; }
.cselect__opt[aria-selected="true"] .cselect__tick { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .cselect__list { animation: none; } .cselect__chev { transition: none; } }

/* =============================================================================
   GALLERY (section type `gallery`) — rail of project photos + lightbox
   ========================================================================== */
.gallery__head { display: flex; align-items: flex-end; justify-content: space-between; gap: 40px;
  margin-bottom: clamp(30px, 4vw, 56px); }
.gallery__intro { margin-top: 22px; max-width: 46ch; }
.gallery__tools { display: flex; align-items: center; gap: 24px; flex: none; }
.gallery__filters { display: flex; gap: 8px; flex-wrap: wrap; }
.gallery__filter {
  min-height: 44px; padding: 0 18px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 1.4rem; letter-spacing: .02em; color: var(--t-heading);
  background: none; border: 1px solid color-mix(in srgb, var(--t-heading) 22%, transparent);
  transition: background-color var(--dur-ui) var(--ease), color var(--dur-ui) var(--ease), border-color var(--dur-ui);
}
.gallery__filter:hover { border-color: var(--t-heading); }
.gallery__filter.is-on { background: var(--t-heading); color: var(--t-background); border-color: var(--t-heading); }

.gallery__rail {
  display: flex; gap: clamp(12px, 1.4vw, 20px); padding-inline: var(--layout-padding);
  overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: var(--layout-padding);
  scrollbar-width: none; overscroll-behavior-x: contain; outline: none;
}
.gallery__rail::-webkit-scrollbar { display: none; }
.gallery__rail::after { content: ""; flex: 0 0 1px; }
@media (hover: hover) and (pointer: fine) {
  .gallery__rail { cursor: grab; }
  .gallery__rail.is-dragging { cursor: grabbing; }
  .gallery__rail.is-dragging .gallery__open { pointer-events: none; }
}
.gallery__rail:focus-visible { box-shadow: inset 0 0 0 2px var(--c-warm-brown); }
.gallery__item { flex: 0 0 clamp(250px, 23vw, 360px); margin: 0; scroll-snap-align: start; }
.gallery__item[hidden] { display: none; }
.gallery__open {
  position: relative; display: block; width: 100%; padding: 0; border: 0; cursor: zoom-in;
  aspect-ratio: 4 / 5; border-radius: var(--radius-md); overflow: hidden; background: var(--c-cool-light-gray);
}
.gallery__open img { width: 100%; height: 100%; object-fit: cover; display: block; user-select: none;
  transition: transform .9s var(--ease); }
.gallery__open::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 55%, rgba(23, 21, 19, .35)); opacity: 0; transition: opacity var(--dur-ui); }
.gallery__zoom { position: absolute; right: 14px; bottom: 14px; z-index: 1; width: 44px; height: 44px;
  display: grid; place-items: center; border-radius: 50%; color: #fff;
  background: rgba(23, 21, 19, .55); backdrop-filter: blur(6px);
  opacity: 0; transform: translateY(6px) scale(.9); transition: opacity var(--dur-ui), transform var(--dur-ui) var(--ease); }
.gallery__open:hover img, .gallery__open:focus-visible img { transform: scale(1.045); }
.gallery__open:hover::after, .gallery__open:focus-visible::after { opacity: 1; }
.gallery__open:hover .gallery__zoom, .gallery__open:focus-visible .gallery__zoom { opacity: 1; transform: none; }
.gallery__open:focus-visible { outline: 2px solid var(--c-warm-brown); outline-offset: 3px; }
@media (hover: none) { .gallery__zoom { opacity: 1; transform: none; } }
.gallery__cap { display: flex; flex-direction: column; gap: 6px; padding: 14px 4px 0; }
.gallery__tag { color: var(--c-warm-brown); text-transform: uppercase; letter-spacing: .12em; }
.gallery__title { font-size: 1.6rem; line-height: 1.35; color: var(--t-heading); }
.gallery__foot { display: flex; align-items: center; gap: 30px; margin-top: clamp(26px, 3vw, 40px); }
.gallery__progress { flex: 1; height: 2px; background: color-mix(in srgb, var(--t-heading) 14%, transparent); overflow: hidden; }
.gallery__progress span { display: block; height: 100%; background: var(--c-warm-brown);
  transform-origin: 0 50%; transform: scaleX(.2); transition: transform .2s linear; }
.gallery__cta { flex: none; }
@media (max-width: 899px) {
  .gallery__head { flex-direction: column; align-items: flex-start; gap: 22px; }
  .gallery__nav { display: none; }
}
@media (max-width: 767px) {
  .gallery__item { flex-basis: 72vw; }
  .gallery__foot { flex-direction: column; align-items: stretch; gap: 22px; }
  .gallery__cta { justify-content: center; }
}

/* lightbox */
.lbox { position: fixed; inset: 0; z-index: 95; display: grid; place-items: center;
  background: rgba(14, 13, 12, .94); opacity: 0; transition: opacity .3s var(--ease-op); }
.lbox[hidden] { display: none; }
.lbox.is-open { opacity: 1; }
.lbox__stage { width: 100%; height: 100%; display: grid; place-items: center; padding: 70px 90px 80px; }
.lbox__fig { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 16px; max-width: 100%; max-height: 100%; }
.lbox__img { max-width: min(1400px, 100%); max-height: calc(100svh - 190px); width: auto; height: auto;
  border-radius: var(--radius-sm); box-shadow: 0 30px 80px rgba(0, 0, 0, .5);
  transition: opacity .25s var(--ease-op), transform .45s var(--ease); }
.lbox.is-loading .lbox__img { opacity: .35; transform: scale(.985); }
.lbox__cap { color: rgba(255, 255, 255, .88); font-size: 1.5rem; text-align: center; display: flex; gap: 12px; align-items: center; }
.lbox__tag { color: var(--c-gold, #c9a227); text-transform: uppercase; letter-spacing: .12em; }
.lbox__count { position: absolute; top: 26px; left: 50%; transform: translateX(-50%); color: rgba(255, 255, 255, .7); letter-spacing: .1em; }
.lbox__btn { position: absolute; width: 52px; height: 52px; display: grid; place-items: center; border-radius: 50%;
  color: #fff; background: rgba(255, 255, 255, .08); border: 1px solid rgba(255, 255, 255, .22); cursor: pointer;
  font-size: 1.8rem; transition: background-color .2s, border-color .2s; }
.lbox__btn:hover, .lbox__btn:focus-visible { background: rgba(255, 255, 255, .16); border-color: rgba(255, 255, 255, .6); outline: none; }
.lbox__btn svg { width: 20px; height: 20px; }
.lbox__close { top: 16px; right: 16px; }
.lbox__prev { left: 22px; top: 50%; transform: translateY(-50%); }
.lbox__prev svg { transform: rotate(180deg); }
.lbox__next { right: 22px; top: 50%; transform: translateY(-50%); }
@media (max-width: 767px) {
  .lbox__stage { padding: 64px 12px 120px; }
  .lbox__img { max-height: calc(100svh - 230px); }
  .lbox__prev, .lbox__next { top: auto; bottom: 28px; transform: none; }
  .lbox__prev { left: calc(50% - 64px); } .lbox__next { right: calc(50% - 64px); }
}
@media (prefers-reduced-motion: reduce) {
  .lbox, .lbox__img, .gallery__open img, .gallery__zoom { transition: none; }
}

/* =============================================================================
   TESTIMONIALS (section type `testimonials`) — rating summary + cards
   ========================================================================== */
.tmon { position: relative; overflow: hidden; }
.tmon__inner { position: relative; }
.tmon__head { display: flex; align-items: flex-end; justify-content: space-between; gap: 30px;
  margin-bottom: clamp(32px, 4vw, 60px); }
.tmon__score { display: flex; align-items: center; gap: 16px; flex: none; }
.tmon__avg { font-family: var(--font-display); font-size: clamp(4.4rem, 5vw, 6.4rem); line-height: 1; color: var(--t-heading); }
.tmon__stars { display: inline-flex; gap: 2px; color: var(--c-gold, #c9a227); }
.tmon__count { display: block; margin-top: 6px; color: var(--t-secondary); }
.tmon__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: clamp(14px, 1.6vw, 24px); outline: none; }
.tmon__card { margin: 0; display: flex; flex-direction: column; gap: 20px; padding: clamp(24px, 2.2vw, 34px);
  border-radius: var(--radius-lg); background: var(--c-warm-white);
  box-shadow: 0 1px 0 rgba(23, 21, 19, .04), 0 20px 50px -30px rgba(23, 21, 19, .35); }
.tmon__card-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.tmon__project { color: var(--c-warm-brown); text-transform: uppercase; letter-spacing: .12em; }
.tmon__quote { margin: 0; flex: 1; color: var(--c-cool-dark-blue); }
.tmon__who { display: flex; align-items: center; gap: 12px; padding-top: 18px; border-top: 1px solid var(--c-cool-light-gray); }
.tmon__avatar { width: 42px; height: 42px; flex: none; border-radius: 50%; display: grid; place-items: center;
  font-family: var(--font-display); font-size: 1.8rem; color: var(--c-gold, #c9a227); background: var(--c-cool-dark-blue); }
.tmon__name { display: block; font-weight: 500; color: var(--c-cool-dark-blue); }
.tmon__place { display: block; color: var(--c-cool-gray-blue); }
@media (max-width: 767px) {
  .tmon__head { flex-direction: column; align-items: flex-start; gap: 18px; }
  /* phones: a swipe row, each card most of the screen wide */
  .tmon__grid { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
    margin-inline: calc(var(--layout-padding) * -1); padding-inline: var(--layout-padding);
    scroll-padding-inline: var(--layout-padding); }
  .tmon__grid::-webkit-scrollbar { display: none; }
  .tmon__card { flex: 0 0 84vw; scroll-snap-align: start; }
}
/* the chat launcher steps aside while a photo is open */
.lbox-open .echat-launch { visibility: hidden; }

/* Branded gallery cursor (mouse only; app.js adds .has-gcur to the rail). */
.gallery__rail.has-gcur, .gallery__rail.has-gcur .gallery__open { cursor: none; }
.gcur { position: fixed; left: 0; top: 0; z-index: 60; pointer-events: none; width: 0; height: 0; }
.gcur::before { content: ""; position: absolute; left: -36px; top: -36px; width: 72px; height: 72px; border-radius: 50%;
  background: var(--c-cool-dark-blue); box-shadow: inset 0 0 0 1px rgba(201, 162, 39, .6), 0 12px 30px -10px rgba(23, 21, 19, .55);
  transform: scale(0); opacity: 0; transition: transform .35s var(--ease), opacity .25s var(--ease-op); }
.gcur__label { position: absolute; left: 0; top: 0; transform: translate(-50%, -50%); white-space: nowrap;
  font: 500 1.3rem/1 var(--font-ui); letter-spacing: .12em; text-transform: uppercase; color: var(--c-gold, #c9a227);
  opacity: 0; transition: opacity .2s; }
.gcur.is-on::before { transform: scale(.62); opacity: 1; }
.gcur.is-on.is-photo::before { transform: scale(1.18); }
.gcur.is-on.is-drag::before { transform: scale(1.05, .9); }
.gcur.is-on.is-press::before { transform: scale(.95); }
.gcur.is-on .gcur__label { opacity: 1; }
.gcur.is-on:not(.is-photo):not(.is-drag) .gcur__label { font-size: 1.1rem; }
.gallery__rail.has-gcur .gallery__zoom { display: none; } /* the cursor says it now */
@media (prefers-reduced-motion: reduce) { .gcur::before, .gcur__label { transition: none; } }

/* testimonials swipe row: dots (app.js) and a drag cursor when it scrolls */
.tmon__dots { display: flex; justify-content: center; gap: 2px; margin-top: 18px; }
.tmon__dots[hidden] { display: none; }
@media (max-width: 767px) { .tmon__grid { cursor: grab; touch-action: pan-x pan-y; } .tmon__grid.is-dragging { cursor: grabbing; } }
.tmon__grid.is-dragging { user-select: none; }

/* Horizontal rails scroll sideways only. overflow-x: auto computes overflow-y
   to auto as well, so a reveal offset, a hover lift or a shadow that pokes
   past the row let it be dragged up and down on touch. */
.tmon__grid, .gallery__rail, .services__rail, .track__rail { overflow-y: hidden; overscroll-behavior-y: auto; }
@media (max-width: 767px) {
  .tmon__grid { touch-action: pan-x pan-y; padding-top: 6px; padding-bottom: 36px; margin-bottom: -30px; }
}
