/* ==========================================================================
   LUSSO — Window Furnishings
   Design system
   ========================================================================== */

:root {
  /* ---- Brand palette (brand-guidelines.md — do not invent new colours) ---- */
  --paper:      #F7F7F6;   /* Base background, cool off-white */
  --mist:       #DEDFDC;   /* Light tint / dividers / secondary surfaces */
  --stone:      #8C8E8B;   /* Mid grey — labels and captions ON INK only */
  --graphite:   #3A3B3C;   /* Body text on light backgrounds */
  --ink:        #101113;   /* Anchor — near-true-black */
  --bronze:     #6E5A43;   /* Accent ONLY — thin rules, marks, eyebrows, hover */

  /* ---- Working aliases ----
     Brand Stone is 3.08:1 on Paper and 2.47:1 on Mist, so it cannot carry
     small text on light backgrounds without failing WCAG AA. Stone is used
     verbatim on ink (5.72:1); --muted is Stone darkened along the same
     neutral hue for light backgrounds (5.66:1 on Paper, 4.53:1 on Mist).
     Bronze is the mirror case: 6.11:1 on Paper but 2.88:1 on Ink, so dark
     sections use --bronze-soft, the same hue lifted to 5.72:1. */
  --ink-deep:   #101113;   /* One black only — depth comes from hairlines */
  --ink-soft:   var(--graphite);
  --mist-deep:  #EAEBE8;
  --line:       var(--mist);
  --line-dark:  rgba(255,255,255,.16);
  --muted:      #616360;
  --muted-dark: var(--stone);
  --brass:      var(--bronze);
  --brass-soft: #A08A6E;

  /* ---- Type — one family only ---- */
  --font-body:    'Manrope', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  --font-ui:      var(--font-body);
  --font-display: var(--font-body);

  /* Metrics */
  --container: 1280px;
  --gutter: 28px;
  --header-h: 92px;
  --ease: cubic-bezier(.22,.61,.36,1);

  /* ======================================================================
     DESIGN TOKENS — the single source of truth for size and rhythm.
     ----------------------------------------------------------------------
     These values are the DESKTOP/TABLET end of the scale. The mobile end is
     redefined in the @media block immediately below, so changing a size for
     the whole site means editing one of two places, never a component.

     Components must reference these rather than hard-coding px. If you find
     yourself writing `font-size: 21px` in a component, add a token instead.
     See DESIGN-SYSTEM.md.
     ====================================================================== */

  /* Type scale */
  --t-display:  clamp(38px, 5.4vw, 76px);
  --t-h2:       clamp(21px, 2.3vw, 30px);
  --t-h2-ls:    .07em;
  --t-h3:       clamp(18px, 1.7vw, 22px);
  --t-lead:     clamp(17px, 1.35vw, 19.5px);
  --t-lead-lh:  1.8;
  --t-kicker:   clamp(14px, 1.5vw, 17px);
  --t-eyebrow:  12px;
  --t-ui:       12.5px;      /* buttons, link-u, nav, meta rows */
  --t-body-sm:  15.4px;      /* card excerpts, cap/step copy, list rows */
  --t-prose:    17px;        /* article body — deliberately above UI text */
  --t-prose-lh: 1.82;

  /* Vertical rhythm */
  --space-section:       clamp(72px, 9vw, 132px);
  --space-section-tight: clamp(56px, 6vw, 88px);
  --space-stack:         36px;   /* heading block -> button / list below it */
  --space-eyebrow:       22px;   /* eyebrow -> whatever follows */
  --space-kicker:        10px;
  --space-grid:          64px;   /* section intro -> a grid of columns */
  --space-sec-head:      48px;   /* .sec-head: intro block -> tiles/gallery */
  --space-sec-head-sm:   36px;   /* .sec-head--sm: the tighter variant */
  --space-display-tight: 24px;   /* .display--tight: display -> body copy */

  /* Panel padding — quote cards, callouts, feature bodies, CTA blocks */
  --pad-panel:    clamp(32px, 3.4vw, 46px);
  --pad-panel-sm: clamp(24px, 3vw, 34px);

  /* Buttons. --btn-min-h is an accessibility floor: never reduce it. */
  --btn-py:    17px;
  --btn-px:    34px;
  --btn-fs:    12.5px;
  --btn-ls:    .2em;
  --btn-min-h: 48px;
  --btn-wrap:  nowrap;
}

/* ==========================================================================
   MOBILE TOKENS — the mobile-first end of every scale above.
   Nothing here is a "shrink everything" override: each value was chosen for a
   ~375-430px viewport and meets its desktop counterpart exactly at 721px, so
   there is no jump across the breakpoint.

   TO RESIZE THE SITE ON MOBILE, EDIT HERE — not in a component.
   ========================================================================== */
@media (max-width: 720px) {
  :root {
    --t-display:  clamp(27px, 6.5vw, 39px);
    --t-h2:       clamp(18px, 3.4vw, 21px);
    --t-h2-ls:    .06em;
    --t-h3:       clamp(16.5px, 3vw, 18px);
    --t-lead:     clamp(16px, 2.4vw, 17px);
    --t-lead-lh:  1.7;
    --t-kicker:   clamp(13px, 2vw, 14px);
    --t-eyebrow:  11px;
    --t-ui:       11.5px;
    --t-body-sm:  15px;
    --t-prose:    16.5px;
    --t-prose-lh: 1.72;

    --space-section:       clamp(44px, 11vw, 72px);
    --space-section-tight: clamp(36px, 9vw, 56px);
    --space-stack:         24px;
    --space-eyebrow:       14px;
    --space-kicker:        8px;
    --space-grid:          36px;
    --space-sec-head:      26px;
    --space-sec-head-sm:   22px;
    --space-display-tight: 14px;

    --pad-panel:    clamp(22px, 5vw, 32px);
    --pad-panel-sm: clamp(18px, 4vw, 24px);

    --btn-py:   13px;
    --btn-px:   22px;
    --btn-fs:   11.5px;
    --btn-ls:   .14em;
    --btn-wrap: normal;   /* long CTAs wrap instead of overflowing the screen */
  }
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.7;
  color: var(--graphite);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}
/* `clip` contains sideways overflow exactly as `hidden` does, but without making
   the body a scroll container — which would break the sticky article TOC. */
@supports (overflow: clip) { body { overflow-x: clip; } }

/* Long words, URLs and product codes must not push narrow layouts sideways. */
h1, h2, h3, h4, h5, h6, p, li, a, dt, dd, th, td, blockquote, figcaption {
  overflow-wrap: break-word;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
/* Removes the 300ms double-tap-to-zoom delay on anything tappable. */
a, button, summary, label, input[type="checkbox"] { touch-action: manipulation; }
ul { margin: 0; padding: 0; list-style: none; }
address { font-style: normal; }
h1, h2, h3, h4, h5, h6 { margin: 0; font-weight: 400; }
:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; }

/* ---------- Layout ---------- */
/* Gutters absorb the notch insets so nothing hides under a rounded corner or
   camera cutout in landscape. The insets are 0 on every non-notched device. */
.container {
  width: 100%; max-width: var(--container); margin-inline: auto;
  padding-inline:
    calc(var(--gutter) + env(safe-area-inset-left, 0px))
    calc(var(--gutter) + env(safe-area-inset-right, 0px));
}
.container--narrow { max-width: 940px; }
.section { padding-block: var(--space-section); }
.section--tight { padding-block: var(--space-section-tight); }
.section--dark { background: var(--ink); color: #fff; }
.section--deep { background: var(--ink-deep); color: #fff; }
.section--mist { background: var(--mist); }
.section--dark p, .section--deep p { color: var(--muted-dark); }

/* ---------- Type scale ---------- */
.eyebrow {
  font-family: var(--font-ui);
  font-size: var(--t-eyebrow);
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--brass);
  margin: 0 0 var(--space-eyebrow);
}
.section--dark .eyebrow, .section--deep .eyebrow { color: var(--brass-soft); }

.kicker {
  font-family: var(--font-ui);
  font-size: var(--t-kicker);
  font-weight: 400;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 var(--space-kicker);
  line-height: 1.6;
}
.section--dark .kicker, .section--deep .kicker { color: var(--muted-dark); }

/* The signature Lusso move: uppercase kicker above a large Manrope Light line */
.display {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--t-display);
  line-height: 1.06;
  letter-spacing: -.5px;
  color: var(--ink);
  margin: 0;
}
.section--dark .display, .section--deep .display, .hero .display { color: #fff; }

.h2 {
  font-family: var(--font-ui);
  font-size: var(--t-h2);
  font-weight: 400;
  line-height: 1.32;
  letter-spacing: var(--t-h2-ls);
  text-transform: uppercase;
  color: var(--ink);
}
.section--dark .h2, .section--deep .h2 { color: #fff; }

.h3 {
  font-family: var(--font-ui);
  font-size: var(--t-h3);
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: .02em;
  color: var(--ink);
}
.section--dark .h3, .section--deep .h3 { color: #fff; }

.lead { font-size: var(--t-lead); line-height: var(--t-lead-lh); color: var(--muted); }
.section--dark .lead, .section--deep .lead { color: var(--muted-dark); }
p { margin: 0 0 1.15em; }
p:last-child { margin-bottom: 0; }

.rule { width: 54px; height: 1px; background: var(--brass); border: 0; margin: 0 0 26px; }
.rule--center { margin-inline: auto; }

/* ---------- Buttons ---------- */
.btn {
  --btn-bg: var(--ink);
  --btn-fg: #fff;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-ui);
  font-size: var(--btn-fs);
  font-weight: 500;
  letter-spacing: var(--btn-ls);
  text-transform: uppercase;
  padding: var(--btn-py) var(--btn-px);
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-bg);
  transition: background .38s var(--ease), color .38s var(--ease), border-color .38s var(--ease);
  /* nowrap on desktop, normal on mobile: at 375px a long CTA at full tracking
     computes wider than the viewport and was being silently clipped by
     body{overflow-x:clip}. */
  white-space: var(--btn-wrap);
}
.btn:hover { background: transparent; color: var(--btn-bg); }
.btn--light { --btn-bg: #fff; --btn-fg: var(--ink); }
.btn--light:hover { background: transparent; color: #fff; border-color: #fff; }
.btn--outline { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn--outline:hover { background: var(--ink); color: #fff; }
.btn--outline-light { background: transparent; color: #fff; border-color: rgba(255,255,255,.42); }
.btn--outline-light:hover { background: #fff; color: var(--ink); border-color: #fff; }
/* Bronze rule: never a fill. This button wears bronze as a hairline only. */
.btn--brass { background: transparent; color: var(--brass); border-color: var(--brass); }
.btn--brass:hover { background: var(--brass); color: var(--paper); }
.btn .arw { transition: transform .38s var(--ease); }
.btn:hover .arw { transform: translateX(5px); }

/* Text link with animated underline */
.link-u {
  font-family: var(--font-ui);
  font-size: var(--t-ui);
  font-weight: 500;
  letter-spacing: var(--btn-ls);
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding-bottom: 6px;
  position: relative;
  border-bottom: 1px solid currentColor;
  transition: gap .38s var(--ease), color .3s var(--ease);
}
.link-u:hover { gap: 16px; color: var(--brass); }

/* ==========================================================================
   Header
   ========================================================================== */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 200;
  height: var(--header-h);
  display: flex;
  align-items: center;
  transition: background .4s var(--ease), height .4s var(--ease), box-shadow .4s var(--ease), border-color .4s var(--ease);
  border-bottom: 1px solid transparent;
}
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(0,0,0,.55), rgba(0,0,0,0));
  opacity: 1;
  transition: opacity .4s var(--ease);
  pointer-events: none;
}
.site-header.is-stuck,
.site-header.is-solid {
  background: var(--paper);
  height: 74px;
  border-bottom-color: var(--line);
  box-shadow: 0 8px 34px rgba(0,0,0,.06);
}
.site-header.is-stuck::before, .site-header.is-solid::before { opacity: 0; }

.header-inner { display: flex; align-items: center; gap: 34px; width: 100%; }

/* Logo — the wordmark is a knocked-out lockup, so it is never recoloured.
   Two files only: white over the dark hero, ink once the header goes to paper.
   Both are in the DOM so the swap costs no request at scroll time; the pair is
   under 9 KB. Width is above the 110px brand minimum and the intrinsic
   width/height attributes keep the header free of layout shift. */
.brand { display: block; position: relative; line-height: 0; flex: none; }
.brand__logo {
  display: block;
  width: 112px;          /* brand minimum is 110px wide — do not go under */
  height: auto;
  aspect-ratio: 1600 / 470;
  transition: opacity .4s var(--ease);
}
/* Stacked rather than toggled with display:none, so the pair crossfades with
   the rest of the header and both keep a real layout box. */
.header-inner .brand__logo--ink {
  position: absolute;
  inset: 0;
  opacity: 0;
}
.is-stuck .brand__logo--white, .is-solid .brand__logo--white,
body.nav-open .brand__logo--white { opacity: 0; }
.is-stuck .brand__logo--ink, .is-solid .brand__logo--ink,
body.nav-open .brand__logo--ink { opacity: 1; }
/* Clear space: half the wordmark height on every side. */
.header-inner .brand { padding-right: 20px; }

/* Nav */
.nav { margin-left: auto; }
.nav__list { display: flex; align-items: center; gap: 34px; }
.nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #fff;
  padding-block: 10px;
  transition: color .3s var(--ease), opacity .3s var(--ease);
}
.is-stuck .nav__link, .is-solid .nav__link { color: var(--ink); }
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 2px;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .4s var(--ease);
}
.nav__link:hover::after,
.nav__item.is-current > .nav__link::after { transform: scaleX(1); transform-origin: left; }
.nav__caret { width: 8px; height: 8px; opacity: .7; transition: transform .35s var(--ease); }
.nav__item:hover .nav__caret { transform: rotate(180deg); }

/* Dropdown */
.nav__item--has-menu { position: relative; }
.submenu {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translate(-50%, 12px);
  min-width: 268px;
  background: var(--paper);
  border: 1px solid var(--line);
  box-shadow: 0 26px 60px rgba(0,0,0,.13);
  padding: 14px 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity .32s var(--ease), transform .32s var(--ease), visibility .32s;
}
.nav__item--has-menu:hover .submenu,
.nav__item--has-menu:focus-within .submenu {
  opacity: 1; visibility: visible; transform: translate(-50%, 0);
}
.submenu::before { content: ""; position: absolute; top: -14px; left: 0; right: 0; height: 14px; }
.submenu a {
  display: block;
  padding: 10px 28px;
  font-family: var(--font-body);
  font-size: 14.5px;
  font-weight: 300;
  color: var(--ink-soft);
  transition: background .25s, color .25s, padding-left .3s var(--ease);
}
.submenu a:hover { background: var(--mist); color: var(--ink); padding-left: 34px; }
.submenu__title {
  padding: 8px 28px 6px;
  font-family: var(--font-ui);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--brass);
}
.submenu__sep { height: 1px; background: var(--line); margin: 12px 0; }

/* Header actions */
.header-actions { display: flex; align-items: center; gap: 22px; flex: none; }
.header-phone {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--font-ui); font-size: 13px; font-weight: 500; letter-spacing: .08em;
  color: #fff; transition: color .4s var(--ease), opacity .3s;
}
.header-phone:hover { opacity: .72; }
.is-stuck .header-phone, .is-solid .header-phone { color: var(--ink); }
.header-cta { padding: 14px 26px; font-size: 11.5px; }
.header-cta.btn--light { --btn-bg: #fff; --btn-fg: var(--ink); }
.is-stuck .header-cta, .is-solid .header-cta { --btn-bg: var(--ink); --btn-fg: #fff; }
.is-stuck .header-cta:hover, .is-solid .header-cta:hover { background: transparent; color: var(--ink); border-color: var(--ink); }

/* Burger — 48x48 hit area, 30x20 of visible bars centred inside it.
   The negative margin keeps the bars optically aligned to the gutter. */
.burger {
  display: none;
  width: 48px; height: 48px;
  position: relative; flex: none;
  margin-right: -9px;
}
.burger span {
  position: absolute; left: 9px; height: 1.5px; width: 30px; background: #fff;
  transition: transform .38s var(--ease), opacity .25s, background .4s var(--ease);
}
.burger span:nth-child(1) { top: 14px; }
.burger span:nth-child(2) { top: 23px; }
.burger span:nth-child(3) { top: 32px; }
.is-stuck .burger span, .is-solid .burger span { background: var(--ink); }
body.nav-open .burger span { background: var(--ink); }
/* The drawer is Ink, so the header holds its own Paper bar above it — the
   wordmark keeps its light background and the bars read as a dark close mark. */
body.nav-open .site-header::before { opacity: 0; }
body.nav-open .site-header {
  background: var(--paper);
  border-bottom-color: var(--line);
}
body.nav-open .burger span:nth-child(1) { transform: translateY(9px) rotate(45deg); }
body.nav-open .burger span:nth-child(2) { opacity: 0; }
body.nav-open .burger span:nth-child(3) { transform: translateY(-9px) rotate(-45deg); }

/* ---------- Mobile drawer ----------
   An Ink panel that drops from beneath the Paper header bar and is only as tall
   as its contents, so the page stays visible underneath. Ink is one of the two
   permitted surfaces; Bronze appears only as the hairline under the panel and
   as the colour of the one open row — a mark, never a fill. */
.drawer {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 190;
  max-height: 100dvh;
  background: var(--ink);
  color: #fff;
  border-bottom: 1px solid var(--bronze);
  box-shadow: 0 30px 60px rgba(0,0,0,.28);
  /* Insets keep the panel clear of the notch, the home indicator and the
     rounded corners when the drawer is open in either orientation. */
  padding:
    calc(var(--header-h) + 16px + env(safe-area-inset-top, 0px))
    calc(var(--gutter) + env(safe-area-inset-right, 0px))
    calc(30px + env(safe-area-inset-bottom, 0px))
    calc(var(--gutter) + env(safe-area-inset-left, 0px));
  overflow-y: auto;
  overscroll-behavior: contain;   /* drawer scrolling never chains to the page */
  -webkit-overflow-scrolling: touch;
  transform: translateY(-100%);
  visibility: hidden;
  /* On close, visibility is held until the slide-out finishes; on open it flips
     immediately, so the panel is focusable on the very first frame. Transitioning
     visibility as a duration instead left it hidden while JS moved focus in. */
  transition: transform .55s var(--ease), visibility 0s linear .55s;
}
body.nav-open .drawer {
  transform: translateY(0);
  visibility: visible;
  transition: transform .55s var(--ease), visibility 0s linear 0s;
}
body.nav-open { overflow: hidden; }
/* Rows carry no dividers — spacing does the separating, as everywhere else on
   the site. The chevron sits against the label rather than out at the right
   edge, so the eye reads label-then-affordance in one move. */
.drawer__link {
  display: flex; align-items: center; justify-content: flex-start; gap: 11px;
  min-height: 48px;               /* full-width, thumb-sized row */
  padding: 7px 0;
  font-family: var(--font-ui);
  font-size: 14px; font-weight: 500; letter-spacing: .16em; text-transform: uppercase;
  color: #fff;
  width: 100%; text-align: left;
  transition: color .28s var(--ease), opacity .28s var(--ease);
}

/* Chevrons are drawn from two borders on a rotated box — no extra markup, so
   this reaches every page and both templates without touching their HTML. */
.drawer__link::after,
.drawer__sub a::after {
  content: "";
  flex: none;
  width: 6px; height: 6px;
  border-right: 1.4px solid currentColor;
  border-bottom: 1.4px solid currentColor;
  opacity: .6;
  transition: transform .35s var(--ease), opacity .28s var(--ease);
}
/* A link points onward: › */
a.drawer__link::after,
.drawer__sub a::after { transform: rotate(-45deg); }
/* A group points down, and flips up once it is open: ⌄ */
.drawer__group > .drawer__link::after { transform: translateY(-2px) rotate(45deg); }
.drawer__group.is-open > .drawer__link::after { transform: translateY(2px) rotate(-135deg); opacity: 1; }

/* The open branch is the single Bronze mark in the panel. */
.drawer__group.is-open > .drawer__link { color: var(--brass-soft); }

.drawer__sub { max-height: 0; overflow: hidden; transition: max-height .45s var(--ease); }
/* Generous, because a level-2 group opening inside this one has to fit too. */
.drawer__group.is-open > .drawer__sub { max-height: 1400px; }

/* Level 2 — a group nested inside Products (Curtains / Blinds / Shutters). */
.drawer__sub .drawer__group > .drawer__link {
  min-height: 48px;
  padding: 5px 0 5px 15px;
  font-size: 12.5px;
  letter-spacing: .14em;
  color: rgba(255,255,255,.72);
}
.drawer__sub .drawer__group.is-open > .drawer__link { color: var(--brass-soft); }
.drawer__sub .drawer__group.is-open > .drawer__sub { max-height: 620px; }

/* Level 3 — the product links themselves, indented once more. */
.drawer__sub .drawer__sub a {
  padding-left: 30px;
  font-size: 12px;
  color: rgba(255,255,255,.6);
}
.drawer__sub a {
  display: flex; align-items: center; gap: 10px;
  min-height: 48px;
  padding: 5px 0 5px 15px;
  font-family: var(--font-ui);
  font-size: 12.5px; font-weight: 500; letter-spacing: .14em; text-transform: uppercase;
  color: rgba(255,255,255,.72);
  transition: color .28s var(--ease);
}

/* Touch devices get no hover, so :active is the only press feedback available. */
.drawer__link:active, .drawer__sub a:active { color: var(--brass-soft); }
.drawer__sub a:active::after { opacity: 1; }

/* The old "+" marker is replaced by the chevrons above. It is still in the
   markup of every page, so it is hidden here rather than edited out of each. */
.plus { display: none; }

/* Buttons sit on Ink here, so they take the light treatment. */
.drawer__foot { margin-top: 30px; display: grid; gap: 12px; }
.drawer__foot .btn { --btn-bg: #fff; --btn-fg: var(--ink); }
.drawer__foot .btn:hover { background: transparent; color: #fff; border-color: #fff; }
.drawer__foot .btn--outline {
  --btn-bg: transparent;
  background: transparent; color: #fff; border-color: rgba(255,255,255,.42);
}
.drawer__foot .btn--outline:hover { background: #fff; color: var(--ink); border-color: #fff; }

/* ==========================================================================
   Hero
   ========================================================================== */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  color: #fff;
  overflow: hidden;
  background: var(--ink-deep);
}
.hero__media { position: absolute; inset: 0; }
.hero__media img {
  width: 100%; height: 100%; object-fit: cover;
  transform: scale(1.12);
  animation: heroZoom 14s var(--ease) forwards;
}
@keyframes heroZoom { to { transform: scale(1); } }
/* Anchored to the copy corner, not laid across the frame — the scrim only
   darkens what has to be read over.

   Two versions, because the two heroes carry different amounts of copy. A
   service page stacks crumbs, an eyebrow, an H1, a lead paragraph and two
   buttons, and that block reaches past 60% of the frame height; the homepage
   carries one short beat down at the bottom. Running the homepage's gradient
   on a service page put white crumbs and a white H1 over an unscrimmed part
   of the still — measured at 1.0–1.2:1 against the generated hero stills,
   which are high-key by brand direction and offer nothing to read against.
   So the default reaches the top of the crumbs, and the homepage keeps the
   lower anchor it was tuned to. */
.hero__media::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(to top,
      rgba(10,10,10,.84) 0%,
      rgba(10,10,10,.66) 40%,
      rgba(10,10,10,.42) 64%,
      rgba(10,10,10,0) 88%);
}
/* The homepage hero takes a warm wash instead of the scrim above — low sun
   through the glass rather than a grey darkening. The default is a `.hero`
   rule, so the scrim has to be switched off rather than simply left unset, and
   this replaces it outright: one flat colour, multiplied.

   Homepage only, and scoped by the markup rather than by a class: `.hero-track`
   exists on index.html and nowhere else, so no page-level opt-in is needed.

   `multiply`, not `overlay`. The clip is a high-key interior — bright room,
   sheer curtains, sun off the water — and overlay treats everything above
   mid-grey as a screen, which leaves exactly the parts that should catch the
   light almost untouched. Multiply is the blend that actually casts colour
   onto a white, which is what low sun does to a sheer.

   THE z-index IS LOAD-BEARING. Left at `auto` this layer still paints — a
   solid colour on it covers the clip — but the blend silently does nothing:
   multiply at full strength comes back pixel-identical to no wash at all.
   Chromium only blends the pseudo-element against the footage beneath once it
   is an explicit member of the painting order. 1 puts it over the clip and
   under every piece of hero copy (.hero__inner and .hero__beat sit at 2, the
   progress rail at 3). Do not remove it as redundant.

   It also slightly deepens the frame, which the white unshielded copy over it
   only benefits from — see .hero__inner.

   Strength was picked against the clip rather than by eye: below about 0.25
   the cast barely registers on a frame with this much daylight in it, and
   above about 0.40 the ocean stops reading as ocean and the blinds stop
   reading as white — which is the product. 0.30 is warm enough to be the
   point of the shot and light enough to leave both intact. */
.hero-track .hero__media::after {
  background: #E6965A;
  opacity: 0.3;
  mix-blend-mode: multiply;
  z-index: 1;
}
.hero__inner { position: relative; z-index: 2; width: 100%; padding-block: 0 clamp(56px, 8vh, 96px); padding-top: calc(var(--header-h) + 40px); }
.hero__seo {
  font-family: var(--font-ui);
  font-size: 11.5px; font-weight: 500; letter-spacing: .12em; text-transform: uppercase;
  color: var(--brass-soft);
  margin: 0 0 22px;
  display: flex; align-items: center; gap: 14px;
}
.hero__seo::before { content: ""; width: 42px; height: 1px; background: var(--brass-soft); }
.hero .display { max-width: 15ch; margin-bottom: 26px; }
.hero__copy { max-width: 52ch; font-size: clamp(16.5px, 1.35vw, 19px); color: rgba(255,255,255,.82); margin-bottom: 40px; }
.hero__actions { display: flex; flex-wrap: wrap; gap: 16px; }
.hero__scroll {
  position: absolute; right: var(--gutter); bottom: clamp(56px, 8vh, 96px); z-index: 2;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  font-family: var(--font-ui); font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  color: rgba(255,255,255,.62);
  writing-mode: vertical-rl;
}
.hero__scroll .bar { width: 1px; height: 62px; background: rgba(255,255,255,.34); position: relative; overflow: hidden; }
.hero__scroll .bar::after {
  content: ""; position: absolute; inset: 0; background: #fff;
  animation: scrollBar 2.4s var(--ease) infinite;
}
@keyframes scrollBar { 0% { transform: translateY(-100%); } 60%,100% { transform: translateY(100%); } }

/* ==========================================================================
   Intro screen (home only)
   --------------------------------------------------------------------------
   Black, the wordmark wiping in left to right, a line of place under it, then
   the whole plate scales up a touch and lifts off the page.

   Nothing here applies until `assets/js/boot.js` puts `is-intro` on <html>,
   which it only does on a first visit within a session. No JS, no class, no
   overlay — the page is simply the page. Timings are duplicated in that file;
   they have to agree or the plate will be removed mid-fade.

   z-index 400 clears the header (200) and the drawer (190) but deliberately
   sits under the skip link (500): if someone tabs during the intro, the one
   control that gets them into the page should still be visible.
   ========================================================================== */
.intro { display: none; }

.is-intro .intro {
  display: flex;
  position: fixed; inset: 0; z-index: 400;
  flex-direction: column; align-items: center; justify-content: center;
  background: #000;                /* the one true black — deeper than --ink */
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}

/* Locked only while the plate is opaque. The moment it starts lifting the
   page is the reader's again — the fade is scenery, not a modal. */
.is-intro:not(.is-intro-out),
.is-intro:not(.is-intro-out) body { overflow: hidden; }

.is-intro-out .intro { opacity: 0; transform: scale(1.06); pointer-events: none; }

.intro__mark { width: min(58vw, 340px); }
.intro__mark img {
  display: block; width: 100%; height: auto;
  clip-path: inset(0 100% 0 0);
  animation: introWipe .55s .05s var(--ease) forwards;
}
@keyframes introWipe { to { clip-path: inset(0 0 0 0); } }

.intro__place {
  margin-top: 22px;
  font-family: var(--font-ui); font-size: var(--t-eyebrow); font-weight: 500;
  letter-spacing: .32em; text-transform: uppercase;
  color: var(--brass-soft);
  opacity: 0;
  animation: introPlace .3s .35s ease forwards;
}
@keyframes introPlace { to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .intro__mark img { animation: none; clip-path: none; }
  .intro__place { animation: none; opacity: 1; }
  /* boot.js shortens the hold to match; .001ms transitions come from the
     global reduced-motion rule, so the lift is effectively a cut. */
}

/* ==========================================================================
   Hero — scroll-scrubbed reveal (home only)
   --------------------------------------------------------------------------
   The hero pins for the length of a taller track while the clip is scrubbed
   by scroll position: the room runs from midday to dusk as the reader moves
   down the page, and the drapery closes with them.

   Every rule below is inert until main.js adds `is-scrub`, which it only does
   on a fine-pointer desktop, off reduced motion, once the clip is decodable
   and while the reader is still at the top of the page. A phone, a reader who
   asked for less motion, a failed video request and a no-JS visit all keep
   exactly the image hero that ships in the HTML — same height, same copy.
   That is also why the track owns the extra height rather than the hero: the
   hero stays a 100svh section and the enhancement is one class on a wrapper.
   ========================================================================== */
.hero-track { position: relative; }
.hero-track .hero { position: sticky; top: 0; }

/* Scrub speed lives here and nowhere else. The hero is pinned at 100svh, so
   the scroll the clip is spread over is (this height - 100svh): at 400svh the
   15 s runs over 300svh of scrolling, half the pace the original 250svh set.
   Raise it to slow the scrub further, lower it to quicken. Everything that
   cares — the progress rail, the two copy beats, the header's pin-forgiveness
   in main.js — reads the track's measured height, so this is the only number.
   Phones never get `is-scrub` and are unaffected. */
.hero-track.is-scrub { height: 400svh; }
.hero-track.is-scrub .hero { height: 100svh; min-height: 0; }

/* `is-play` — the phone. The clip runs on its own once it is in view, so the
   track never grows, the hero never pins and the reader's scroll is never
   taken; only the backdrop changes. */
.hero-track.is-play .hero__video { opacity: 1; }

/* Sits over the still, under .hero__media::after. On the homepage that layer
   is now switched off and both are ungraded, which keeps the swap a dissolve
   for the same reason it was one before: still and clip are treated alike. */
.hero__video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  opacity: 0;
  transition: opacity .8s var(--ease);
}
.hero-track.is-scrub .hero__video { opacity: 1; }

/* Anything the clip's arrival must NOT change hangs off a media query rather
   than off `is-scrub`. Whatever only lands when the video is ready is, by
   definition, a visible change at the moment it lands — and the reader reads
   that as a flash on a hero that has already painted. This query has to stay
   in step with the <picture> and the preloads on index.html, and with
   `scrubQ`/`playQ`/`lessMotion` in main.js: between them these two queries
   describe exactly the viewports that open on a clip's own first frame. The
   gap they leave — a phone in landscape, too short to pin and too wide for a
   portrait crop — is the plain image hero, and wants neither rule. */
@media (min-width: 721px) and (min-height: 500px) and (prefers-reduced-motion: no-preference),
       (max-width: 720px) and (prefers-reduced-motion: no-preference) {
  /* The still is that first frame, so a slow zoom running on the still and not
     on the clip is a scale jump at the handover. It also has nothing left to
     zoom under an opaque clip. */
  .hero-track .hero__media img { animation: none; transform: none; }
}

/* The copy-corner wash that used to sit here — a radial on the desktop corner,
   a centre band on the phone — is gone: the hero shows the clip clean on both.
   Nothing replaces it, so the white copy is now read directly against whatever
   the frame is doing behind it. If a future clip opens brighter than this one,
   the legibility comes back from a text-side shield (.hero__inner) rather than
   from re-dimming the picture. */

/* The second beat. display:none rather than opacity:0 while the page cannot
   scrub: a line that will never be revealed should not be read out either. */
.hero__beat { display: none; }
.hero-track.is-scrub .hero__beat {
  display: block;
  position: absolute;
  left: 0; right: 0;
  bottom: clamp(56px, 8vh, 96px);
  z-index: 2;
  opacity: 0;
  pointer-events: none;
}
.hero__beat .display { max-width: 15ch; }

/* Progress through the pin. A bronze hairline on the bottom edge — the reader
   is standing still, so something has to say the scroll is going somewhere. */
.hero__rail {
  display: none;
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  height: 2px;
  background: rgba(255,255,255,.14);
}
.hero-track.is-scrub .hero__rail { display: block; }
.hero__rail-fill { display: block; height: 100%; width: 0; background: var(--brass-soft); }

/* Partner strip */
.partners { background: var(--ink); padding-block: 40px; border-top: 1px solid var(--line-dark); }
.partners__inner { display: flex; align-items: center; gap: clamp(28px, 5vw, 66px); flex-wrap: wrap; justify-content: center; }
.partners__label {
  font-family: var(--font-ui); font-size: 10.5px; font-weight: 500; letter-spacing: .12em;
  text-transform: uppercase; color: rgba(255,255,255,.62); flex: none;
}
.partners__logo {
  font-family: var(--font-display); font-size: 23px; font-weight: 300;
  letter-spacing: .06em; color: rgba(255,255,255,.6);
  transition: color .35s var(--ease);
}
.partners__logo:hover { color: #fff; }

/* ==========================================================================
   Difference / split layouts
   ========================================================================== */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(40px, 6vw, 92px); align-items: center; }
.split--wide-left { grid-template-columns: 1.06fr .94fr; }
.split--top { align-items: start; }

.checklist { display: grid; gap: 0; margin-top: 34px; }
.checklist li {
  display: grid; grid-template-columns: auto 1fr; gap: 20px; align-items: start;
  padding: 22px 0;
  border-top: 1px solid var(--line);
  font-size: var(--t-body-sm);
  line-height: 1.72;
}
.checklist li:last-child { border-bottom: 1px solid var(--line); }
.section--dark .checklist li, .section--deep .checklist li { border-color: var(--line-dark); color: rgba(255,255,255,.78); }
.checklist .num {
  font-family: var(--font-ui); font-size: 11px; font-weight: 500; letter-spacing: .14em;
  color: var(--brass); padding-top: 5px;
}

.media-frame { position: relative; overflow: hidden; }
.media-frame img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.1s var(--ease); }
.media-frame:hover img { transform: scale(1.05); }
.media-frame--tall { aspect-ratio: 4 / 5; }
.media-frame--wide { aspect-ratio: 3 / 2; }
.media-frame--square { aspect-ratio: 1 / 1; }

/* Stat badge overlapping image */
.stat-badge {
  position: absolute; right: 0; bottom: 0;
  background: var(--ink); color: #fff;
  padding: 30px 36px; text-align: center;
}
.stat-badge__n { font-family: var(--font-display); font-size: 46px; line-height: 1; font-weight: 300; }
.stat-badge__l { font-family: var(--font-ui); font-size: 10px; letter-spacing: .12em; text-transform: uppercase; color: rgba(255,255,255,.6); margin-top: 10px; }

/* ==========================================================================
   Category tiles
   ========================================================================== */
.tiles {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2px;
}
.tile { position: relative; display: block; overflow: hidden; aspect-ratio: 4 / 5; background: var(--ink); }
.tile img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.2s var(--ease), opacity .5s var(--ease);
  opacity: .82;
}
.tile:hover img { transform: scale(1.08); opacity: 1; }
.tile::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(12,12,12,.82) 0%, rgba(12,12,12,.12) 55%, rgba(12,12,12,0) 100%);
  transition: opacity .5s var(--ease);
}
.tile__label {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 26px 24px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font-family: var(--font-ui); font-size: 12.5px; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase; color: #fff;
}
.tile__label .arw { opacity: 0; transform: translateX(-8px); transition: opacity .4s var(--ease), transform .4s var(--ease); }
.tile:hover .tile__label .arw { opacity: 1; transform: translateX(0); }

/* ==========================================================================
   Testimonials
   ========================================================================== */
.quotes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; margin-top: var(--space-grid); }
.quote {
  background: rgba(255,255,255,.045);
  border: 1px solid var(--line-dark);
  padding: var(--pad-panel);
  display: flex; flex-direction: column;
  transition: background .45s var(--ease), transform .45s var(--ease);
}
.quote:hover { background: rgba(255,255,255,.08); transform: translateY(-4px); }
.stars { display: flex; gap: 5px; margin-bottom: 24px; color: var(--brass-soft); }
.stars svg { width: 14px; height: 14px; }
.quote__title {
  font-family: var(--font-display); font-weight: 300;
  font-size: clamp(21px, 1.9vw, 26px); line-height: 1.28; color: #fff; margin-bottom: 20px;
}
.quote__body { font-size: var(--t-body-sm); line-height: 1.8; color: rgba(255,255,255,.68); flex: 1; }
.quote__by {
  margin-top: 28px; padding-top: 20px; border-top: 1px solid var(--line-dark);
  font-family: var(--font-ui); font-size: 11px; font-weight: 500; letter-spacing: .12em;
  text-transform: uppercase; color: rgba(255,255,255,.85);
}
.quote__by span { display: block; margin-top: 6px; font-weight: 400; letter-spacing: .14em; color: rgba(255,255,255,.62); }

/* ==========================================================================
   Testimonial carousel
   The three hero reviews, one at a time, on a scroll-snap track. Scoped to
   .quotes--carousel so the 85-card grid on reviews.html keeps its layout.
   ========================================================================== */
.quotes__logo {
  width: 132px; height: auto;
  aspect-ratio: 1600 / 470;
  margin: 0 auto 28px;
  display: block;
}

.quotes--carousel {
  display: flex;
  grid-template-columns: none;   /* unset the .quotes grid */
  gap: 0;
  margin-top: 44px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scroll-behavior: smooth;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.quotes--carousel::-webkit-scrollbar { display: none; }

.quotes--carousel > .quote {
  flex: 0 0 100%;
  scroll-snap-align: center;
  background: none;
  border: 0;
  padding: 0 clamp(18px, 7vw, 104px);
  text-align: center;
  align-items: center;
  transition: opacity .5s var(--ease);
}
.quotes--carousel > .quote:hover { background: none; transform: none; }

.quotes--carousel .stars { justify-content: center; margin-bottom: 30px; }

/* The oversized brass quote marks in the reference sit tight against the text,
   so they are pseudo-elements on the body rather than characters in the copy. */
.quotes--carousel .quote__body {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(19px, 2.1vw, 27px);
  line-height: 1.5;
  color: rgba(255,255,255,.92);
  max-width: 46ch;
  margin-inline: auto;
  flex: none;
}
.quotes--carousel .quote__body::before,
.quotes--carousel .quote__body::after {
  color: var(--brass-soft);
  font-size: 1.15em;
  line-height: 0;
  vertical-align: -.1em;
}
.quotes--carousel .quote__body::before { content: "\201C"; margin-right: .12em; }
.quotes--carousel .quote__body::after  { content: "\201D"; margin-left: .06em; }

.quotes--carousel .quote__by {
  border-top: 0;
  padding-top: 0;
  margin-top: 30px;
  letter-spacing: .22em;
  color: rgba(255,255,255,.72);
}
.quotes--carousel .quote__by::before { content: "\2014\00a0\00a0"; color: var(--brass-soft); }

/* Controls */
.quotes-nav {
  display: flex; align-items: center; justify-content: center;
  margin-top: 34px;
}
.quotes-nav__dots { display: flex; gap: 12px; }
.quotes-nav__dot {
  width: 24px; height: 24px;             /* 24px visual, 48px hit area via padding */
  padding: 12px 6px;
  box-sizing: content-box;
  display: grid; place-items: center;
}
.quotes-nav__dot::before {
  content: "";
  width: 100%; height: 1px;
  background: rgba(255,255,255,.28);
  transition: background .35s var(--ease);
}
.quotes-nav__dot[aria-current="true"]::before { background: var(--brass-soft); }

@media (max-width: 720px) {
  .quotes--carousel .quote__body { font-size: 17.5px; }
  .quotes__logo { width: 112px; }
  .quotes-nav { gap: 16px; }
}

/* ==========================================================================
   Testimonial split — the homepage reviews band
   --------------------------------------------------------------------------
   Two columns: a static intro on the left, a deck of cross-fading review
   cards on the right. The deck is a single-cell grid, not absolute
   positioning, so its height is the tallest card and a long review can never
   be clipped — which is what a fixed min-height would have done here, since
   these quotes run anywhere from one line to six.

   Without JS the first card is visible and the rest are not, so the section
   degrades to a single review rather than a stack of overlapping text.
   .quotes--carousel is untouched: the service pages and reviews.html still
   use it.
   ========================================================================== */
.testimonials {
  display: grid;
  grid-template-columns: .92fr 1.08fr;
  grid-template-areas: "intro deck" "cta deck";
  column-gap: clamp(48px, 6vw, 96px);
  row-gap: var(--space-stack);
  align-items: center;
}
/* Areas rather than source order: on a phone the CTA has to come after the
   reviews it is offering more of, but on desktop it belongs under the intro,
   in the left column, with the deck spanning both rows beside it. */
.testimonials__intro { grid-area: intro; }
.testimonials__deck  { grid-area: deck; }
.testimonials__cta   { grid-area: cta; align-self: start; }

.testimonials__intro .display { margin-bottom: var(--space-display-tight); }
.testimonials__intro .lead { max-width: 44ch; }

/* Progress rail — the active dot widens into a bar. 44px hit area comes from
   the vertical padding, so the visible bar stays 2px without dragging the
   target below the accessibility floor. */
.testimonials__rail {
  display: flex; align-items: center; gap: 10px;
  margin-top: var(--space-stack);
}
.testimonials__dot {
  padding: 21px 0;                 /* 2px bar + 42px padding = 44px target */
  box-sizing: content-box;
  display: grid; align-items: center;
  width: 12px;
  transition: width .45s var(--ease);
}
.testimonials__dot::before {
  content: "";
  display: block;
  height: 2px;
  background: rgba(255,255,255,.26);
  transition: background .45s var(--ease);
}
.testimonials__dot:hover::before { background: rgba(255,255,255,.5); }
.testimonials__dot[aria-current="true"] { width: 44px; }
.testimonials__dot[aria-current="true"]::before { background: var(--brass-soft); }

.testimonials__count {
  font-family: var(--font-ui); font-size: var(--t-ui);
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--muted-dark);
  margin-left: 14px;
}

/* ---- The deck ---- */
.testimonials__deck { position: relative; display: grid; }
.tcard {
  grid-area: 1 / 1;                /* every card in the same cell */
  background: rgba(255,255,255,.045);
  border: 1px solid var(--line-dark);
  padding: var(--pad-panel);
  display: flex; flex-direction: column;
  opacity: 0; visibility: hidden;
  transform: translateX(28px) scale(.98);
  transition: opacity .55s var(--ease), transform .55s var(--ease), visibility .55s;
}
.tcard.is-active {
  opacity: 1; visibility: visible;
  transform: none;
  z-index: 2;
}
/* No-JS / pre-init: show the first card. */
.testimonials__deck:not(.is-ready) .tcard:first-child {
  opacity: 1; visibility: visible; transform: none;
}

.tcard .stars { margin-bottom: 26px; }

.tcard__body {
  position: relative;
  flex: 1;
  font-size: var(--t-lead);
  line-height: var(--t-lead-lh);
  font-weight: 300;
  color: rgba(255,255,255,.9);
  margin: 0;
}
.tcard__body::before {
  content: "\201C";
  /* Hangs into the card's padding, never past its border: at 390px that
     padding is only 22px, so the offset is kept under it. */
  position: absolute; top: -.34em; left: -.24em;
  font-size: 4.2em; line-height: 1;
  color: var(--brass-soft); opacity: .16;
  pointer-events: none;
}
.tcard__sep { height: 1px; background: var(--line-dark); margin: 30px 0 24px; }

/* Name and product only. There was an initials disc here standing in for a
   client photo — we have no photographs of these clients and are not going to,
   so a permanent placeholder was only ever going to read as a missing image. */
.tcard__who { display: grid; }
.tcard__name {
  font-family: var(--font-ui); font-size: var(--t-ui); font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase; color: #fff;
  margin: 0 0 6px;
}
.tcard__meta {
  font-family: var(--font-ui); font-size: var(--t-body-sm);
  color: var(--muted-dark); margin: 0;
}

/* Hairline square offset behind the deck — the Lusso reading of the original
   block's corner shapes: depth from a rule, not a fill. */
.testimonials__deck::after {
  content: "";
  position: absolute; z-index: 0;
  right: -26px; bottom: -26px;
  width: 96px; height: 96px;
  border: 1px solid rgba(160,138,110,.28);
  pointer-events: none;
}

/* The two columns hold all the way down. Stacking them put the review a full
   screen below the line that introduces it, so on a phone you read the claim,
   scrolled, and met the evidence as if it belonged to something else — and the
   section ran 915px to say one thing. Side by side it is 750px and the review
   is next to the sentence that sets it up. It is tight at 390px, so the column
   split, the gap and the card's own padding all come in below. */
@media (max-width: 1024px) {
  .testimonials { gap: clamp(18px, 3.4vw, 48px); align-items: start; }
  .testimonials__intro .lead { max-width: 40ch; }
}
@media (max-width: 720px) {
  /* The deck takes the wider half: the intro can wrap, a review in a 170px
     column cannot without turning into a column of three-word lines. */
  .testimonials { grid-template-columns: .82fr 1.18fr; }
  .testimonials__intro .lead { max-width: none; }
  .testimonials__rail { margin-top: 20px; }
  .tcard { padding: var(--pad-panel-sm); }
  .tcard .stars { margin-bottom: 18px; }
  .tcard__sep { margin: 24px 0 20px; }
  .testimonials__deck::after { display: none; }

  /* Every card sits in the same cell, so the deck is as tall as the longest
     review and a short one leaves a hole. Centring the content splits that
     hole above and below the quote, where it reads as breathing room rather
     than as a card that failed to fill. */
  .tcard { justify-content: center; }
  .tcard__body { flex: 0 1 auto; }
}
@media (prefers-reduced-motion: reduce) {
  .tcard { transition: opacity .01ms; transform: none; }
  .testimonials__dot { transition: none; }
}

/* ==========================================================================
   Capability columns
   ========================================================================== */
.caps { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(30px, 3.6vw, 58px); margin-top: var(--space-grid); }
.cap { border-top: 1px solid var(--line); padding-top: 30px; }
.section--dark .cap, .section--deep .cap { border-color: var(--line-dark); }
.cap__n {
  font-family: var(--font-ui); font-size: 11px; font-weight: 500; letter-spacing: .12em;
  color: var(--brass); margin-bottom: 20px; display: block;
}
.cap h3 { margin-bottom: 16px; }
.cap p { font-size: var(--t-body-sm); color: var(--muted); }
.section--dark .cap p, .section--deep .cap p { color: rgba(255,255,255,.66); }

/* ==========================================================================
   Portfolio gallery
   ========================================================================== */
.gallery {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: clamp(260px, 30vw, 440px);
  gap: 2px;
}
.gallery__item { position: relative; overflow: hidden; display: block; background: var(--ink); }
.gallery__item img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.2s var(--ease); }
.gallery__item:hover img { transform: scale(1.06); }
.gallery__item:nth-child(1) { grid-column: span 7; }
.gallery__item:nth-child(2) { grid-column: span 5; }
.gallery__item:nth-child(3) { grid-column: span 5; }
.gallery__item:nth-child(4) { grid-column: span 7; }
.gallery__cap {
  position: absolute; left: 0; bottom: 0; right: 0;
  padding: 26px;
  background: linear-gradient(to top, rgba(12,12,12,.8), transparent);
  color: #fff;
  font-family: var(--font-ui); font-size: 11.5px; font-weight: 500; letter-spacing: .2em; text-transform: uppercase;
  transform: translateY(8px); opacity: 0;
  transition: transform .5s var(--ease), opacity .5s var(--ease);
}
.gallery__item:hover .gallery__cap { transform: translateY(0); opacity: 1; }

/* ==========================================================================
   Process steps
   ========================================================================== */
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(30px, 3.6vw, 60px); margin-top: var(--space-grid); counter-reset: step; }
.step { position: relative; padding-top: 34px; border-top: 1px solid var(--line-dark); }
.step__n {
  font-family: var(--font-display); font-weight: 300;
  font-size: 58px; line-height: 1; color: var(--brass-soft); margin-bottom: 20px; display: block;
}
.step h3 { margin-bottom: 14px; }
.step p { font-size: var(--t-body-sm); }

/* ==========================================================================
   Quick links row
   ========================================================================== */
.quicklinks { display: flex; flex-wrap: wrap; gap: 0; border-top: 1px solid var(--line); margin-top: 40px; }
.quicklinks a {
  flex: 1 1 200px;
  padding: 30px 26px;
  border-bottom: 1px solid var(--line);
  border-right: 1px solid var(--line);
  font-family: var(--font-ui); font-size: 12.5px; font-weight: 500; letter-spacing: .12em; text-transform: uppercase;
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  transition: background .35s var(--ease), color .35s var(--ease), padding-left .35s var(--ease);
}
.quicklinks a:hover { background: var(--ink); color: #fff; padding-left: 34px; }
.quicklinks a:first-child { border-left: 1px solid var(--line); }

/* ==========================================================================
   Contact / quote form
   ========================================================================== */
.quote-block { display: grid; grid-template-columns: .88fr 1.12fr; gap: clamp(40px, 6vw, 96px); align-items: start; }
.form { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
.field { display: flex; flex-direction: column; gap: 9px; }
.field--full { grid-column: 1 / -1; }
.field label {
  font-family: var(--font-ui); font-size: 10.5px; font-weight: 500; letter-spacing: .2em;
  text-transform: uppercase; color: rgba(255,255,255,.55);
}
.field input, .field select, .field textarea {
  font-family: var(--font-body); font-size: 15.5px; font-weight: 300;
  background: transparent;
  border: 0; border-bottom: 1px solid var(--line-dark);
  color: #fff;
  padding: 12px 0;
  transition: border-color .35s var(--ease);
  border-radius: 0;
  appearance: none;
}
.field select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23999' stroke-width='1.4'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 2px center; background-size: 12px; }
.field select option { background: var(--ink); color: #fff; }
.field textarea { resize: vertical; min-height: 104px; }
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-bottom-color: var(--brass); }
.field input::placeholder, .field textarea::placeholder { color: rgba(255,255,255,.55); }
.consent { grid-column: 1 / -1; display: flex; gap: 13px; align-items: flex-start; font-size: 13.6px; color: rgba(255,255,255,.55); line-height: 1.6; }
.consent input { width: 17px; height: 17px; margin-top: 4px; accent-color: var(--brass); flex: none; }
.form__actions { grid-column: 1 / -1; margin-top: 8px; display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.form-note { font-size: 13.5px; color: var(--brass-soft); }

.contact-lines { display: grid; gap: 26px; margin-top: 38px; }
.contact-line { display: grid; grid-template-columns: auto 1fr; gap: 18px; align-items: start; }
.contact-line__k {
  font-family: var(--font-ui); font-size: 10.5px; font-weight: 500; letter-spacing: .2em;
  text-transform: uppercase; color: var(--brass-soft); padding-top: 4px; min-width: 78px;
}
.contact-line__v { color: rgba(255,255,255,.82); font-size: 15.6px; line-height: 1.7; }
.contact-line__v a:hover { color: #fff; text-decoration: underline; text-underline-offset: 4px; }

/* ==========================================================================
   Page hero (inner pages)
   ========================================================================== */
.page-hero {
  position: relative;
  background: var(--ink-deep);
  color: #fff;
  padding-top: calc(var(--header-h) + clamp(64px, 9vw, 118px));
  padding-bottom: clamp(64px, 9vw, 118px);
  overflow: hidden;
}
.page-hero__media { position: absolute; inset: 0; }
.page-hero__media img { width: 100%; height: 100%; object-fit: cover; opacity: .55; }
.page-hero__media::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to bottom, rgba(10,10,10,.6), rgba(10,10,10,.86)); }
.page-hero__inner { position: relative; z-index: 2; }
.page-hero .display { color: #fff; }
.page-hero .kicker { color: rgba(255,255,255,.78); }
.page-hero .lead { color: rgba(255,255,255,.8); }
.page-hero .eyebrow { color: var(--brass-soft); }
.crumbs {
  font-family: var(--font-ui); font-size: 11px; font-weight: 500; letter-spacing: .2em; text-transform: uppercase;
  color: rgba(255,255,255,.62); margin-bottom: 26px;
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
}
.crumbs a:hover { color: #fff; }
.crumbs .sep { color: var(--brass); }
.page-hero .display { margin-bottom: 22px; }
.page-hero .lead { max-width: 62ch; }

/* ==========================================================================
   Post cards (blog + services)
   ========================================================================== */
.filters { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 54px; }
.filter {
  font-family: var(--font-ui); font-size: 11.5px; font-weight: 500; letter-spacing: .12em; text-transform: uppercase;
  padding: 12px 24px;
  border: 1px solid var(--line);
  color: var(--muted);
  transition: background .32s var(--ease), color .32s var(--ease), border-color .32s var(--ease);
}
.filter:hover { border-color: var(--ink); color: var(--ink); }
.filter.is-active { background: var(--ink); border-color: var(--ink); color: #fff; }

.cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(28px, 3vw, 44px); }
.cards--2 { grid-template-columns: repeat(2, 1fr); }
.card { display: flex; flex-direction: column; background: var(--paper); transition: transform .5s var(--ease); }
.card:hover { transform: translateY(-6px); }
.card__media { position: relative; overflow: hidden; aspect-ratio: 3 / 2; background: var(--mist); }
.card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.1s var(--ease); }
.card:hover .card__media img { transform: scale(1.06); }
.card__tag {
  position: absolute; top: 18px; left: 18px; z-index: 2;
  background: rgba(255,255,255,.94);
  padding: 8px 15px;
  font-family: var(--font-ui); font-size: 10px; font-weight: 500; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink);
}
.card__body { padding: 26px 0 0; display: flex; flex-direction: column; flex: 1; }
.card__meta {
  font-family: var(--font-ui); font-size: 10.5px; font-weight: 500; letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 14px; display: flex; gap: 10px; align-items: center;
}
.card__meta .dot { width: 3px; height: 3px; background: var(--brass); border-radius: 50%; }
.card__title {
  font-family: var(--font-ui); font-size: clamp(17px, 1.5vw, 20px); font-weight: 500;
  line-height: 1.38; color: var(--ink); margin-bottom: 13px;
  transition: color .3s var(--ease);
}
.card:hover .card__title { color: var(--brass); }
.card__excerpt { font-size: var(--t-body-sm); line-height: 1.75; color: var(--muted); flex: 1; }
.card__more {
  margin-top: 22px;
  font-family: var(--font-ui); font-size: 11.5px; font-weight: 500; letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink);
  display: inline-flex; align-items: center; gap: 10px;
  transition: gap .35s var(--ease);
}
.card:hover .card__more { gap: 16px; }

/* Featured post — horizontal */
.feature {
  display: grid; grid-template-columns: 1.05fr .95fr;
  gap: 0;
  border: 1px solid var(--line);
  margin-bottom: clamp(40px, 5vw, 72px);
  overflow: hidden;
}
.feature__media { position: relative; overflow: hidden; min-height: 380px; }
.feature__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.2s var(--ease); }
.feature:hover .feature__media img { transform: scale(1.05); }
.feature__body { padding: clamp(34px, 4vw, 62px); display: flex; flex-direction: column; justify-content: center; }
.feature__title {
  font-family: var(--font-display); font-weight: 300;
  font-size: clamp(28px, 3.2vw, 44px); line-height: 1.14; color: var(--ink); margin-bottom: 20px;
}

/* Service list rows */
.srv-rows { border-top: 1px solid var(--line); }
.srv-row {
  display: grid;
  grid-template-columns: 88px 1fr minmax(0, 460px) auto;
  gap: clamp(20px, 3vw, 48px);
  align-items: center;
  padding: clamp(28px, 3vw, 44px) 0;
  border-bottom: 1px solid var(--line);
  transition: background .4s var(--ease), padding-inline .4s var(--ease);
}
.srv-row:hover { background: var(--mist); padding-inline: 22px; }
.srv-row__n { font-family: var(--font-ui); font-size: 11px; font-weight: 500; letter-spacing: .2em; color: var(--brass); }
.srv-row__t { font-family: var(--font-ui); font-size: clamp(18px, 1.8vw, 23px); font-weight: 400; letter-spacing: .04em; text-transform: uppercase; color: var(--ink); }
.srv-row__d { font-size: var(--t-body-sm); color: var(--muted); line-height: 1.72; }
.srv-row__a { font-family: var(--font-ui); font-size: 11.5px; font-weight: 500; letter-spacing: .2em; text-transform: uppercase; display: inline-flex; gap: 10px; align-items: center; transition: gap .35s var(--ease); }
.srv-row:hover .srv-row__a { gap: 16px; color: var(--brass); }

/* Newsletter band */
.band {
  background: var(--mist);
  padding: clamp(44px, 5vw, 72px);
  display: grid; grid-template-columns: 1fr auto; gap: clamp(28px, 4vw, 60px); align-items: center;
}
.band__form { display: flex; gap: 0; min-width: min(440px, 100%); }
.band__form input {
  flex: 1; background: transparent; border: 1px solid var(--line); border-right: 0;
  padding: 17px 20px; font-family: var(--font-body); font-size: 15px; font-weight: 300; color: var(--ink);
  border-radius: 0;
}
.band__form input:focus { outline: none; border-color: var(--ink); }

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer { background: var(--ink-deep); color: #fff; padding-block: clamp(64px, 7vw, 96px) 0; }
.footer-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: clamp(32px, 4vw, 62px); }
.footer-brand .brand__logo { width: 128px; }
/* The tagline sits outside the lockup's clear space, styled as an eyebrow. */
.footer-brand .brand__sub {
  display: block;
  margin-top: 26px;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--brass-soft);
}
.footer-brand p { margin-top: 26px; max-width: 34ch; font-size: 15.2px; color: rgba(255,255,255,.6); }
.footer-col h2 {
  font-family: var(--font-ui); font-size: 10.5px; font-weight: 500; letter-spacing: .12em;
  text-transform: uppercase; color: var(--brass-soft); margin-bottom: 24px;
}
.footer-col li { margin-bottom: 13px; }
.footer-col a, .footer-col address {
  font-size: 15px; font-style: normal; color: rgba(255,255,255,.66);
  transition: color .3s var(--ease);
  line-height: 1.75;
}
.footer-col a:hover { color: #fff; }
.socials { display: flex; gap: 12px; margin-top: 28px; }
.socials a {
  width: 40px; height: 40px; border: 1px solid var(--line-dark);
  display: grid; place-items: center;
  transition: background .35s var(--ease), border-color .35s var(--ease), color .35s var(--ease);
}
.socials a:hover { background: #fff; border-color: #fff; color: var(--ink); }
.socials svg { width: 15px; height: 15px; }
.footer-bottom {
  margin-top: clamp(48px, 5vw, 72px);
  /* Last block on the page — clears the iOS home indicator under viewport-fit=cover. */
  padding-block: 28px calc(28px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--line-dark);
  display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  font-size: 13.4px; color: rgba(255,255,255,.62);
}
.footer-bottom a:hover { color: #fff; }
.footer-bottom nav { display: flex; gap: 26px; flex-wrap: wrap; }

/* ==========================================================================
   Scroll reveal
   ========================================================================== */
.reveal { opacity: 0; transform: translateY(26px); transition: opacity .95s var(--ease), transform .95s var(--ease); }
.reveal.is-in { opacity: 1; transform: none; }
.reveal[data-d="1"] { transition-delay: .1s; }
.reveal[data-d="2"] { transition-delay: .2s; }
.reveal[data-d="3"] { transition-delay: .3s; }
.reveal[data-d="4"] { transition-delay: .4s; }
.reveal[data-d="5"] { transition-delay: .5s; }
.reveal[data-d="6"] { transition-delay: .6s; }
.reveal[data-d="7"] { transition-delay: .7s; }

/* Back to top */
.to-top {
  position: fixed; z-index: 150;
  right: calc(24px + env(safe-area-inset-right, 0px));
  bottom: calc(24px + env(safe-area-inset-bottom, 0px));
  width: 48px; height: 48px;
  background: var(--ink); color: #fff;
  display: grid; place-items: center;
  opacity: 0; visibility: hidden; transform: translateY(12px);
  transition: opacity .4s var(--ease), transform .4s var(--ease), visibility .4s, background .3s;
}
.to-top.is-vis { opacity: 1; visibility: visible; transform: none; }
.to-top:hover { background: var(--brass); }

/* ==========================================================================
   Responsive
   ========================================================================== */
@media (max-width: 1180px) {
  .tiles { grid-template-columns: repeat(3, 1fr); }
  .nav__list { gap: 24px; }
  .header-phone { display: none; }
}

@media (max-width: 1024px) {
  :root { --header-h: 76px; }
  .nav, .header-cta { display: none; }
  .burger { display: block; margin-left: auto; }
  .header-actions { display: none; }
  .split, .quote-block, .caps, .steps, .quotes { grid-template-columns: 1fr; }
  .split--wide-left { grid-template-columns: 1fr; }
  .cards { grid-template-columns: repeat(2, 1fr); }
  .feature { grid-template-columns: 1fr; }
  .feature__media { min-height: 260px; aspect-ratio: 16/10; }
  .gallery__item:nth-child(n) { grid-column: span 6; }
  .band { grid-template-columns: 1fr; }
  .srv-row { grid-template-columns: 46px 1fr; gap: 14px 20px; }
  .srv-row__d { grid-column: 2; }
  .srv-row__a { grid-column: 2; }
  .quotes { gap: 18px; }
  .hero__scroll { display: none; }
}

@media (max-width: 720px) {
  :root { --gutter: 20px; }
  body { font-size: 16px; }
  .tiles { grid-template-columns: repeat(2, 1fr); }
  .cards { grid-template-columns: 1fr; }
  .form { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .footer-brand { grid-column: 1 / -1; }
  .gallery__item:nth-child(n) { grid-column: span 12; }
  /* The phone hero takes the whole screen. It used to stop at 68svh so the
     band below stayed on-stage, but the clip a phone plays is the 9:16 one —
     shot for a full handset screen — and a 68svh window cropped it into a
     letterbox. The base `.hero` rule is already `min-height: 100svh`, so there
     is deliberately no override here; the phone simply inherits it. Anything
     re-added at this selector shortens the clip again.

     100svh, not 100vh: svh is the viewport with the browser chrome showing, so
     the hero is fully visible on arrival rather than running under a toolbar
     that only retracts once the reader scrolls. */
  .stat-badge { padding: 22px 24px; }
  .stat-badge__n { font-size: 36px; }
  .partners__inner { gap: 22px; }
  .quicklinks a { flex-basis: 100%; border-left: 1px solid var(--line); }
}

@media (max-width: 460px) {
  .footer-grid { grid-template-columns: 1fr; }
  /* The .btn shrink that used to live here is now driven by the button tokens,
     and the full-width hero pair was removed: at the reduced tracking both CTAs
     size to their content, which reads as part of the layout rather than as two
     slabs filling the screen. */
}

/* --------------------------------------------------------------------------
   Touch targets
   Below 1024px the site is driven by a thumb, not a cursor. Every interactive
   element gets a 48px minimum hit box, and text inputs go to 16px — anything
   smaller makes iOS Safari zoom the page on focus.
   -------------------------------------------------------------------------- */
@media (max-width: 1024px) {
  .btn { min-height: var(--btn-min-h); justify-content: center; }

  .filter { display: inline-flex; align-items: center; min-height: 48px; }

  .field input, .field select, .field textarea,
  .band__form input { font-size: 16px; }

  .consent input { width: 22px; height: 22px; margin-top: 1px; }

  .footer-col li { margin-bottom: 0; }
  .footer-col a { display: inline-flex; align-items: center; min-height: 48px; }

  .footer-bottom { gap: 4px 20px; }
  .footer-bottom nav { gap: 4px 26px; }
  .footer-bottom nav a { display: inline-flex; align-items: center; min-height: 48px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; }
}

/* Print */
@media print {
  .site-header, .drawer, .to-top, .hero__scroll { display: none !important; }
  body { color: #000; }
}

/* ==========================================================================
   Article / blog post
   ========================================================================== */
.post-wrap {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  gap: clamp(36px, 5vw, 78px);
  align-items: start;
}

/* Sticky table of contents */
.toc { position: sticky; top: calc(74px + 28px); }
.toc__title {
  font-family: var(--font-ui); font-size: 10.5px; font-weight: 500; letter-spacing: .12em;
  text-transform: uppercase; color: var(--brass); margin-bottom: 20px;
  padding-bottom: 14px; border-bottom: 1px solid var(--line);
}
.toc a {
  display: block; padding: 9px 0 9px 14px;
  font-size: 14px; line-height: 1.5; color: var(--muted);
  border-left: 1px solid var(--line);
  transition: color .3s var(--ease), border-color .3s var(--ease), padding-left .3s var(--ease);
}
.toc a:hover, .toc a.is-active { color: var(--ink); border-left-color: var(--brass); padding-left: 20px; }

/* Prose */
/* min-width:0 stops wide children (the comparison table) forcing the grid column open */
.toc, .prose { min-width: 0; }
.prose { max-width: 74ch; font-size: var(--t-prose); line-height: var(--t-prose-lh); color: var(--ink-soft); }
.prose > * + * { margin-top: 1.15em; }
.prose h2 {
  font-family: var(--font-ui);
  font-size: clamp(22px, 2.2vw, 29px);
  font-weight: 400; line-height: 1.28; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink);
  margin-top: 2.2em; margin-bottom: .1em;
  padding-top: 1.1em; border-top: 1px solid var(--line);
  scroll-margin-top: 110px;
}
.prose h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.prose h3 {
  font-family: var(--font-ui); font-size: clamp(17px, 1.5vw, 20px); font-weight: 500;
  line-height: 1.4; color: var(--ink); margin-top: 1.9em; margin-bottom: .2em;
  scroll-margin-top: 110px;
}
.prose h4 {
  font-family: var(--font-ui); font-size: 15.5px; font-weight: 500; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink); margin-top: 1.7em; margin-bottom: .2em;
}
.prose strong { font-weight: 500; color: var(--ink); }
.prose a:not(.btn):not(.link-u) {
  color: var(--ink); border-bottom: 1px solid var(--brass);
  transition: color .25s var(--ease), background .25s var(--ease);
}
.prose a:not(.btn):not(.link-u):hover { color: var(--brass); }
.prose ul, .prose ol { padding-left: 0; margin-left: 0; list-style: none; }
.prose ul li, .prose ol li {
  position: relative; padding-left: 30px; margin-top: .55em; line-height: 1.75;
}
.prose ul li::before {
  content: ""; position: absolute; left: 4px; top: .78em;
  width: 12px; height: 1px; background: var(--brass);
}
.prose ol { counter-reset: li; }
.prose ol li { counter-increment: li; }
.prose ol li::before {
  content: counter(li) "."; position: absolute; left: 0; top: 0;
  font-family: var(--font-ui); font-size: 13px; font-weight: 500; color: var(--brass);
}
.prose figure { margin: 2.4em 0; }
.prose figure img { width: 100%; height: auto; }
.prose figcaption {
  margin-top: 14px; font-size: 13.4px; line-height: 1.6; color: var(--muted);
  padding-left: 16px; border-left: 1px solid var(--brass);
}

/* Break an image out of the text column */
.prose .bleed { margin-inline: calc(-1 * clamp(0px, 4vw, 90px)); max-width: none; }

/* Direct-answer / key-point callout */
.answer {
  background: var(--mist);
  border-left: 2px solid var(--brass);
  padding: var(--pad-panel-sm);
  font-size: var(--t-prose); line-height: 1.75;
}
.answer p { margin: 0; }
.answer p + p { margin-top: .9em; }
.answer__label {
  display: block;
  font-family: var(--font-ui); font-size: 10.5px; font-weight: 500; letter-spacing: .12em;
  text-transform: uppercase; color: var(--brass); margin-bottom: 14px;
}

/* Comparison table */
.cmp-wrap { overflow-x: auto; margin-top: 1.8em; }
.cmp { width: 100%; border-collapse: collapse; font-size: 15px; min-width: 560px; }
.cmp caption { text-align: left; font-size: 13.4px; color: var(--muted); padding-bottom: 12px; }
.cmp th, .cmp td { padding: 16px 18px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--line); }
.cmp thead th {
  font-family: var(--font-ui); font-size: 11px; font-weight: 500; letter-spacing: .12em;
  text-transform: uppercase; color: #fff; background: var(--ink); border-bottom: 0;
}
.cmp tbody th {
  font-family: var(--font-ui); font-size: 12.5px; font-weight: 500; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink); width: 24%;
}
.cmp tbody tr:nth-child(even) { background: var(--mist); }

/* Pros / cons pair */
.pc { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; margin-top: 1.8em; }
.pc__col { padding: clamp(22px, 2.6vw, 30px); background: var(--mist); }
.pc__col h4 { margin-top: 0; display: flex; align-items: center; gap: 10px; }
.pc__col ul li { padding-left: 26px; font-size: 15.4px; }
.pc__col ul li::before { width: 9px; }
/* No red/green — the brand sheet separates do from don't with ink vs stone,
   and lets the bronze mark carry the affirmative. */
.pc__col--yes h4 { color: var(--ink); }
.pc__col--yes ul li::before { background: var(--bronze); }
.pc__col--no h4 { color: var(--muted); }
.pc__col--no ul li::before { background: var(--stone); }

/* FAQ */
.faq { margin-top: 1.6em; border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  list-style: none; cursor: pointer;
  padding: 22px 44px 22px 0; position: relative;
  font-family: var(--font-ui); font-size: 16.5px; font-weight: 500; line-height: 1.45; color: var(--ink);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; position: absolute; right: 8px; top: 50%; width: 13px; height: 13px;
  margin-top: -6px;
  background:
    linear-gradient(var(--brass), var(--brass)) center/13px 1.5px no-repeat,
    linear-gradient(var(--brass), var(--brass)) center/1.5px 13px no-repeat;
  transition: transform .35s var(--ease);
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq summary:hover { color: var(--brass); }
.faq__a { padding: 0 0 24px; font-size: 16px; line-height: 1.78; color: var(--muted); }
.faq__a > * + * { margin-top: .9em; }

/* Post meta bar */
.post-meta {
  display: flex; flex-wrap: wrap; gap: 10px 22px; align-items: center;
  font-family: var(--font-ui); font-size: 11px; font-weight: 500; letter-spacing: .12em;
  text-transform: uppercase; color: rgba(255,255,255,.6);
  margin-bottom: 26px;
}
.post-meta .dot { width: 3px; height: 3px; background: var(--brass); border-radius: 50%; }

/* Author / share footer */
.post-foot {
  margin-top: clamp(48px, 5vw, 72px); padding-top: 34px; border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; gap: 26px; flex-wrap: wrap; align-items: center;
}
.post-foot__by { font-size: 14.6px; color: var(--muted); max-width: 46ch; }
.post-foot__by strong { display: block; font-family: var(--font-ui); font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink); margin-bottom: 8px; }

/* Inline CTA inside the article */
.post-cta {
  margin-top: 2.6em;
  background: var(--ink); color: #fff;
  padding: var(--pad-panel);
}
.post-cta p { color: rgba(255,255,255,.72); font-size: 16px; }
.post-cta .display { color: #fff; font-size: clamp(26px, 2.8vw, 38px); margin-bottom: 14px; }

@media (max-width: 1024px) {
  .post-wrap { grid-template-columns: minmax(0, 1fr); }
  .toc {
    position: static; border: 1px solid var(--line); padding: 24px 26px; margin-bottom: 8px;
  }
  .toc__title { margin-bottom: 14px; }
  .toc a { border-left: 0; padding-left: 0; }
  .toc a:hover, .toc a.is-active { padding-left: 6px; }
  .prose .bleed { margin-inline: 0; }
}

@media (max-width: 720px) {
  .pc { grid-template-columns: 1fr; }
  /* .prose size now comes from --t-prose. */
}

/* ==========================================================================
   Skip link — keyboard users land here first
   ========================================================================== */
.skip-link {
  position: absolute;
  left: 16px;
  top: -100px;
  z-index: 500;
  background: var(--ink);
  color: #fff;
  padding: 14px 22px;
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  transition: top .25s var(--ease);
}
.skip-link:focus { top: 16px; }
#main:focus { outline: none; }

/* Author byline / E-E-A-T block */
.byline {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  margin-bottom: 26px;
}
/* Bronze as a hairline mark, not a fill — this sits on ink, so it takes the
   lifted bronze that clears AA against the dark ground. */
.byline__avatar {
  width: 46px; height: 46px; border-radius: 50%;
  background: transparent; color: var(--brass-soft);
  border: 1px solid var(--brass-soft);
  display: grid; place-items: center; flex: none;
  font-family: var(--font-display); font-weight: 300; font-size: 21px;
}
.byline__meta { font-size: 14px; line-height: 1.5; color: rgba(255,255,255,.72); }
.byline__meta strong { display: block; color: #fff; font-family: var(--font-ui); font-size: 13px; letter-spacing: .1em; text-transform: uppercase; }
.byline__meta a { border-bottom: 1px solid var(--brass-soft); }
.byline__meta a:hover { color: var(--brass-soft); }

.author-card {
  display: grid; grid-template-columns: auto 1fr; gap: 24px; align-items: start;
  border: 1px solid var(--line); padding: var(--pad-panel-sm); margin-top: 2.4em;
}
.author-card__avatar {
  width: 64px; height: 64px; border-radius: 50%;
  background: var(--ink); color: var(--brass-soft);
  display: grid; place-items: center; flex: none;
  font-family: var(--font-display); font-size: 28px;
}
.author-card__name {
  font-family: var(--font-ui); font-size: 13px; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink); margin-bottom: 10px;
}
.author-card p { font-size: 15px; line-height: 1.72; color: var(--muted); margin: 0; }
.author-card p + p { margin-top: .7em; }

@media (max-width: 560px) {
  .author-card { grid-template-columns: 1fr; }
}

/* ==========================================================================
   Brass on dark surfaces
   --brass is tuned for contrast on light backgrounds, so it is too dark to
   read on the ink sections. Swap in the lighter tint wherever it lands there.
   ========================================================================== */
.section--dark .cap__n,
.section--deep .cap__n,
.section--dark .checklist .num,
.section--deep .checklist .num,
.section--dark .srv-row__n,
.section--deep .srv-row__n,
.section--dark .card__meta,
.section--deep .card__meta,
.hero .crumbs .sep,
.page-hero .crumbs .sep,
.post-cta .eyebrow {
  color: var(--brass-soft);
}
.section--dark .srv-row:hover .srv-row__a,
.section--deep .srv-row:hover .srv-row__a,
.section--dark .card:hover .card__title,
.section--deep .card:hover .card__title {
  color: var(--brass-soft);
}

/* ==========================================================================
   LAYOUT UTILITIES
   Small, reusable spacing hooks. These replaced inline style="margin-*" in
   the markup — inline styles cannot be overridden from a stylesheet without
   !important, so they can never be made responsive.
   Use these instead of writing a margin into the markup.
   ========================================================================== */
.sec-head              { margin-bottom: var(--space-sec-head); }
.sec-head--sm          { margin-bottom: var(--space-sec-head-sm); }
.stack-actions         { margin-top: var(--space-stack); }
.stack-actions--center { margin-top: var(--space-stack); text-align: center; }
.display--tight        { margin-bottom: var(--space-display-tight); }

/* ==========================================================================
   PARTNER MARQUEE  (opt-in: needs .partners--marquee + a duplicated group)
   The track holds two identical groups and translates by exactly -50% of its
   own width — one full group — so the loop has no visible seam. Each item
   carries its own trailing bronze dot, so the separator survives the wrap.
   Pages without the duplicated markup keep the static centred row.
   ========================================================================== */
.partners--marquee { --mq-gap: clamp(18px, 3vw, 34px); --mq-duration: 40s; }
.partners--marquee .marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
}
.partners--marquee .marquee__track {
  display: flex; width: max-content;
  animation: partners-marquee var(--mq-duration) linear infinite;
  will-change: transform;
}
.partners--marquee .marquee:hover .marquee__track,
.partners--marquee .marquee:focus-within .marquee__track { animation-play-state: paused; }
.partners--marquee .marquee__group {
  display: flex; align-items: center; gap: var(--mq-gap); flex: none;
  padding-right: var(--mq-gap);   /* matches the gap, so the seam is seamless */
}
.partners--marquee .marquee__group > li {
  display: flex; align-items: center; gap: var(--mq-gap); flex: none; white-space: nowrap;
}
.partners--marquee .marquee__group > li::after {
  content: ""; flex: none; width: 3px; height: 3px; border-radius: 50%;
  background: var(--brass-soft); opacity: .85;
}
@keyframes partners-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

@media (prefers-reduced-motion: reduce) {
  .partners--marquee .marquee { overflow: visible; -webkit-mask-image: none; mask-image: none; }
  /* display:block matters as much as animation:none — left as a flex parent the
     group keeps flex:none, sizes to max-content and runs off the screen. */
  .partners--marquee .marquee__track { display: block; animation: none; width: auto; will-change: auto; }
  .partners--marquee .marquee__group[aria-hidden="true"] { display: none; }
  .partners--marquee .marquee__group { flex-wrap: wrap; justify-content: center; padding-right: 0; padding-inline: var(--gutter); }
  .partners--marquee .marquee__group > li:last-child::after { display: none; }
}

/* ==========================================================================
   TILE SCROLLER  (opt-in: add .tiles--scroll alongside .tiles)
   Below 1024px — style.css's own touch threshold, where the nav becomes a
   burger — eight tiles stop stacking into four tall rows and become a
   4-column, 2-row track that swipes sideways.

   minmax(--tile-w, 1fr) does both jobs in one declaration: where four columns
   cannot fit, tracks hold at --tile-w and the grid overflows so it scrolls;
   where they do fit, 1fr expands them to fill. So it meets the desktop grid at
   the breakpoint with no jump. Default row flow keeps reading order 1-2-3-4
   across the top rather than pairing items vertically.
   ========================================================================== */
@media (max-width: 1023.98px) {
  .tiles--scroll {
    --tile-w: clamp(130px, 40vw, 200px);
    grid-template-columns: repeat(4, minmax(var(--tile-w), 1fr));
    grid-template-rows: repeat(2, auto);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;   /* a swipe must not trigger back-nav */
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .tiles--scroll::-webkit-scrollbar { display: none; }
  .tiles--scroll .tile { scroll-snap-align: start; }
}

/* ==========================================================================
   REVIEW CAROUSEL — vertical centring
   Slides are flex children of one track, so every slide is as tall as the
   longest review. Packed to the top, a short review dumped all the surplus
   underneath it. Centring splits it above and below. Height is deliberately
   left alone: pinning it to the active slide clips taller reviews mid-swipe.
   ========================================================================== */
.quotes--carousel > .quote { justify-content: center; }

/* ==========================================================================
   MOBILE SCALE — components
   Everything the tokens cannot express: per-component padding, gaps and the
   handful of sizes that are not part of a shared scale. Grouped here so the
   mobile behaviour of the whole site is readable in one place.
   ========================================================================== */
@media (max-width: 720px) {

  /* ---- Buttons + links ---- */
  .btn { min-height: var(--btn-min-h); text-align: center; }
  /* .link-u is 25px tall — passes WCAG 2.5.8 AA (24px) but not the 44px bar.
     A pseudo-element extends the hit area so the animated underline stays
     welded to the text instead of dropping to a 44px box edge. */
  .link-u::before {
    content: ""; position: absolute; left: 0; right: 0; top: 50%;
    height: 44px; transform: translateY(-50%);
  }

  /* ---- Home hero ---- */
  .hero .display  { font-size: clamp(32px, 7vw, 39px); margin-bottom: 14px; }
  .hero__seo      { font-size: 10.5px; margin-bottom: 12px; }
  .hero__seo::before { width: 28px; }
  .hero__copy     { font-size: 16px; line-height: 1.6; margin-bottom: 22px; }
  /* The top pad is what stops a shorter hero sliding the eyebrow up under the
     logo: the copy is bottom-anchored, so this is the clearance the header
     needs, and the hero's min-height gives way to it rather than the reverse. */
  .hero__inner    { padding-block: calc(var(--header-h) + 20px) clamp(28px, 4.5vh, 96px); }
  .hero__actions  { gap: 12px; }
  .hero__actions .btn { width: auto; }

  /* ---- Inner-page hero (blog, service, about, terms) ---- */
  .page-hero      { padding-top: calc(var(--header-h) + clamp(36px, 9vw, 118px));
                    padding-bottom: clamp(36px, 9vw, 118px); }
  .page-hero .display { margin-bottom: 14px; }
  .crumbs         { font-size: 10px; gap: 8px; margin-bottom: 16px; }

  /* ---- Partner strip ---- */
  .partners          { padding-block: 22px; }
  .partners__label   { font-size: 10px; }
  .partners__logo    { font-size: 16px; }
  .partners--marquee { --mq-duration: 26s; }

  /* ---- Checklist / stat badge ---- */
  .checklist     { margin-top: 24px; }
  .checklist li  { padding: 16px 0; gap: 14px; line-height: 1.6; }
  .stat-badge    { padding: 16px 18px; }
  .stat-badge__n { font-size: 30px; }
  .stat-badge__l { font-size: 9.5px; margin-top: 6px; }

  /* ---- Category tiles ---- */
  .tile__label   { padding: 14px 13px; font-size: 10.5px; letter-spacing: .08em; gap: 8px; }
  /* The arrow only appears on .tile:hover, which touch never fires — it was
     reserving ~22px of a 150px tile to render nothing. */
  .tile__label .arw { display: none; }

  /* ---- Capability + process columns ---- */
  .cap, .step  { padding-top: 22px; }
  .caps        { gap: 26px; }
  .steps       { gap: 28px; }
  .cap__n      { margin-bottom: 12px; }
  .cap h3      { margin-bottom: 10px; }
  .cap p, .step p { line-height: 1.65; }
  .step__n     { font-size: 40px; margin-bottom: 12px; }
  .step h3     { margin-bottom: 8px; }

  /* ---- Gallery ---- */
  .gallery      { grid-auto-rows: 210px; }
  /* Captions were hover-only, so on touch they never appeared at all. */
  .gallery__cap { padding: 16px; font-size: 10.5px; letter-spacing: .14em;
                  transform: none; opacity: 1; }

  /* ---- Quick links ---- */
  .quicklinks   { margin-top: 26px; }
  .quicklinks a { min-height: 52px; padding: 14px 16px; font-size: 11.5px; letter-spacing: .1em; }

  /* ---- Review carousel + grid ---- */
  .quotes__logo                { margin-bottom: 18px; }
  .quotes--carousel            { margin-top: var(--space-grid); }
  .quotes--carousel .stars     { margin-bottom: 18px; }
  .quotes--carousel .quote__by { margin-top: 20px; }
  .quotes-nav                  { margin-top: 22px; }
  .quote__title                { font-size: clamp(18px, 3.6vw, 21px); margin-bottom: 14px; }
  .quote__by                   { margin-top: 20px; padding-top: 16px; }
  .stars                       { margin-bottom: 16px; }

  /* ---- Post + service cards ---- */
  .cards        { gap: 22px; }
  .card__body   { padding: 18px 0 0; }
  .card__meta   { margin-bottom: 10px; }
  .card__title  { font-size: clamp(16px, 3.2vw, 17px); margin-bottom: 10px; }
  .card__more   { margin-top: 16px; font-size: 10.5px; letter-spacing: .14em; }
  .card__tag    { top: 12px; left: 12px; padding: 6px 12px; }

  /* ---- Featured post ---- */
  .feature        { margin-bottom: 28px; }
  .feature__body  { padding: var(--pad-panel); }
  .feature__title { font-size: clamp(23px, 5.4vw, 34px); margin-bottom: 14px; }
  .feature__media { min-height: 200px; }

  /* ---- Filters ---- */
  .filters { gap: 8px; margin-bottom: 24px; }
  .filter  { padding: 10px 18px; font-size: 10.5px; letter-spacing: .1em; }

  /* ---- Service rows ---- */
  .srv-row     { padding: 20px 0; gap: 10px 16px; }
  .srv-row__t  { font-size: clamp(16.5px, 3.4vw, 18px); }
  .srv-row:hover { padding-inline: 0; }   /* no hover on touch; keeps rows aligned */

  /* ---- Newsletter band ---- */
  .band            { padding: 26px 20px; gap: 20px; }
  .band__form input { padding: 13px 16px; }

  /* ---- Article: table of contents ---- */
  .toc        { padding: 18px 18px; }
  .toc__title { margin-bottom: 10px; }
  .toc a      { padding: 8px 0; font-size: 13.5px; }
  .post-wrap  { gap: 24px; }

  /* ---- Article: prose ---- */
  /* Body size comes from --t-prose. Article copy stays deliberately larger
     than UI text — only the heading rhythm tightens here. */
  .prose h2        { font-size: clamp(19px, 4vw, 22px); margin-top: 1.7em; padding-top: .8em; }
  .prose h3        { font-size: clamp(16.5px, 3.2vw, 17px); margin-top: 1.5em; }
  .prose h4        { font-size: 14.5px; margin-top: 1.4em; }
  .prose figure    { margin: 1.7em 0; }
  .prose figcaption { margin-top: 10px; font-size: 12.8px; }
  .prose ul li, .prose ol li { padding-left: 24px; }
  .answer__label   { margin-bottom: 10px; }
  .pc__col         { padding: var(--pad-panel-sm); }
  .cmp th, .cmp td { padding: 12px 14px; }

  /* ---- Article: FAQ ---- */
  .faq summary { padding: 18px 40px 18px 0; font-size: 15.5px; }
  .faq__a      { padding: 0 0 20px; font-size: 15.5px; line-height: 1.7; }

  /* ---- Article: meta, byline, footer, inline CTA ---- */
  .post-meta        { margin-bottom: 18px; gap: 8px 16px; }
  .byline           { margin-bottom: 18px; gap: 12px; }
  .byline__avatar   { width: 40px; height: 40px; font-size: 18px; }
  .post-foot        { margin-top: 32px; padding-top: 24px; gap: 18px; }
  .post-cta         { margin-top: 2em; }
  .post-cta .display { font-size: clamp(22px, 5vw, 26px); }
  .author-card      { gap: 16px; margin-top: 1.8em; }
  .author-card__avatar { width: 52px; height: 52px; font-size: 23px; }

  /* ---- Contact block + form ---- */
  .form            { gap: 16px; }
  .field           { gap: 7px; }
  .field input, .field select, .field textarea { padding: 10px 0; }
  .field textarea  { min-height: 88px; }
  .form__actions   { margin-top: 4px; gap: 16px; }
  .contact-lines   { margin-top: 26px; gap: 18px; }
  .contact-line    { gap: 14px; }
  .contact-line__v { font-size: 15px; line-height: 1.6; }

  /* ---- Footer ---- */
  .site-footer            { padding-block: 44px 0; }
  .footer-brand .brand__sub { margin-top: 16px; }
  .footer-brand p         { margin-top: 18px; font-size: 14.6px; }
  .footer-col h2          { margin-bottom: 10px; }
  .socials                { margin-top: 18px; }
  .socials a              { width: 44px; height: 44px; }   /* was 40 — under the floor */
  .footer-bottom          { margin-top: 30px; font-size: 12.6px; }

  /* ---- Header ---- */
  /* The wordmark link is 112x33, under the 44px floor. Centring it in a 44px
     box leaves it pixel-identical, since the header centres already. */
  .header-inner .brand { display: flex; align-items: center; min-height: 44px; }
}
