/* ============================================================
   CANDIDSCAPE â€” Interiors & Construction
   Shared stylesheet
   ============================================================ */

/* ============================================================
   FONTS â€” self-hosted
   Previously an @import of fonts.googleapis.com inside this file, which could
   not begin downloading until this stylesheet had itself been fetched and
   parsed, and then required a DNS lookup plus two TLS handshakes to a second
   origin before any text could paint in the real face.
   Now same-origin woff2, declared here so there is no extra request, cached for
   a year, with font-display:swap so text is never invisible.

   One variable face replaces the previous three (Archivo variable + two Fraunces
   statics, 112 KB total). Montserrat carries the whole 100â€“900 range in 38 KB,
   so headings, body, eyebrows and buttons all come from a single download and
   there is no second family to wait on. SIL Open Font Licence, same as before.

   Weights are recalibrated rather than inherited: Fraunces was a serif set at
   400, and a geometric sans at 400 reads thin and washed out at heading sizes.
   Headings are therefore 600â€“700 with tighter negative tracking. See the
   typography rules immediately below :root.
   ============================================================ */
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/fonts/montserrat-variable.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ============================================================
   HOMEPAGE SIGNATURE UPGRADE — 2026-08
   A tighter editorial hierarchy, verified proof, and one motion-led process.
   These rules are deliberately page-scoped so shared service pages keep their
   established layout while the homepage can carry a stronger art direction.
   ============================================================ */
.page-home .site-header .brand img { width:clamp(86px, 7.8vw, 108px); height:auto; }

.page-home .hero {
  display:flex;
  align-items:center;
  min-height:calc(100svh - 76px);
  padding-block:clamp(68px, 9vh, 108px) clamp(34px, 5vh, 58px);
  overflow:hidden;
}
.page-home .hero::after {
  content:'';
  position:absolute;
  inset:0;
  z-index:-1;
  pointer-events:none;
  background:
    linear-gradient(90deg, transparent 0 49.9%, rgba(255,255,255,.08) 50%, transparent 50.1%),
    linear-gradient(0deg, transparent 0 71.9%, rgba(255,255,255,.07) 72%, transparent 72.1%);
  mask-image:linear-gradient(90deg, #000, transparent 72%);
  opacity:.55;
}
.page-home .hero-grid { gap:clamp(20px, 3vh, 34px); }
.page-home .hero h1 { max-width:21ch; font-size:clamp(42px, 4.8vw, 66px); line-height:1.035; }
.page-home .hero-lead { max-width:50ch; font-size:clamp(15px, 1.25vw, 18px); }
.page-home .hero-feature {
  display:grid;
  grid-template-columns:minmax(210px, 280px) minmax(320px, 520px) 72px;
  align-items:end;
  gap:clamp(12px, 2vw, 24px);
  max-width:920px;
}
.page-home .hero-project-card {
  position:static;
  right:auto;
  bottom:auto;
  width:100%;
  min-height:102px;
  padding:15px 17px;
  opacity:1;
  transform:none;
  pointer-events:auto;
  border-color:rgba(255,255,255,.22);
  background:rgba(5,5,31,.42);
}
.page-home .hero-project-card strong { font-size:clamp(20px, 1.7vw, 25px); }
.page-home .hero-controls { grid-template-columns:40px minmax(0, 1fr) 40px; }
.page-home .hero-arrow { width:40px; height:40px; }
.page-home .hero-dots { flex-wrap:nowrap; gap:4px; margin:0; }
.page-home .hero-dot { flex:1 1 0; min-width:28px; width:auto; }
.page-home .hero-count { display:grid; grid-template-columns:auto 1fr auto; align-items:center; gap:8px; color:rgba(255,255,255,.86); font-size:10px; font-weight:700; letter-spacing:.16em; }
.page-home .hero-count i { display:block; width:100%; height:1px; background:rgba(255,255,255,.35); }
.page-home .hero-proof {
  display:grid;
  grid-template-columns:repeat(3, minmax(0, 1fr));
  max-width:760px;
  padding-top:clamp(18px, 2.5vh, 28px);
  border-top:1px solid rgba(255,255,255,.2);
}
.page-home .hero-proof > div { display:grid; gap:4px; padding-right:clamp(14px, 2.5vw, 32px); }
.page-home .hero-proof > div + div { padding-left:clamp(14px, 2.5vw, 32px); border-left:1px solid rgba(255,255,255,.18); }
.page-home .hero-proof strong { color:var(--paper); font:400 clamp(24px, 2.2vw, 34px)/1 'Fraunces', Georgia, serif; letter-spacing:-.035em; }
.page-home .hero-proof > div > span { color:rgba(255,255,255,.72); font-size:9px; font-weight:600; letter-spacing:.13em; text-transform:uppercase; }
.page-home .hero-scroll-cue { position:absolute; right:clamp(18px, 3vw, 46px); bottom:28px; display:flex; align-items:center; gap:12px; color:rgba(255,255,255,.68); font-size:9px; font-weight:600; letter-spacing:.17em; text-transform:uppercase; writing-mode:vertical-rl; }
.page-home .hero-scroll-cue i { position:relative; display:block; width:1px; height:52px; overflow:hidden; background:rgba(255,255,255,.24); }
.page-home .hero-scroll-cue i::after { content:''; position:absolute; inset:0; background:var(--gold); transform:translateY(-100%); animation:home-scroll-cue 2.2s ease-in-out infinite; }
@keyframes home-scroll-cue { 45%,100% { transform:translateY(100%); } }

.home-proof-strip { overflow:hidden; border-block:1px solid var(--line); background:var(--paper); }
.home-proof-strip__grid { display:grid; grid-template-columns:minmax(220px, .72fr) minmax(0, 1.28fr); align-items:center; min-height:96px; }
.home-proof-strip p { padding-right:clamp(24px, 4vw, 58px); color:var(--ink); font:400 clamp(18px, 1.6vw, 23px)/1.25 'Fraunces', Georgia, serif; }
.home-proof-strip ul { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); border-left:1px solid var(--line); list-style:none; }
.home-proof-strip li { position:relative; display:flex; align-items:center; min-height:48px; padding:12px 18px 12px 42px; color:var(--ink-soft); font-size:11px; font-weight:600; letter-spacing:.045em; }
.home-proof-strip li::before { content:''; position:absolute; left:19px; width:8px; height:8px; border:1px solid var(--gold); transform:rotate(45deg); }
.home-proof-strip li:nth-child(even) { border-left:1px solid var(--line); }
.home-proof-strip li:nth-child(n+3) { border-top:1px solid var(--line); }

.page-home .home-system { position:relative; overflow:hidden; background:var(--paper-warm); }
.page-home .home-system::before { content:'CANDIDSCAPE'; position:absolute; left:50%; top:12px; color:rgba(20,19,42,.035); font:400 clamp(76px, 12vw, 190px)/1 'Fraunces', Georgia, serif; letter-spacing:-.07em; white-space:nowrap; pointer-events:none; transform:translateX(-50%); }
.home-system__grid { position:relative; display:grid; grid-template-columns:minmax(260px, .72fr) minmax(0, 1.28fr); gap:clamp(44px, 8vw, 124px); align-items:center; }
.home-system__intro { position:sticky; top:112px; align-self:start; padding-top:clamp(10px, 3vw, 42px); }
.home-system__intro .section-title { max-width:11ch; font-size:clamp(38px, 4.7vw, 66px); line-height:1.02; }
.home-system__lede { max-width:43ch; margin-top:22px; color:var(--ink-soft); font-size:clamp(15px, 1.25vw, 18px); line-height:1.72; }
.home-system__intro .btn { margin-top:28px; }
.home-system__visual { position:relative; min-width:0; }
.home-system__image { position:relative; overflow:hidden; min-height:clamp(360px, 48vw, 640px); background:var(--ink); }
.home-system__image::after { content:''; position:absolute; inset:0; background:linear-gradient(180deg, transparent 32%, rgba(5,5,31,.32) 100%); pointer-events:none; }
.home-system__image img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; transform:scale(1.035); transition:transform 1.5s var(--ease-soft); }
.home-system__visual.is-process-live .home-system__image img { transform:scale(1); }
.home-system__image figcaption { position:absolute; left:20px; bottom:18px; z-index:1; color:rgba(255,255,255,.86); font-size:9px; font-weight:600; letter-spacing:.15em; text-transform:uppercase; }
.home-system__steps { position:absolute; right:clamp(-34px, -2vw, -18px); top:50%; z-index:2; width:min(310px, 46%); padding:10px 0; background:rgba(8,7,34,.88); box-shadow:0 26px 70px rgba(8,7,34,.3); backdrop-filter:blur(14px); color:var(--white); list-style:none; transform:translateY(-50%); }
.home-system__steps::before { content:''; position:absolute; left:38px; top:34px; bottom:34px; width:1px; background:rgba(255,255,255,.18); }
.home-system__steps::after { content:''; position:absolute; left:38px; top:34px; bottom:34px; width:1px; background:var(--gold); transform:scaleY(var(--process, 0)); transform-origin:top; transition:transform .2s linear; }
.home-system__steps li { position:relative; z-index:1; display:grid; grid-template-columns:58px minmax(0, 1fr); align-items:center; min-height:78px; padding:10px 18px 10px 10px; opacity:.46; transition:opacity .4s var(--ease), transform .45s var(--ease), background .4s var(--ease); }
.home-system__steps li.is-active { opacity:1; background:rgba(255,255,255,.07); transform:translateX(-8px); }
.home-system__steps li > span { display:grid; place-items:center; width:58px; color:var(--gold-lit); font-size:9px; font-weight:700; letter-spacing:.12em; }
.home-system__steps li > span::after { content:''; position:absolute; left:34px; width:9px; height:9px; border:2px solid var(--noir); border-radius:50%; background:rgba(255,255,255,.4); transition:background .3s, transform .3s; }
.home-system__steps li.is-active > span::after { background:var(--gold); transform:scale(1.25); }
.home-system__steps div { display:grid; gap:4px; }
.home-system__steps strong { font:400 clamp(18px, 1.7vw, 24px)/1.1 'Fraunces', Georgia, serif; }
.home-system__steps small { color:rgba(255,255,255,.68); font-size:10px; letter-spacing:.035em; }

.hscroll-intro { position:relative; z-index:1; display:flex; align-items:end; justify-content:space-between; gap:28px; padding-top:clamp(18px, 3vw, 36px); padding-bottom:clamp(18px, 2.5vw, 28px); color:var(--white); }
.hscroll-intro .eyebrow { margin-bottom:10px; color:var(--gold-lit); font-size:9px; font-weight:600; letter-spacing:.16em; text-transform:uppercase; }
.hscroll-intro h2 { max-width:18ch; color:var(--white); font:400 clamp(25px, 3vw, 42px)/1.06 'Fraunces', Georgia, serif; letter-spacing:-.035em; }
.hscroll-intro a { position:relative; z-index:2; display:inline-flex; align-items:center; justify-content:space-between; gap:16px; flex:none; min-width:286px; min-height:56px; padding:0 24px; border:1px solid rgba(255,255,255,.38); border-radius:999px; background:rgba(255,255,255,.06); box-shadow:0 10px 24px rgba(0,0,0,.16); color:var(--white); cursor:pointer; pointer-events:auto; font-size:10px; font-weight:600; letter-spacing:.1em; text-transform:uppercase; transition:transform .3s var(--ease), background-color .3s var(--ease), border-color .3s var(--ease), box-shadow .3s var(--ease); }
.hscroll-intro a:hover, .hscroll-intro a:focus-visible { transform:translateY(-2px); border-color:rgba(255,255,255,.75); background:rgba(255,255,255,.13); box-shadow:0 15px 30px rgba(0,0,0,.24); }
.hscroll-intro a span { transition:transform .3s var(--ease); }
.hscroll-intro a:hover span { transform:translateX(5px); }
.hscroll-cta-mobile-wrap { display:none; }

.home-work-head { display:grid; grid-template-columns:minmax(0, 1fr) minmax(260px, 430px); align-items:end; gap:clamp(28px, 6vw, 86px); margin-bottom:clamp(24px, 3vw, 38px); }
.home-work-head .section-title { margin-bottom:0 !important; }
.home-work-lede { color:var(--ink-soft); font-size:clamp(14px, 1.18vw, 17px); line-height:1.72; text-wrap:pretty; }

@media (max-width:900px) {
  .page-home .hero { min-height:auto; padding-block:clamp(54px, 8vw, 74px) 38px; }
  .page-home .hero-feature { grid-template-columns:minmax(0, 1fr) 58px; max-width:100%; }
  .page-home .hero-project-card { grid-column:1 / -1; max-width:360px; }
  .page-home .hero-controls { min-width:0; }
  .page-home .hero-scroll-cue { display:none; }
  .home-system__grid { grid-template-columns:1fr; gap:34px; }
  .home-system__intro { position:static; padding-top:0; }
  .home-system__intro .section-title { max-width:15ch; }
  .home-system__visual { padding-right:34px; }
  .home-system__steps { right:0; width:min(330px, 50%); }
}

@media (max-width:640px) {
  .page-home .site-header .brand img { width:76px; }
  .page-home .hero { min-height:calc(100svh - 72px); padding-block:58px 30px; align-items:flex-start; }
  .page-home .hero h1 { max-width:100%; font-size:clamp(34px, 10.2vw, 43px); line-height:1.04; }
  .page-home .hero-tag { margin-bottom:14px; font-size:9px; }
  .page-home .hero-actions { display:grid; grid-template-columns:1fr 1fr; gap:9px; margin-top:22px; }
  .page-home .hero-actions .btn { min-height:48px; padding-inline:12px; font-size:12px; }
  .page-home .hero-project-card { display:none; }
  .page-home .hero-feature { display:grid; grid-template-columns:minmax(0, 1fr) 52px; gap:10px; }
  .page-home .hero-dots { gap:2px; }
  .page-home .hero-dot { min-width:18px; height:36px; padding-block:16.5px; }
  .page-home .hero-dot::after { top:16.5px; }
  .page-home .hero-proof { margin-top:0; padding-top:16px; }
  .page-home .hero-proof > div { padding-right:8px; }
  .page-home .hero-proof > div + div { padding-left:10px; }
  .page-home .hero-proof strong { font-size:22px; }
  .page-home .hero-proof > div > span { font-size:7.5px; line-height:1.35; }

  .home-proof-strip__grid { grid-template-columns:1fr; padding-block:18px; }
  .home-proof-strip p { padding:0 0 15px; font-size:18px; }
  .home-proof-strip ul { grid-template-columns:1fr; border-left:0; border-top:1px solid var(--line); }
  .home-proof-strip li { min-height:42px; padding-block:9px; }
  .home-proof-strip li:nth-child(even) { border-left:0; }
  .home-proof-strip li:nth-child(n+2) { border-top:1px solid var(--line); }

  .home-system__intro .section-title { font-size:clamp(34px, 10vw, 46px); }
  .home-system__visual { display:grid; padding-right:0; gap:0; }
  .home-system__image { min-height:360px; }
  .home-system__steps { position:relative; right:auto; top:auto; width:calc(100% - 24px); margin:-72px 12px 0; transform:none; }
  .home-system__steps li { min-height:68px; }

  .hscroll-intro { align-items:start; flex-direction:column; gap:14px; }
  .hscroll-intro h2 { font-size:28px; }
  .hscroll-intro .hscroll-cta--desktop { display:none; }
  .hscroll-cta-mobile-wrap { display:block; padding-block:18px 24px; }
  .hscroll-cta-mobile-wrap .hscroll-cta {
    display:inline-flex; align-items:center; justify-content:space-between;
    width:100%; min-height:56px; padding:0 24px;
    border:1px solid rgba(255,255,255,.38); border-radius:999px;
    background:rgba(255,255,255,.06); color:var(--white);
    font-size:10px; font-weight:600; letter-spacing:.1em; text-transform:uppercase;
  }

  .home-work-head { grid-template-columns:1fr; gap:14px; }
  .page-home .contact-dock a { min-height:48px; font-size:13px; }
}

@media (prefers-reduced-motion:reduce) {
  .page-home .hero-scroll-cue i::after { animation:none; transform:none; }
  .home-system__image img, .home-system__steps li, .home-system__steps::after,
}

/* Fraunces, restored as a DISPLAY face only â€” the page headlines and nothing
   else. It was retired earlier in this project when the brief was payload and
   minimalism; the brief is now "reads like the best interior studios in the
   world", and those sites are almost universally an editorial serif for display
   over a neutral sans for text. Montserrat alone is clean but anonymous â€” it is
   the most-used Google font in existence, and it was the single thing making
   this site read as a template.

   Two faces, 72.8 KB total: still 35% below the 112 KB this project started at.
   Its wght axis is pinned at 400, so nothing may ask for bold â€” see the display
   rules below, which set size and tracking rather than weight. */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/fraunces-400-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


:root {
  --ink: #14132a;
  --ink-soft: #4a4a63;
  --paper: #f4f1ea;
  --paper-warm: #ece7db;
  --line: #d6d2c6;
  --clay: #00003b;       /* brand navy (accent) */
  --clay-deep: #1b1b5c;  /* lifted navy for hovers */
  --gold: #d9c39a;       /* accent on navy only â€” eyebrows, rules, active states */
  --white: #fdfcf9;
  --shadow: 0 1px 2px rgba(20,19,42,.04), 0 8px 30px rgba(20,19,42,.07);
  --container-max: 1320px;
  --page-padding: clamp(18px, 4vw, 56px);
  --section-space: clamp(46px, 4.8vw, 68px);
  --section-space-small: clamp(38px, 3.8vw, 52px);
  --text-xs: 11px;
  --text-sm: clamp(13px, 1vw, 14px);
  --text-base: clamp(14px, 1.1vw, 16px);
  --text-lg: clamp(17px, 1.45vw, 20px);
  --heading-sm: clamp(18px, 1.55vw, 23px);
  --heading-md: clamp(24px, 2.6vw, 33px);
  --heading-lg: clamp(31px, 3.8vw, 54px);
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --border: var(--line);
  --surface: var(--paper);
  --foreground: var(--ink);
  --muted: var(--ink-soft);
  --accent: var(--clay);
  --maxw: var(--container-max);
  --ease: cubic-bezier(.16,1,.3,1);

  /* Fluid type scale â€” every step interpolates between 320px and 1240px, so
     text sizes itself continuously instead of stepping at a breakpoint. */
  --step--1: clamp(0.83rem, 0.79rem + 0.20vw, 0.94rem);
  --step-0:  clamp(1.00rem, 0.95rem + 0.25vw, 1.13rem);
  --step-1:  clamp(1.20rem, 1.11rem + 0.44vw, 1.50rem);
  --step-2:  clamp(1.44rem, 1.29rem + 0.74vw, 2.00rem);
  --step-3:  clamp(1.73rem, 1.49rem + 1.19vw, 2.67rem);
  --step-4:  clamp(2.07rem, 1.71rem + 1.83vw, 3.55rem);
  --step-5:  clamp(2.49rem, 1.94rem + 2.74vw, 4.74rem);

  /* Fluid spacing scale. */
  --space-s:  clamp(12px, 2vw, 20px);
  --space-m:  clamp(24px, 4vw, 44px);
  --space-l:  var(--section-space);
  --space-xl: clamp(64px, 8vw, 112px);

  /* Hairlines are drawn INSIDE cells (see the grid section below), never as a
     coloured container showing through a 1px gap â€” that technique leaves solid
     blocks wherever the last row is not full. */
  --hairline: var(--line);
  --hairline-dark: rgba(255,255,255,.15);

  /* Scrollbar width, measured once by main.js. 100vw includes the classic
     Windows scrollbar but the layout viewport does not, so every full-bleed
     band built on `width:100vw` sits about 8px too far left and overflows the
     same amount on the right. Defaults to 0, which is correct on overlay-
     scrollbar platforms and degrades to the old behaviour without scripting. */
  --sbw: 0px;
}

/* Break out of .wrap to the true viewport edge. */
.bleed {
  margin-inline: calc(50% - 50vw + var(--sbw) / 2);
  width: calc(100vw - var(--sbw));
  max-width: calc(100vw - var(--sbw));
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* Flex and grid children default to min-width:auto, which lets long words and
   wide media push a track wider than its share and cause page-level overflow. */
* { min-width: 0; }

html { scroll-behavior: smooth; }

body {
  font-family: 'Montserrat', sans-serif;
  background: var(--paper);
  color: var(--ink);
  line-height: 1.7;
  /* 16px, not the previous 17px: Montserrat's x-height runs noticeably larger
     than Archivo's, so 16px here reads at about the same optical size. */
  font-size: 16px;
  letter-spacing: -.005em;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: 'Montserrat', sans-serif;
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -.026em;
}
h1 { font-weight: 700; line-height: 1.04; letter-spacing: -.032em; }
h2 { font-weight: 700; line-height: 1.12; letter-spacing: -.026em; }
h3 { font-weight: 600; line-height: 1.25; letter-spacing: -.015em; }
h4 { font-weight: 600; letter-spacing: -.01em; }

/* ---------- Display type ----------
   The page headlines only: the hero, section titles, the feature plate and the
   sticky-story beats. Everything smaller â€” card titles, FAQ questions, labels,
   nav, buttons, body â€” stays Montserrat, which is what keeps the pairing an
   editorial contrast rather than a costume.

   Weight stays 400 because this Fraunces has its wght axis pinned there;
   asking for 600 or 700 would get a synthesised faux bold, which is smeared and
   was the only badly-rendered type on the old site. The presence comes from
   size and from tighter tracking, not from weight. */
.hero h1,
.section-title,
.feature-shot-cap h2,
.ss-beat h3,
.cta h2,
.cta-panel h2 {
  font-family: 'Montserrat', sans-serif;
  font-weight: 600;
  letter-spacing: -.03em;
}
/* Optical sizing: Fraunces carries an opsz axis, so large settings get the
   finer, higher-contrast cut rather than a scaled-up text design. */
.hero h1, .section-title { font-optical-sizing: auto; }

/* Keep headline and body measures readable without per-page overrides.
   64ch rather than 68ch, for the same x-height reason as the body size. */
h1, h2 { max-width: 20ch; text-wrap: balance; }
p { max-width: 64ch; text-wrap: pretty; }

a { color: inherit; text-decoration: none; }

/* Replaced body{overflow-x:hidden}, which hid overflow rather than preventing
   it. Media can no longer exceed its container in the first place. */
img, video, svg, iframe { display: block; max-width: 100%; height: auto; }

/* Site-wide keyboard focus ring. Previously only nav, breadcrumbs and service
   cards had one, so most of the site was unusable by keyboard. */
:focus-visible { outline: 3px solid var(--clay); outline-offset: 3px; border-radius: 2px; }
.dark-band :focus-visible,
.site-footer :focus-visible,
.testimonials-band :focus-visible,
.clients-band :focus-visible { outline-color: #f4d19d; }

/* Skip link â€” first tab stop on every page. */
.skip-link {
  position: absolute; left: 8px; top: 0; z-index: 200;
  padding: 12px 20px; min-height: 44px; display: inline-flex; align-items: center;
  background: var(--clay); color: var(--white);
  font-size: 14px; font-weight: 700; letter-spacing: .04em; border-radius: 0 0 4px 4px;
  /* transform rather than `top`, so revealing it does not reflow the header. */
  transform: translateY(-120%);
  transition: transform .25s var(--ease);
}
.skip-link:focus { transform: none; }

/* Fluid gutter, capped measure, no breakpoint.
   Deliberately max-width + padding rather than `width: min(...)`: .svc-hero .wrap
   and .res-hero .wrap both override `width`, and with the min() form those
   overrides would escape the cap and run full-bleed. */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--page-padding);
}

/* ---------- Header / Nav ---------- */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: var(--paper);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-bottom: 1px solid var(--line);
}
.nav {
  display: flex; align-items: center; justify-content: space-between;
  height: 68px;
  gap: 24px;
}
.brand {
  display: flex; align-items: center; flex-shrink: 0;
}
.brand img { height: 46px; width: auto; display: block; }
@media (max-width: 560px) {
  .brand img { height: 38px; }
}
.nav-links { display: flex; gap: 30px; align-items: center; margin-left: auto; }
.mobile-menu-intro { display:none; }
@media (min-width:881px) { .mobile-menu-intro { display:none !important; } }
/* Was padding:7px 0, rendering ~35px tall. Now a 44px minimum hit area. */
.nav-links a {
  font-size: 13px; font-weight: 500; letter-spacing: .04em;
  position: relative; display: inline-flex; align-items: center;
  min-height: 44px; padding: 7px 0; color: var(--ink-soft);
  transition: color .3s var(--ease);
}
/* Underline was animated with `width`, which reflows the pseudo-element on
   every frame of every nav hover. scaleX does the same thing on the compositor. */
.nav-links a::after {
  content: ''; position: absolute; left: 0; bottom: -2px;
  width: 100%; height: 1.5px; background: var(--clay);
  transform: scaleX(0); transform-origin: left center;
  transition: transform .32s var(--ease);
}
.nav-links a:hover, .nav-links a.active { color: var(--ink); }
.nav-links a.active::after, .nav-links a:hover::after,
.nav-links a:focus-visible::after { transform: scaleX(1); }
.nav-services { position:relative; }
.nav-services-trigger { display:flex; align-items:center; gap:4px; }
/* This control opens the entire service menu on mobile and was 24x30px.
   Raised to the 44x44 minimum; the chevron itself stays visually small. */
.services-toggle {
  display:inline-grid; place-items:center; width:44px; height:44px; padding:0; border:0; background:transparent;
  cursor:pointer; color:var(--ink-soft); border-radius:999px;
  transition:color .3s var(--ease), background .3s var(--ease);
}
.services-toggle span { width:7px; height:7px; border-right:1.5px solid currentColor; border-bottom:1.5px solid currentColor; transform:rotate(45deg) translateY(-2px); transition:transform .25s var(--ease); }
.services-toggle:hover { background:var(--paper-warm); }
.services-toggle:focus-visible { outline:2px solid var(--clay); outline-offset:2px; }
.nav-services:hover .services-toggle,
.nav-services:focus-within .services-toggle,
.nav-services.services-open .services-toggle { color:var(--ink); }
.nav-services:hover .services-toggle span,
.nav-services:focus-within .services-toggle span,
.nav-services.services-open .services-toggle span { transform:rotate(225deg) translate(-1px,-2px); }
.services-menu {
  /* Centre the panel on its trigger. The Services item is now near the middle
     of the navigation, so a right-anchored panel can run off the left edge. */
  position:absolute; top:calc(100% + 17px); left:50%; right:auto; z-index:110;
  width:540px; max-width:calc(100vw - 40px); padding:20px 10px 0;
  background:var(--white); border:1px solid var(--line); box-shadow:0 18px 42px rgba(20,19,42,.13);
  opacity:0; visibility:hidden; transform:translate(-50%,-8px); pointer-events:none;
  transition:opacity .2s ease, transform .2s var(--ease), visibility .2s;
}
.nav-services:hover .services-menu,
.nav-services:focus-within .services-menu,
.nav-services.services-open .services-menu { opacity:1; visibility:visible; transform:translateX(-50%); pointer-events:auto; }
/* Dismissed with the chevron or Esc â€” stays shut until the pointer or focus leaves. */
.nav-services.services-shut:not(.services-open):hover .services-menu,
.nav-services.services-shut:not(.services-open):focus-within .services-menu { opacity:0; visibility:hidden; transform:translate(-50%,-8px); pointer-events:none; }
/* Invisible bridge across the gap under the header, so the pointer can travel
   from the trigger into the panel without it closing. It inherits the panel's
   pointer-events, so it never blocks the nav while the panel is closed. */
.services-menu::before { content:''; position:absolute; left:0; right:0; top:-19px; height:19px; }
.services-menu-cols { display:grid; grid-template-columns:1fr; }
.services-col { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); column-gap:12px; }
.services-col-title {
  grid-column:1 / -1;
  font-size:10px; font-weight:700; letter-spacing:.2em; text-transform:uppercase;
  color:var(--clay); padding:0 12px 8px; line-height:1;
}
.services-menu a { display:flex; align-items:center; min-height:44px; padding:9px 12px; color:var(--ink) !important; font-size:13px; line-height:1.35; transition:background .2s ease, color .2s ease; }
.services-menu a::after { display:none !important; }
.services-menu a:hover, .services-menu a:focus-visible { background:var(--paper-warm); color:var(--clay) !important; }
.services-menu a.is-current { background:var(--paper-warm); color:var(--clay) !important; font-weight:700; box-shadow:inset 2px 0 0 var(--clay); }
.services-menu-all {
  display:flex !important; align-items:center; justify-content:space-between; gap:10px;
  margin:14px -10px 0; padding:14px 22px !important; border-top:1px solid var(--line);
  font-weight:700 !important; letter-spacing:.05em;
}
.services-menu-all span { transition:transform .3s var(--ease); }
.services-menu-all:hover span { transform:translateX(3px); }
.nav-cta {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  background: var(--clay); color: var(--white) !important;
  padding: 12px 20px !important; border-radius: 999px; font-size: 12px !important;
  font-weight: 700 !important; letter-spacing: .06em; white-space: nowrap;
  box-shadow: 0 8px 18px rgba(0,0,59,.16);
  transition: background .3s var(--ease), transform .3s var(--ease), box-shadow .3s var(--ease);
}
.nav-cta::after { display: none !important; }
.nav-cta span { font-size:16px; line-height:0; transition:transform .3s var(--ease); }
.nav-cta:hover { background: var(--clay-deep); transform:translateY(-2px); box-shadow:0 12px 24px rgba(0,0,59,.24); }
.nav-cta:hover span { transform:translateX(3px); }
.menu-toggle {
  display: none; background: none; border: 1px solid var(--line); cursor: pointer;
  min-width:44px; height:44px; padding:0; border-radius:6px; background:var(--white);
  align-items:center; justify-content:center; gap:10px;
  font:600 11px/1 'Montserrat',sans-serif; letter-spacing:.11em; text-transform:uppercase; color:var(--ink);
  transition:background .3s var(--ease), border-color .3s var(--ease), transform .3s var(--ease);
}
.menu-toggle:hover { border-color:var(--ink); background:var(--paper-warm); }
.menu-toggle-icon { display:flex; flex-direction:column; gap:4px; }
.menu-toggle-icon span { display:block; width:17px; height:2px; border-radius:2px; background:var(--ink); transition:.3s var(--ease); }
.menu-toggle.open .menu-toggle-icon span:nth-child(1) { transform:translateY(6px) rotate(45deg); }
.menu-toggle.open .menu-toggle-icon span:nth-child(2) { opacity:0; }
.menu-toggle.open .menu-toggle-icon span:nth-child(3) { transform:translateY(-6px) rotate(-45deg); }
body.menu-open { overflow: hidden; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 13px; font-weight: 600; letter-spacing: .015em;
  padding: 15px 30px; border-radius: 2px;
  /* Was `all`, which makes the browser evaluate every animatable property on
     each frame. Only the four that actually change are listed. */
  transition: background-color .3s var(--ease), color .3s var(--ease),
              border-color .3s var(--ease), transform .3s var(--ease);
  cursor: pointer; border: none;
}
.btn-dark { background: var(--ink); color: var(--white); }
.btn-dark:hover { background: var(--clay-deep); transform: translateY(-2px); }
.btn-ghost { color: var(--white); border: 1px solid rgba(255,255,255,.5); background: rgba(20,19,42,.22); }
.btn-ghost:hover { border-color: var(--white); background: rgba(255,255,255,.12); color: var(--white); transform: translateY(-2px); }
.btn-line { border: 1.5px solid var(--ink); color: var(--ink); background: transparent; }
.btn-line:hover { background: var(--ink); color: var(--white); }
.btn .arr { transition: transform .35s var(--ease); }
.btn:hover .arr { transform: translateX(4px); }

/* ============================================================
   HAIRLINE GRIDS â€” the fix for the grey trailing cells
   ------------------------------------------------------------
   The site previously drew grid hairlines by putting a 1px gap over a coloured
   container, so the container showed through the gaps. Any track left empty in
   the final row also showed the container colour â€” as a solid grey (or navy)
   block. With auto-fit the number of leftover tracks changes with viewport
   width, so it could not be patched with :nth-child.
   Now the container matches the cells and each cell paints its own right and
   bottom hairline inset. An empty trailing track renders as plain background:
   the grid simply ends, at any column count and any width.
   ============================================================ */
.grid-hairline {
  display: grid;
  gap: 0;
  background: var(--white);
  border: 1px solid var(--line);
}
.grid-hairline > * {
  box-shadow: inset -1px 0 0 var(--line), inset 0 -1px 0 var(--line);
}
.grid-hairline-dark {
  display: grid;
  gap: 0;
  background: var(--ink);
  border: 1px solid var(--hairline-dark);
}
.grid-hairline-dark > * {
  box-shadow: inset -1px 0 0 var(--hairline-dark), inset 0 -1px 0 var(--hairline-dark);
}/* Light grids *//* These two have paper-coloured cells, so their container must match paper â€”
   otherwise an empty trailing track shows white against paper cells. *//* Dark grids */

/* ---------- Section scaffolding ---------- */
/* Was a flat 110px top and bottom. The homepage ran to 12,447px for 1,221 words
   â€” roughly ten pixels of scroll per word â€” so this is now the fluid --space-l
   step, which lands ~30-40% tighter on desktop without removing any content. */
.section { padding-block: var(--space-l); }
.eyebrow {
  font-size: 11px; font-weight: 600; letter-spacing: .2em;
  text-transform: uppercase; color: var(--clay);
  display: block; margin-bottom: 14px;
}
.eyebrow::before { display:none; }
/* 16ch capped every section heading at under 40% of the row, so each one wrapped
   to three or four lines and left a void beside it. 24ch plus `pretty` (which
   fills the first line instead of balancing them evenly) drops the average to
   under two lines. On phones the clamp floor makes 24ch wider than the screen,
   so this is a desktop and tablet change only â€” mobile wrapping is untouched. */
.section-title { font-size: clamp(30px, 3.6vw, 46px); max-width: 24ch; text-wrap: pretty; }
/* Centred headings still read better balanced than filled. */
.gallery-cta .section-title, .cta-panel h2 { text-wrap: balance; }

/* ---------- Reveal animation ----------
   Only opacity and transform are animated, so each reveal stays on the
   compositor and never triggers layout or paint.

   Gated behind html.js: main.js sets that class in <head>. Without it nothing
   is hidden, so if JavaScript is blocked or errors the content is simply
   visible rather than stuck at opacity:0 forever.

   Timing was .9s with up to 320ms of stagger â€” the last card in a row could
   take 1.22s to arrive, which reads as lag rather than polish. Now .55s with a
   shorter rise, so it feels immediate while still being a reveal. */
.js .reveal {
  opacity: 0;
  transform: translateY(var(--reveal-rise, 16px));
  transition: opacity .55s var(--ease), transform .55s var(--ease);
  will-change: opacity, transform;
}
.js .reveal.in { opacity: 1; transform: none; }
/* Drop the compositor hint once the element has arrived â€” keeping will-change
   on dozens of elements permanently costs memory for no benefit. */
.js .reveal.done { will-change: auto; }

/* Less travel on small screens: the same 16px rise reads as a bigger, slower
   move relative to a narrow viewport. */
@media (max-width: 560px) {
  .js .reveal { --reveal-rise: 10px; transition-duration: .45s; }
}

/* ---------- Footer ---------- */
.site-footer {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background:
    linear-gradient(90deg, rgba(8, 7, 34, .96) 0%, rgba(8, 7, 34, .9) 48%, rgba(8, 7, 34, .95) 100%),
    #0b0a27;
  color: var(--paper-warm);
  padding-block: clamp(58px, 8vw, 116px) var(--space-m);
}
/* The photograph is only decorative and sits below the fold. Adding it when the
   footer approaches the viewport preserves the composed footer while keeping it
   out of the first-page network waterfall. */
.site-footer.is-background-loaded {
  background:
    linear-gradient(90deg, rgba(8, 7, 34, .96) 0%, rgba(8, 7, 34, .9) 48%, rgba(8, 7, 34, .95) 100%),
    url('/images/residential/mantri-pinnacle/mantri-pinnacle-featured-grand-living-room.webp') center 48% / cover no-repeat,
    #0b0a27;
}
.site-footer::before,
.site-footer::after { content: ''; position: absolute; inset: 0; pointer-events: none; z-index: -1; }
.site-footer::before {
  inset: -28% -10%;
  background: radial-gradient(circle at 15% 32%, rgba(186, 143, 77, .18), transparent 25%), radial-gradient(circle at 84% 18%, rgba(75, 86, 185, .2), transparent 30%), radial-gradient(circle at 54% 105%, rgba(197, 151, 89, .13), transparent 33%);
  filter: blur(18px);
  animation: footer-aurora 16s ease-in-out infinite alternate;
}
.site-footer::after {
  opacity: .18;
  background-image: linear-gradient(90deg, transparent 0, transparent calc(25% - 1px), rgba(255,255,255,.14) 25%, transparent calc(25% + 1px), transparent calc(50% - 1px), rgba(255,255,255,.12) 50%, transparent calc(50% + 1px), transparent calc(75% - 1px), rgba(255,255,255,.1) 75%, transparent calc(75% + 1px)), linear-gradient(0deg, transparent 0, transparent 68%, rgba(255,255,255,.1) 68.1%, transparent 68.4%);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
@keyframes footer-aurora { from { transform: translate3d(-2%, -1%, 0) scale(1); } to { transform: translate3d(3%, 3%, 0) scale(1.08); } }
/* Was 1.4fr .8fr 1fr 1fr collapsing straight to a single column at 880px, with
   no two-column step for tablets and large phones. Now it steps 4 -> 2 -> 1 on
   its own as the viewport narrows.

   Track 3 is sized at roughly double its neighbours because it carries the nine
   services in two sub-columns. It is width, not a span: making that third item
   span two tracks turned four columns into five slots, which wrapped "Get in
   touch" onto a second row with three empty columns beside it.

   The minimums are 0 deliberately. Intrinsic minimums on all four tracks
   (210/130/250/190) plus three gaps exceed the wrap just under 1024px, so the
   last column overflowed the grid instead of the tracks sharing the shortfall. */
.footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .62fr) minmax(0, 1.85fr) minmax(0, .88fr);
  gap: clamp(28px, 5vw, 88px);
  padding-bottom: clamp(36px, 5vw, 70px);
  border-bottom: 1px solid rgba(255,255,255,.15);
}
/* Flex-wrap, not grid. As a grid the wordmark was locked into a `minmax(0,1fr)`
   track sized by the footer column, and "Candidscape" is a single unbreakable
   word — at 1024-1440 it measured ~166px against a ~133px track and spilled
   over the Navigate column beside it. Wrapping lets it drop under the logo
   when the column is too narrow instead of overflowing it. */
.footer-brand { display: flex; flex-wrap: wrap; align-items: center; row-gap: 6px; max-width: 280px; margin-bottom: 20px; }
.footer-brand a { display: inline-flex; align-items: center; flex: 0 0 auto; }
.footer-brand img { height: clamp(56px, 5.6vw, 78px); width: auto; }
.footer-brand p { flex: 1 0 100%; margin: 14px 0 0; font-size: 14px; line-height: 1.55; }
/* Two even columns on tablets: brand + Navigate, then Services + Get in touch.
   Services used to take this whole row on its own, which left Get in touch
   alone on a third row with an empty column beside it. */
@media (max-width: 980px) and (min-width: 641px) {
  .footer-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 44px 58px; }
}

.site-footer p { color: #b5afa0; font-size: 15px; max-width: 36ch; }
.footer-col h3 { font-family: 'Montserrat', sans-serif; font-size: 12px; letter-spacing: .2em; text-transform: uppercase; color: #fff; margin-bottom: 16px; font-weight: 600; }

/* Footer links were 24px tall â€” well under the 44px minimum hit area. They are
   now flex rows with a real minimum height, which also spaces the list better
   on phones without needing a breakpoint. */
.footer-col a, .footer-col span {
  display: flex; align-items: center; min-height: 44px;
  color: #b5afa0; font-size: 15px; line-height: 1.45;
  transition: color .3s;
}
.footer-col span { min-height: 0; padding-block: 10px; }
.footer-col a:hover, .footer-col a:focus-visible { color:#ffffff; }
.footer-bottom {
  display: flex; justify-content: space-between; align-items: center;
  padding-top: var(--space-s); font-size: 13px; color: #8a857a;
  flex-wrap: wrap; gap: 10px;
}
.footer-managed-link {
  color: var(--gold-lit);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: rgba(232, 205, 142, .55);
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
}
.footer-managed-link:hover,
.footer-managed-link:focus-visible {
  color: var(--white);
  text-decoration-color: currentColor;
}
.footer-bottom .gst { letter-spacing: .04em; }

/* On phones the four footer columns stack, so give each a visible divider
   rather than leaving them running together as one undifferentiated list. */
@media (max-width: 640px) {
  .site-footer { padding-top: 40px; }
  /* minmax(0, …) rather than 1fr: a plain fr keeps an auto minimum, which lets
     a long unbroken address or email push the single column wider than the
     phone viewport. */
  .footer-grid { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .site-footer .footer-grid > * { padding-block: 24px; }
  .site-footer .footer-grid > *:first-child { padding-top: 0; }
  .site-footer .footer-grid > * + * { border-top: 1px solid rgba(255,255,255,.10); }
  .footer-brand { margin-bottom: 0; max-width: 100%; }
  .footer-brand img { height: 52px; }
  .footer-col h3 { margin-bottom: 10px; }
  .footer-col a { min-height: 44px; }
  .footer-col span { padding-block: 8px; }
  .footer-grid > .footer-col:last-child a {
    margin-top: 8px; padding-inline: 14px; border: 1px solid rgba(255,255,255,.14);
    border-radius: 8px; background: rgba(255,255,255,.04);
  }
  .footer-grid > .footer-col:last-child span { padding-bottom: 0; }
  .footer-services { column-gap: 12px; }
  .footer-services a { font-size: 13px; line-height: 1.3; overflow-wrap: anywhere; }
  .footer-bottom { justify-content: flex-start; flex-direction: column; align-items: flex-start; padding-top: 20px; gap: 6px; line-height: 1.5; }
}

/* .ph / .ph span deleted â€” styled an image placeholder that no markup on the
   site has ever used. */

@media (max-width: 880px) {
  /* Keep the navigation panel attached to the viewport on mobile browsers. */
  .site-header { background:var(--paper); -webkit-backdrop-filter:none; backdrop-filter:none; }
  .nav-links {
    position: fixed; inset:76px 0 calc(56px + env(safe-area-inset-bottom, 0px)); z-index:101;
    min-height:calc(100dvh - 132px - env(safe-area-inset-bottom, 0px)); flex-direction:column;
    background:var(--paper);
    padding:20px 24px calc(24px + env(safe-area-inset-bottom, 0px)); gap:0; border-bottom:1px solid var(--line);
    transform:translateY(-110%); opacity:0; visibility:hidden; pointer-events:none;
    transition:transform .4s var(--ease),opacity .25s ease,visibility .25s; align-items:stretch;
    overflow-y:auto; overscroll-behavior:contain;
  }
  .nav-links.open { transform:none; opacity:1; visibility:visible; pointer-events:auto; }
  .mobile-menu-intro { display:none; }
  .mobile-menu-intro span { color:var(--clay); font-size:11px; font-weight:700; letter-spacing:.2em; text-transform:uppercase; }
  .mobile-menu-intro p { color:var(--ink-soft); font-weight:500; font-size:23px; line-height:1.2; letter-spacing:-.02em; max-width:18ch; margin-top:12px; }
  .nav-links > a { width:100%; min-height:52px; padding:13px 0; font-size:17px; color:var(--ink); border-bottom:1px solid var(--line); }
  .nav-links a::after { display:none; }
  .nav-links a.active { color:var(--clay); }
  .nav-services { width:100%; border-bottom:1px solid var(--line); }
  .services-menu::before { content:none; }
  .nav-services-trigger { justify-content:space-between; }
  .nav-services-trigger > a { flex:1; min-height:52px; padding:13px 0; font-size:17px; color:var(--ink); }
  .services-toggle { width:48px; height:52px; margin-right:0; border-left:1px solid var(--line); }
  .services-toggle span { width:8px; height:8px; }
  .nav-services:hover .services-menu, .nav-services:focus-within .services-menu { opacity:0; visibility:hidden; transform:translateY(-8px); pointer-events:none; }
  /* Inline accordion: no card, it sits inside the full-screen nav panel. */
  .nav-services.services-open .services-menu { position:static; width:auto; max-width:none; padding:2px 0 16px; background:transparent; border:0; box-shadow:none; opacity:1; visibility:visible; transform:none; pointer-events:auto; }
  .nav-services.services-open .services-toggle { color:var(--clay); }
  .nav-services.services-open .services-toggle span { transform:rotate(225deg) translate(-1px,-2px); }
  .services-menu-cols { grid-template-columns:1fr; gap:0; }
  .services-col { grid-template-columns:1fr; }
  .services-col-title { padding:14px 0 4px; font-size:10px; letter-spacing:.16em; }
  .services-menu a { padding:10px 0 10px 14px; min-height:42px; font-size:14px; color:var(--ink-soft) !important; border-left:1px solid var(--line); }
  .services-menu a:hover, .services-menu a:focus-visible { background:transparent; color:var(--clay) !important; }
  .services-menu a.is-current { background:transparent; color:var(--clay) !important; border-left-color:var(--clay); box-shadow:inset 1px 0 0 var(--clay); }
  .services-menu-all { display:none !important; }
  .menu-toggle { display:inline-flex; position:relative; z-index:102; touch-action:manipulation; }
  .menu-toggle-label { display:none; }
  .nav { gap:12px; }
  .nav-links .nav-cta { width:100%; min-height:50px; justify-content:center; padding:13px 18px !important; font-size:12px !important; margin-top:20px; border:0; border-radius:6px; }
  /* .section and .footer-grid overrides removed â€” both are fluid now. */
}

@media (max-width: 420px) {
  .wrap { padding-left: 20px; padding-right: 20px; }
  .brand img { height: 34px; }
  .menu-toggle { min-width:42px; width:42px; height:42px; padding:0; }
}

/* ---------- Design & Build section ---------- */
.db-section { border-top:1px solid var(--line); border-bottom:1px solid var(--line); background:var(--white); }
/* Explicit two-by-two placement. The heading is capped at 16ch, so letting it
   span the full width left a tall empty band to its right; the picture now
   occupies exactly that band and stops there. Row two carries the copy and the
   points, which start level with each other. */
.db-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); column-gap:var(--space-m); row-gap:clamp(26px,3vw,42px); align-items:stretch; }
.db-head { grid-column:1; grid-row:1; min-width:0; align-self:start; }
.db-figure { grid-column:2; grid-row:1; }
.db-text { grid-column:1; grid-row:2; min-width:0; }
.db-points { grid-column:2; grid-row:2; }
.db-text p { color:var(--ink-soft); font-size:17px; margin-top:18px; line-height:1.7; }
.db-text p:first-child { margin-top:0; }
/* The picture is positioned out of flow so its natural 3:2 ratio cannot dictate
   the row height â€” otherwise it grew to 386px and dragged a band of empty space
   in beside the heading. Height now comes from min-height, or from the heading
   when that wraps taller, and the image crops to fill whatever it gets. */
.db-figure { position:relative; min-height:clamp(220px,18vw,264px); margin:0; overflow:hidden; border-radius:10px; background:var(--paper-warm); box-shadow:var(--shadow); }
.db-figure img { position:absolute; inset:0; display:block; width:100%; height:100%; object-fit:cover; object-position:center; transition:transform .7s var(--ease); }
@media (hover:hover) { .db-figure:hover img { transform:scale(1.035); } }
.db-points { list-style:none; padding:0; }
.db-points li { padding:22px 0; border-bottom:1px solid var(--line); }
.db-points li:first-child { border-top:1px solid var(--line); }
/* An explicit weight, not the UA's bold for <strong>. Montserrat's variable
   wght axis covers 100â€“900, so any weight named here is a real instance and
   never a synthesised faux bold. 600 is the sub-heading weight used throughout. */
.db-points li strong { display:block; font-weight:600; font-size:20px; letter-spacing:-.015em; margin-bottom:6px; }
.db-points li span { color:var(--ink-soft); font-size:15px; line-height:1.65; }

/* Stacked, there is no second column to stretch against, so the placement is
   dropped and the figure takes an explicit ratio. Source order then reads
   heading, picture, copy, points. */
@media (max-width:880px) {
  .db-grid { grid-template-columns:minmax(0,1fr); row-gap:26px; }
  .db-head, .db-figure, .db-text, .db-points { grid-column:auto; grid-row:auto; }
  .db-figure { min-height:0; aspect-ratio:16 / 10; }
}
@media (max-width:560px) {
  .db-figure { aspect-ratio:4 / 3; }
  .db-points li { padding:18px 0; }
}
@media (prefers-reduced-motion: reduce) {
  .db-figure img { transition:none; }
  .db-figure:hover img { transform:none; }
}

/* ============================================================
   UNIFIED CONTACT DOCK
   Replaces the separate WhatsApp bubble with one paired contact control.
   Desktop keeps it compact at the lower-right; phones receive the same two
   actions as a full-width, thumb-friendly bottom bar.
   ============================================================ */
.wa-float { display:none !important; }
.contact-dock {
  position:fixed; right:24px; bottom:24px; z-index:130;
  display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
  min-width:258px; overflow:hidden;
  border:1px solid rgba(255,255,255,.16); border-radius:9px;
  background:var(--noir); box-shadow:0 14px 34px rgba(20,19,42,.22);
  animation:contact-dock-in .65s var(--ease-soft) .35s both;
}
.contact-dock a {
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  min-height:50px; padding:12px 16px;
  color:var(--white); font-size:12px; font-weight:600; letter-spacing:.04em;
  transition:background-color .3s var(--ease), color .3s var(--ease), transform .3s var(--ease);
}
.contact-dock a + a { border-left:1px solid rgba(255,255,255,.16); }
.contact-dock .is-wa { background:#1f8f4e; }
.contact-dock svg { flex:0 0 auto; }
@media (hover:hover) {
  .contact-dock a:hover, .contact-dock a:focus-visible { transform:translateY(-2px); background:#17162f; }
  .contact-dock .is-wa:hover, .contact-dock .is-wa:focus-visible { background:#197744; }
}
@keyframes contact-dock-in { from { opacity:0; transform:translate3d(0, 12px, 0); } to { opacity:1; transform:none; } }
@media (max-width:880px) {
  .contact-dock { right:0; bottom:0; left:0; min-width:0; width:100%; border:0; border-radius:0; box-shadow:0 -8px 26px rgba(20,19,42,.16); padding-bottom:env(safe-area-inset-bottom, 0px); }
  .contact-dock a { min-height:56px; font-size:14px; }
  .site-footer { padding-bottom:calc(var(--space-m) + 56px + env(safe-area-inset-bottom, 0px)); }
}
@media (prefers-reduced-motion:reduce) { .contact-dock { animation:none; } .contact-dock a { transition:none; } }

/* Typography reset: a single restrained Montserrat system keeps the site
   minimal and avoids a decorative serif appearing in isolated components. */
h1, h2, h3, h4,
.hero-project-card strong,
.stat-figure,
.reserved h3,
.testimonial-card::before,
.testimonial-card blockquote,
.footer-wordmark,
.nav-links > a:not(.nav-cta),
.nav-services-trigger > a {
  font-family: 'Montserrat', sans-serif !important;
}/* ---------- Process steps ---------- */
.process-step { background:var(--white); padding:34px 28px; }
.process-step .step-num { font-weight:700; font-size:38px; letter-spacing:-.045em; color:var(--clay); line-height:1; margin-bottom:14px; }
.process-step h3 { font-size:20px; margin-bottom:10px; }
.process-step p { color:var(--ink-soft); font-size:15px; line-height:1.6; }

/* ---------- Picture card: industries + featured projects ----------
   One component, two users. Separated tiles with a 16:10 crop, clay category
   label, serif title and a CTA line, rather than the flat hairline table the
   industries section used to be and the borderless thumbnails the projects
   section used to be. The whole tile is the link, so the click target is the
   card rather than the title text.
   Deliberately not folded into .svc-band's rules â€” that component is scoped to
   its own section and carries layout quirks for a nine-card grid. */
.industries-section { border-top:1px solid var(--line); border-bottom:1px solid var(--line); background:var(--paper); }
/* Both grids are declared here, above the shared breakpoints below. Declaring
   .proj-grid later in the file gave it the same specificity but a later source
   position, so it beat those breakpoints and stayed four-across on tablets. */
.industries-grid, .proj-grid { display:grid; grid-template-columns:repeat(4, minmax(0, 1fr)); gap:16px; }
.industries-grid { margin-top:var(--space-m); }
.industry-card, .proj-card {
  display:flex; flex-direction:column; overflow:hidden; position:relative;
  border:1px solid var(--line); border-radius:10px; background:var(--white);
  color:inherit; text-decoration:none;
  box-shadow:0 2px 8px rgba(20,19,42,.04);
  transition:transform .4s var(--ease), box-shadow .4s var(--ease), border-color .4s var(--ease);
}
.industry-card:hover, .proj-card:hover { transform:translateY(-5px); border-color:color-mix(in srgb, var(--clay) 42%, var(--line)); box-shadow:0 18px 36px rgba(20,19,42,.12); z-index:1; }
.industry-card:focus-visible, .proj-card:focus-visible { outline:3px solid var(--clay); outline-offset:3px; }
.industry-card:hover h3, .proj-card:hover h3 { color:var(--clay); }
.industry-card-media, .proj-card-media { aspect-ratio:16 / 10; overflow:hidden; background:var(--ink); }
.industry-card-media img, .proj-card-media img { display:block; width:100%; height:100%; object-fit:cover; object-position:center; transition:transform .7s var(--ease); }
.industry-card:hover .industry-card-media img,
.proj-card:hover .proj-card-media img { transform:scale(1.06); }
.industry-card-body, .proj-card-body { display:flex; flex:1 1 auto; flex-direction:column; min-width:0; padding:24px 24px 26px; }
.industry-card .idx, .proj-card .meta { color:var(--clay); font-size:11px; font-weight:600; letter-spacing:.2em; text-transform:uppercase; }
.industry-card h3, .proj-card h3 { margin:13px 0 11px; font-size:clamp(22px, 1.6vw, 26px); line-height:1.1; text-wrap:balance; transition:color .3s var(--ease); }
/* The auto margin belongs on the CTA, not the copy. On the copy it pushed the
   paragraph to the card's bottom edge, opening a gap under every one-line title
   while the cards stretched to match the tallest. Moving it down keeps the CTAs
   aligned across the row and lets each paragraph sit under its own heading. */
.industry-card p, .proj-card p { color:var(--ink-soft); font-size:15px; line-height:1.6; }
.industry-card-body::after, .proj-card-body::after { content:'Explore service  \2192'; margin-top:auto; padding-top:20px; color:var(--clay); font-size:11px; font-weight:700; letter-spacing:.13em; text-transform:uppercase; }

@media (max-width:1180px) { .industries-grid, .proj-grid { grid-template-columns:repeat(2, minmax(0, 1fr)); } }
@media (max-width:760px) { .industries-grid, .proj-grid { gap:12px; } .industry-card-body, .proj-card-body { padding:20px; } }
@media (max-width:520px) { .industries-grid, .proj-grid { grid-template-columns:1fr; } }
@media (hover:none) { .industry-card:hover, .proj-card:hover { transform:none; box-shadow:0 2px 8px rgba(20,19,42,.04); } }
@media (prefers-reduced-motion: reduce) {
  .industry-card, .proj-card, .industry-card-media img, .proj-card-media img,
  .industry-card h3, .proj-card h3 { transition:none; }
  .industry-card:hover, .proj-card:hover { transform:none; }
  .industry-card:hover .industry-card-media img,
  .proj-card:hover .proj-card-media img { transform:none; }
}

/* ---------- Why section expanded ---------- */
.why-grid-6 { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr)); gap:var(--space-m); margin-top:var(--space-m); }
.why-grid-6 .why-item h3 { margin-bottom:12px; color:var(--paper); font-size:20px; }
.why-grid-6 .why-item p { color:#b5afa0; font-size:15px; line-height:1.6; }

/* The Areas section (.areas-section / .areas-collage / .areas-image) lived here
   and has been removed along with its markup on the homepage. */

/* ---------- Clients choose ---------- */
.choose-list { list-style:none; padding:0; margin-top:38px; max-width:68ch; }
.choose-list li { padding:18px 0; border-bottom:1px solid var(--line); color:var(--ink-soft); font-size:16px; line-height:1.6; }
.choose-list li:first-child { border-top:1px solid var(--line); }

/* ---------- Home-page enquiry form ----------
   Was a two-column band: an argument on the left, the form squeezed into a
   360px rail on the right. The argument has gone (it was the page's fourth
   restatement of the same point) and the form now has the band to itself,
   centred and capped at a readable width, with the short fields paired. */
.home-enquiry-section { background:var(--paper-warm); }
.home-enquiry-single { max-width:720px; margin-inline:auto; }
.home-enquiry-intro { text-align:center; margin-bottom:var(--space-m); }
.home-enquiry-intro .section-title { margin-inline:auto; }
.home-contact-card { padding:clamp(26px, 3vw, 38px); border:1px solid var(--line); border-radius:4px; background:var(--white); box-shadow:var(--shadow); }
.home-contact-intro { margin:14px auto 0; color:var(--ink-soft); font-size:15px; line-height:1.6; max-width:48ch; }
.home-contact-form .field { margin-bottom:16px; }
/* Name+phone and email+service pair up on one row each; the project line runs
   full width beneath them. auto-fit rather than a breakpoint, so it collapses
   to one column continuously as the card narrows. */
.home-form-row { display:grid; grid-template-columns:repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap:0 20px; }
.home-contact-form .btn { width:100%; justify-content:center; min-height:52px; }
.home-contact-form .form-note { margin-bottom:0; }
@media (max-width:560px) { .home-contact-card { padding:24px 20px; } }

/* ---------- Blog placeholder ---------- */
.blog-preview { border-top:1px solid var(--line); }
.blog-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr)); gap:var(--space-s); margin-top:var(--space-m); }
.blog-card { padding:28px 24px; border:1px solid var(--line); background:var(--white); }
.blog-card h3 { font-size:19px; margin-bottom:8px; }
.blog-card p { color:var(--ink-soft); font-size:14px; }

/* ---------- Testimonials placeholder ---------- */
.testimonials-band { background:var(--ink); color:var(--paper); }
.testimonials-band .eyebrow { color:#c9a36a; }
.testimonials-band .eyebrow::before { background:#c9a36a; }
.testimonial-note { color:#b5afa0; font-size:16px; max-width:50ch; margin-top:20px; }/* ---------- Consultation steps ---------- */
.consult-step { background:var(--paper); padding:34px 28px; }
.consult-step .step-num { font-weight:700; font-size:38px; letter-spacing:-.045em; color:var(--clay); line-height:1; margin-bottom:14px; }
.consult-step h3 { font-size:20px; margin-bottom:10px; }
.consult-step p { color:var(--ink-soft); font-size:15px; line-height:1.6; }

/* ---------- Page-level FAQ (Home / About) ---------- */
.page-faq { border-top:1px solid var(--line); background:var(--white); }
.page-faq-list { max-width:860px; margin-top:38px; }
.page-faq-list details { border-top:1px solid var(--line); }
.page-faq-list details:last-child { border-bottom:1px solid var(--line); }
.page-faq-list summary { cursor:pointer; position:relative; font-weight:600; font-size:20px; letter-spacing:-.015em; padding:21px 48px 21px 0; list-style:none; line-height:1.35; }
.page-faq-list summary::-webkit-details-marker { display:none; }
.page-faq-list summary::after { content:'+'; position:absolute; right:3px; top:17px; color:var(--clay); font:300 30px/1 'Montserrat',sans-serif; transition:transform .25s var(--ease); }
.page-faq-list details[open] summary::after { transform:rotate(45deg); }
.page-faq-list p { color:var(--ink-soft); padding:0 20px 24px 0; font-size:16px; line-height:1.68; max-width:72ch; }

/* ---------- Editorial FAQ ----------
   The questions become a numbered, responsive conversation instead of a
   full-width utility list. Each native <details> element remains keyboard and
   screen-reader friendly; motion is only a visual enhancement. */
.page-faq { background:linear-gradient(135deg, var(--white) 0%, var(--paper-warm) 100%); }
.page-faq-grid { display:grid; grid-template-columns:minmax(230px, .7fr) minmax(0, 1.3fr); gap:clamp(34px, 7vw, 110px); align-items:start; }
.page-faq-intro { position:sticky; top:96px; align-self:start; }
.page-faq-intro .section-title { max-width:13ch; font-size:clamp(28px, 3.25vw, 42px); line-height:1.1; }
.page-faq-intro > p { max-width:31ch; margin-top:18px; color:var(--ink-soft); font-size:15px; line-height:1.7; }
.page-faq-contact { display:inline-flex; align-items:center; gap:10px; min-height:42px; margin-top:26px; color:var(--ink); font-size:11px; font-weight:600; letter-spacing:.08em; text-transform:uppercase; border-bottom:1px solid var(--ink); }
.page-faq-contact span { font-size:16px; transition:transform .3s var(--ease); }
.page-faq-contact:hover span, .page-faq-contact:focus-visible span { transform:translateX(4px); }
.page-faq-list { max-width:none; margin-top:0; counter-reset:faq; border-top:1px solid var(--line); }
.page-faq-list details { position:relative; counter-increment:faq; overflow:hidden; border:0; border-bottom:1px solid var(--line); transition:background-color .35s var(--ease), padding .35s var(--ease), box-shadow .35s var(--ease); }
.page-faq-list details::before { content:''; position:absolute; top:0; bottom:0; left:0; width:2px; background:var(--gold); transform:scaleY(0); transform-origin:top; transition:transform .4s var(--ease); }
.page-faq-list details:hover, .page-faq-list details[open] { background:rgba(255,255,255,.7); box-shadow:0 10px 28px rgba(20,19,42,.045); }
.page-faq-list details[open] { padding-left:clamp(14px, 2vw, 24px); }
.page-faq-list details[open]::before { transform:scaleY(1); }
.page-faq-list summary { display:grid; grid-template-columns:42px minmax(0, 1fr) 32px; align-items:center; gap:12px; min-height:82px; padding:18px 0; color:var(--ink); font-size:clamp(16px, 1.55vw, 21px); font-weight:500; letter-spacing:-.025em; line-height:1.3; }
.page-faq-list summary::before { content:'0' counter(faq); color:var(--clay); font-size:10px; font-weight:600; letter-spacing:.16em; }
.page-faq-list summary::after { position:static; justify-self:end; display:grid; place-items:center; width:30px; height:30px; border:1px solid var(--line); border-radius:0; color:var(--clay); font:300 24px/1 'Montserrat',sans-serif; transition:transform .3s var(--ease), background-color .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease); }
.page-faq-list details[open] summary::after { transform:rotate(45deg); background:var(--clay); border-color:var(--clay); color:var(--white); }
.page-faq-list summary:focus-visible { outline:2px solid var(--clay); outline-offset:-2px; }
.page-faq-list p { max-width:58ch; margin:0 38px 0 54px; padding:0 0 26px; color:var(--ink-soft); font-size:15px; line-height:1.72; animation:faq-answer-in .42s var(--ease) both; }
@keyframes faq-answer-in { from { opacity:0; transform:translateY(-7px); } to { opacity:1; transform:none; } }
@media (max-width:800px) { .page-faq-grid { grid-template-columns:1fr; gap:28px; } .page-faq-intro { position:static; } .page-faq-intro .section-title { max-width:17ch; } }
@media (max-width:560px) { .page-faq-intro .section-title { font-size:clamp(25px, 7vw, 30px); } .page-faq-intro > p { font-size:14px; margin-top:14px; } .page-faq-contact { margin-top:20px; } .page-faq-list summary { grid-template-columns:32px minmax(0, 1fr) 28px; gap:9px; min-height:68px; font-size:16px; } .page-faq-list summary::after { width:26px; height:26px; font-size:21px; } .page-faq-list details[open] { padding-left:12px; } .page-faq-list p { margin:0 8px 0 41px; padding-bottom:20px; font-size:14px; line-height:1.65; } }/* ---------- Mission & Vision (About) ---------- */
.mv-card { background:var(--white); padding:40px 34px; }
.mv-card h3 { font-size:24px; margin-bottom:14px; }
.mv-card p { color:var(--ink-soft); font-size:16px; line-height:1.65; }

/* The @media (max-width:880px) and (max-width:560px) blocks that used to sit
   here only re-declared grid-template-columns for .db-grid, .industries-grid,
   .mv-grid, .process-grid, .consult-grid, .why-grid-6 and .blog-grid. Every one
   of those grids is now intrinsically sized with auto-fit + minmax(), so it
   reflows continuously at every width instead of jumping at two breakpoints.
   Both blocks deleted â€” nothing replaces them. */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior:auto; }
  *, *::before, *::after { animation-duration:.01ms !important; animation-iteration-count:1 !important; scroll-behavior:auto !important; transition-duration:.01ms !important; }
  /* Must out-specify `.js .reveal` (0-2-0), or reveals would still start at
     opacity:0 for visitors who asked for no motion. */
  .reveal, .js .reveal { opacity:1 !important; transform:none !important; will-change:auto !important; }
}

/* ============================================================
   Breadcrumb â€” shared by the Services hub and every service page
   ============================================================ */
.breadcrumb { margin-bottom: clamp(20px, 3vw, 34px); }
.breadcrumb ol {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0; padding: 0; list-style: none;
  font-size: 12px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
}
.breadcrumb li { display: flex; align-items: center; gap: 8px; min-width: 0; }
.breadcrumb li + li::before { content: '/'; opacity: .45; font-weight: 400; }
.breadcrumb a { color: inherit; opacity: .72; transition: opacity .25s var(--ease); }
.breadcrumb a:hover, .breadcrumb a:focus-visible { opacity: 1; text-decoration: underline; text-underline-offset: 3px; }
.breadcrumb [aria-current='page'] { opacity: 1; }

/* ============================================================
   PAGE 3 â€” Services hub
   ============================================================ */
.services-hub { overflow-x: clip; }
.services-hub .section { padding-block: clamp(64px, 9vw, 118px); }/* ---------- Hero ---------- */
.svc-hero .wrap { width: 100%; min-width: 0; }
.svc-hero .breadcrumb { color: rgba(255,255,255,.86); }
.svc-hero .eyebrow { color: #f4d19d; }
.svc-hero .eyebrow::before { background: #f4d19d; }

/* ---------- Service grid ---------- */
.svc-grid-section { background: var(--paper); }
.svc-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 310px), 1fr));
  gap: clamp(20px, 2.4vw, 32px);
  margin: clamp(34px, 5vw, 56px) 0 0; padding: 0; list-style: none;
}
.svc-card { display: flex; min-width: 0; }
.svc-card-link {
  display: flex; flex-direction: column; width: 100%; min-width: 0;
  background: var(--white); border: 1px solid var(--line); border-radius: 10px;
  overflow: hidden; box-shadow: var(--shadow);
  transition: transform .45s var(--ease), box-shadow .45s var(--ease), border-color .45s var(--ease);
}
.svc-card-link:hover, .svc-card-link:focus-visible {
  transform: translateY(-6px);
  border-color: color-mix(in srgb, var(--clay) 34%, var(--line));
  box-shadow: 0 2px 4px rgba(20,19,42,.05), 0 22px 52px rgba(20,19,42,.14);
}
.svc-card-link:focus-visible { outline: 3px solid var(--clay); outline-offset: 3px; }

.svc-card-media { position: relative; display: block; overflow: hidden; background: var(--paper-warm); }
.svc-card-media::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(20,19,42,0) 55%, rgba(20,19,42,.28) 100%);
  opacity: 0; transition: opacity .45s var(--ease);
}
.svc-card-media img {
  width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; object-position: center;
  transition: transform .7s var(--ease);
}
.svc-card-link:hover .svc-card-media img,
.svc-card-link:focus-visible .svc-card-media img { transform: scale(1.06); }
.svc-card-link:hover .svc-card-media::after,
.svc-card-link:focus-visible .svc-card-media::after { opacity: 1; }

.svc-card-body {
  display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0;
  padding: clamp(22px, 2.4vw, 30px);
}
.svc-card-title {
  font-size: clamp(23px, 2.2vw, 29px); line-height: 1.14;
  margin-bottom: 12px; text-wrap: balance;
  transition: color .3s var(--ease);
}
.svc-card-link:hover .svc-card-title,
.svc-card-link:focus-visible .svc-card-title { color: var(--clay); }
.svc-card-copy {
  display: block; color: var(--ink-soft);
  font-size: clamp(14.5px, 1.25vw, 15.5px); line-height: 1.66;
  text-wrap: pretty; overflow-wrap: anywhere;
}
.svc-card-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.svc-tag {
  display: inline-block; padding: 6px 12px;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--paper);
  font-size: 11.5px; font-weight: 600; letter-spacing: .04em; line-height: 1.35;
  color: var(--ink-soft);
  transition: border-color .3s var(--ease), color .3s var(--ease);
}
.svc-card-link:hover .svc-tag, .svc-card-link:focus-visible .svc-tag {
  border-color: color-mix(in srgb, var(--clay) 28%, var(--line)); color: var(--ink);
}
.svc-card-cta {
  display: inline-flex; align-items: center; gap: 10px;
  margin-top: auto; padding-top: 24px;
  font-size: 12px; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: var(--clay);
}
.svc-card-arrow { transition: transform .35s var(--ease); }
.svc-card-link:hover .svc-card-arrow, .svc-card-link:focus-visible .svc-card-arrow { transform: translateX(5px); }

@media (max-width: 560px) {
  .services-hub .wrap { padding-inline: 20px; }
  .svc-card-body { padding: 22px 20px; }
}

@media (prefers-reduced-motion: reduce) {
  .svc-card-link, .svc-card-media img, .svc-card-arrow { transition: none !important; }
  .svc-card-link:hover, .svc-card-link:focus-visible { transform: none; }
  .svc-card-link:hover .svc-card-media img, .svc-card-link:focus-visible .svc-card-media img { transform: none; }
}

/* ============================================================
   PAGES 4â€“11 â€” Service detail pages
   (moved out of service-page-template.php so it is cached once
   instead of re-sent inline with every service page)
   ============================================================ */
.service-template-page { overflow-x: clip; }
.service-template-page .section { padding-block: clamp(64px, 9vw, 110px); }
.service-template-page img { background: var(--paper-warm); }
.service-template-page a:focus-visible,
.service-template-page summary:focus-visible { outline: 3px solid var(--clay); outline-offset: 4px; }/* ---------- Hero ---------- */
.res-hero .wrap {
  width: 100%; min-width: 0; max-width: none; margin: 0;
  padding-left: max(32px, calc((100vw - var(--maxw)) / 2 + 32px));
  padding-right: 32px;
}
.res-hero .breadcrumb { color: rgba(255,255,255,.86); }
.res-hero .eyebrow { color: #f4d19d; }
.res-hero .eyebrow::before { background: #f4d19d; }/* ---------- Intro ---------- */
.res-copy .section-title { font-size: clamp(34px, 4.4vw, 56px); text-wrap: balance; }/* ---------- Card grids ---------- */
/* Backgrounds, borders and hairlines come from the shared hairline-grid rules
   near the top of this file â€” only the track sizing lives here. *//* Reserve two lines for the title so body copy starts on the same baseline
   across a row, and pin the copy to the bottom of the card. */
.dark-band .eyebrow { color: #c9a36a; }
.dark-band .eyebrow::before { background: #c9a36a; }
.dark-band .section-title { color: var(--white); }

/* ---------- Projects ---------- */
.project-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: clamp(20px, 3vw, 30px); margin-top: clamp(28px, 4vw, 42px);
}
.project-card { display: flex; flex-direction: column; min-width: 0; }
.project-card img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; object-position: center;
  border-radius: 4px; box-shadow: var(--shadow); content-visibility: auto;
}
.project-card h3 { font-size: clamp(24px, 2.6vw, 31px); line-height: 1.15; margin: 18px 0 9px; text-wrap: balance; }
.project-card p { color: var(--ink-soft); font-size: clamp(15px, 1.35vw, 17px); line-height: 1.68; text-wrap: pretty; }

/* ---------- CTA ---------- */
.cta-panel { background: var(--paper-warm); text-align: center; padding: clamp(64px, 9vw, 88px) max(20px, 5vw); }
.cta-panel h2 { font-size: clamp(31px, 4.6vw, 58px); line-height: 1.16; margin: 0 auto 22px; max-width: 20ch; text-wrap: balance; }
.cta-panel p { color: var(--ink-soft); margin: 0 auto 30px; max-width: 50ch; }
.cta-panel .btn { min-height: 50px; justify-content: center; }

@media (max-width: 880px) {/* .res-intro column override removed â€” it is intrinsically sized now. The
     aspect-ratio change stays: a 4/5 portrait at full width is too tall once
     the intro stacks. */
}
@media (max-width: 560px) {
  .service-template-page .section { padding-block: 64px; }
  .res-hero .wrap { padding-inline: 20px; }
  .project-card h3 { margin-top: 16px; }
  .cta-panel { padding-inline: 20px; }
}/* ---------------------------------------------------------------
   Services hub â€” project gallery
   Added so the Home page's featured-project cards have a real
   /services#gallery target to link through to, as the content
   document requires. Reuses the existing .project-grid/.project-card
   rules; only the meta line and the through-link are new.
   --------------------------------------------------------------- */
.svc-gallery-section .project-card { scroll-margin-top: 96px; }
.svc-gallery-section .project-card h3 { margin-top: 8px; }/* ============================================================
   PROJECT GALLERY
   ============================================================ */
.gallery-hero > .wrap > p:last-child { max-width:58ch; margin-top:18px; color:var(--ink-soft); font-size:var(--step-0); line-height:1.65; }
.gallery-project-head .section-title { margin:0; }/* The gallery now uses the same six-column mosaic rhythm as the rest of the
   site, so a visitor arriving from the homepage meets the same visual language.

   It also fixes a sharpness problem: the old `--lead` tile spanned 8 of 12
   columns, displaying a 1400px photograph across ~820 CSS px and asking for
   1,640 device pixels on a 2x screen. Nothing here now exceeds 3 of 6 columns
   (~600px), which a 1400px source serves exactly. */
/* The lead modifier is retained in the markup but no longer changes the span â€”
   the rhythm above already gives the first tile prominence. */
.gallery-item--lead { grid-column:span 3; }
.gallery-cta .section-title { max-width:18ch; margin:0 auto 28px; }
/* The aspect ratio now lives on the item, not the image, so these overrides
   have to target the item â€” and out-specify the :nth-child rules above, which
   are (0,2,0). Hence the doubled class on each selector. */
@media (max-width:800px) {
  .gallery-item--lead.gallery-item--lead { grid-column:span 2; aspect-ratio:16 / 10; }
}
@media (max-width:520px) {
  .gallery-item.gallery-item, .gallery-item--lead.gallery-item--lead { grid-column:auto; aspect-ratio:4 / 3; }
}

/* ============================================================
   HOME  (index.php)
   Moved out of the page's inline <style> block. The .wrap and .btn/.btn-dark/
   .btn-line overrides it used to carry are deliberately NOT reproduced: the
   homepage now uses the shared 1240px container and the shared button
   component, so it matches every other page.
   ============================================================ */

/* ---------- Hero ---------- */
.hero-section-scope { --gold: #c9a36a; }
/* The hero art is a real <img> rather than a CSS background, so the preload
   scanner can discover it and fetchpriority applies. Was a 2,087 KB PNG loaded
   as background-image; now a 123 KB WebP with an art-directed mobile crop. */
.hero {
  position: relative; isolation: isolate;
  padding-block: var(--space-xl) var(--space-l);
  background: var(--ink);
}
.hero-bg {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}

/* ---------- Hero slideshow ----------
   Twelve projects across the portfolio. Every slide is absolutely positioned inside a
   container that already has its height from the hero's own padding, so adding
   or removing slides is structurally incapable of shifting layout â€” CLS cannot
   regress no matter how late slides 2-12 arrive.
   Crossfade is opacity only; the slow push-in is a transform. Neither costs a
   layout or a paint. */
.hero-cine { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.hero-slide {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity .65s var(--ease);
}
.hero-slide.is-active { opacity: 1; }
.hero-slide picture, .hero-slide img { display: block; width: 100%; height: 100%; }
.hero-slide .hero-bg { position: absolute; z-index: 0; }

/* Ken Burns. Deliberately slow and small â€” at 9s and 7% it should register as
   depth rather than as movement. Applied only while the slide is showing, so an
   off-screen slide is not animating. */
.hero-slide.is-active .hero-bg { animation: heroDrift 9s var(--ease) forwards; }
@keyframes heroDrift {
  from { transform: scale(1)    translateY(0); }
  to   { transform: scale(1.07) translateY(-1.2%); }
}

/* The .hero-feature-cap rules that sat here have gone with the caption panel.
   main.js already guards on the element being absent, so the slideshow simply
   stops updating a caption that no longer exists. */

/* Progress indicators. Each is a 3px bar in a 44px-tall hit area â€” the bar is
   what you see, the button is what you can actually hit. */
.hero-dots { display: flex; gap: 8px; margin-top: 18px; flex-wrap: wrap; }
.hero-dots:empty { display: none; }
.hero-dot {
  position: relative; width: 44px; height: 44px; padding: 20.5px 0;
  border: 0; background: none; cursor: pointer;
}
.hero-dot::before {
  content: ''; display: block; height: 3px; border-radius: 2px;
  background: rgba(255,255,255,.34);
}
.hero-dot::after {
  content: ''; position: absolute; left: 0; right: 0; top: 20.5px;
  height: 3px; border-radius: 2px; background: var(--gold);
  transform: scaleX(0); transform-origin: left center;
}
/* The active bar fills across exactly the slide's hold time, so the indicator
   is a real progress readout rather than decoration. */
.hero-dot.is-active::after { animation: heroDotFill var(--hold, 5.6s) linear forwards; }
.hero-dot.is-done::after { transform: scaleX(1); }
@keyframes heroDotFill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.hero-dot:focus-visible { outline: 3px solid rgba(255,255,255,.85); outline-offset: 2px; }

@media (max-width: 880px) {
  .hero-dots { margin-top: 14px; }
}

@media (prefers-reduced-motion: reduce) {
  /* No auto-advance (handled in main.js), no drift, no fades. The dots stay
     and stay clickable, so all six projects remain reachable â€” the slideshow
     becomes a manual gallery rather than disappearing. */
  .hero-slide { transition: none; }
  .hero-slide.is-active .hero-bg { animation: none; }
  .hero-dot.is-active::after { animation: none; transform: scaleX(1); }
}
/* Readability scrim. Every service page had one via .svc-hero::before; the
   homepage did not, because .hero lived in a file the service pages never see.
   Hero copy was white-on-photo with only a text-shadow behind it. */
/* Two scrims, not one.
   The vertical gradient alone left the headline sitting at about 45% opacity
   over whatever the slide happened to show â€” fine over a dark room, washed out
   over the full-height glazing on the RMZ slide. The horizontal gradient darkens
   the left, where the text is, and fades to nothing on the right, so the
   photograph keeps its brightness exactly where nothing is written on it.
   Both scrims were reduced on 10 August 2026. The two-scrim structure and the
   reasoning above are unchanged and still correct: only the strength moved.
   The previous values buried the photograph to reach ~11:1 against text that
   needs 4.5:1 (3:1 for the display H1) - two to three times the requirement,
   paid for in image.

   Measured by sampling the actual hero frames and compositing both gradient
   layers over the sampled average behind each text block:

     desktop  H1 15.95 -> 12.35 · lead 15.74 -> 10.79 · buttons 14.41 -> 10.04
     mobile   H1  9.93 -> ~5.6  · lead 14.19 -> ~7.9  · buttons 16.66 -> ~9.5

   Every value still clears AA several times over. The headroom is kept wide on
   purpose rather than trimmed to the floor: these are AVERAGES across each text
   block, and a photograph can carry a local highlight - a window, a lamp - well
   above its own mean.

   The photograph underneath is warm: sampled rgb(194,174,146) at the top of the
   mobile frame, rgb(104,81,55) behind the desktop headline. The scrim therefore
   uses a warm charcoal instead of the previous blue cast, keeping the interiors
   natural while preserving text contrast.

   `.hero-tag` does not constrain any of this. It carries its own
   rgba(20,19,42,.65) chip and stays legible independently of the scrim. */
.hero::before {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(95deg, rgba(20,20,20,.45) 0%, rgba(20,20,20,.30) 42%, rgba(20,20,20,.03) 78%),
    linear-gradient(180deg, rgba(20,20,20,.34) 0%, rgba(20,20,20,.19) 45%, rgba(20,20,20,.53) 100%);
}
/* Below 880px the text spans the full width, so the directional scrim would
   only darken one edge of it â€” a flat wash is correct there. */
@media (max-width: 880px) {
  .hero::before {
    background: linear-gradient(180deg, rgba(20,20,20,.38) 0%, rgba(20,20,20,.22) 45%, rgba(20,20,20,.55) 100%);
  }
}
.hero .wrap { position: relative; z-index: 3; }
/* Single column, not the previous two-track auto-fit.
   The second column existed to hold the project caption panel; with that gone
   it held only the slide dots, so at desktop width the headline was squeezed
   into half the viewport and wrapped to five lines while the dots floated in
   empty space beside it. One column lets the headline take a proper measure and
   puts the controls where controls belong â€” at the foot of the hero. */
.hero-grid {
  display: grid; grid-template-columns: 1fr;
  gap: var(--space-m); align-items: start;
}
.hero-feature { display: flex; flex-wrap: wrap; align-items: center; gap: 18px; justify-content: flex-start; }
.hero-content { min-width: 0; color: var(--paper); }
.hero-tag {
  display: inline-block; padding: 6px 10px; margin-bottom: var(--space-s);
  border-radius: 4px; background: rgba(20,19,42,.65); color: var(--paper);
  font-size: 11px; font-weight: 600; letter-spacing: .2em; text-transform: uppercase;
}
/* 15ch, and it now has the full column to spend it in â€” so the headline lands
   on three generous lines rather than five cramped ones. */
.hero h1 {
  max-width: 17ch; margin: 0 0 12px; color: var(--paper);
  font-family: 'Montserrat', sans-serif;
  font-size: clamp(40px, 5.15vw, 70px);
  font-weight: 400;
  letter-spacing: -.045em;
  line-height: 1.08;
  text-wrap: balance;
}
.hero h1 em { font-style: italic; }
.hero-lead {
  max-width: 56ch; margin: var(--space-s) 0 0; color: rgba(255,255,255,.92);
  font-size: clamp(15px, 1.35vw, 18px);
  font-weight: 400;
  line-height: 1.55;
  text-wrap: pretty;
}
.hero-lead + .hero-lead { margin-top: 14px; }
.hero-more { margin-top: 16px; max-width: 56ch; }
.hero-more summary { list-style: none; }
.hero-more summary::-webkit-details-marker { display: none; }
.hero-more-toggle {
  display: inline-flex; align-items: center; gap: 11px; min-height: 46px;
  padding: 11px 16px; border: 1px solid rgba(255,255,255,.42); border-radius: 999px;
  background: rgba(20,19,42,.38); color: var(--paper); cursor: pointer;
  font-size: 12px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  transition: background-color .28s var(--ease), border-color .28s var(--ease), transform .28s var(--ease), box-shadow .28s var(--ease);
}
.hero-more-toggle:hover, .hero-more-toggle:focus-visible { background: var(--paper); border-color: var(--paper); color: var(--ink); box-shadow: 0 10px 26px rgba(0,0,0,.2); transform: translateY(-2px); }
.hero-more-toggle:focus-visible { outline: 3px solid rgba(255,255,255,.8); outline-offset: 3px; }
.hero-more-toggle span:last-child { font-size: 17px; line-height: 1; transition: transform .32s var(--ease); }
.hero-more-close { display: none; }
.hero-more[open] .hero-more-open { display: none; }
.hero-more[open] .hero-more-close { display: inline; }
.hero-more[open] .hero-more-toggle span:last-child { transform: rotate(180deg); }
.hero-more-content { max-height: 0; overflow: hidden; padding-top: 0; color: rgba(255,255,255,.92); font-size: var(--step-0); line-height: 1.6; opacity: 0; transition: max-height .5s var(--ease), opacity .26s var(--ease), padding-top .42s var(--ease); }
.hero-more[open] .hero-more-content { max-height: 520px; padding-top: 16px; opacity: 1; }
.hero-more-content p { transform: translateY(-8px); transition: transform .42s var(--ease); }
.hero-more[open] .hero-more-content p { transform: translateY(0); }
.hero-more-content p + p { margin-top: 14px; }
@media (prefers-reduced-motion: reduce) {
  .hero-more-toggle, .hero-more-toggle span:last-child, .hero-more-content, .hero-more-content p { transition: none; }
}
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: var(--space-m); }
.hero-actions .btn {
  position: relative;
  min-height: 54px;
  padding-inline: 25px;
  border-radius: 8px;
  overflow: hidden;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .01em;
  box-shadow: 0 12px 28px rgba(0,0,0,.18);
}
.hero-actions .btn::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg, transparent 25%, rgba(255,255,255,.32) 50%, transparent 75%);
  transform: translateX(-120%);
  transition: transform .65s var(--ease);
}
.hero-actions .btn:hover::before { transform: translateX(120%); }
.hero-actions .btn > * { position: relative; z-index: 1; }
.hero-actions .btn-dark {
  background: linear-gradient(125deg, #f0d7aa, #c99b5c);
  color: #161126;
  box-shadow: 0 12px 30px rgba(16,12,36,.34), inset 0 1px rgba(255,255,255,.45);
}
.hero-actions .btn-dark:hover { background: linear-gradient(125deg, #f7e4bf, #d6a96b); }
.hero-actions .btn-ghost {
  border-color: rgba(255,255,255,.58);
  background: rgba(8,8,28,.26);
  backdrop-filter: blur(8px);
}

/* The homepage follows the same four-field enquiry pattern as Contact. The
   service selector was useful internally but slows visitors down before they
   have described their actual requirement. */
.home-contact-form .field:has(#home-service) { display: none; }
/* .page-contact #message was in this rule too, but it is an ID selector (1-1-0)
   and so outranked the contact card's own field sizing (0-4-1) — the message
   box rendered 50px tall beside 74px siblings. The contact page now takes its
   height from the .contact-brief field rule; the homepage is unchanged. */
.home-contact-form #home-message { min-height: 50px; }

/* Keep the homepage selection concise and remove the project name requested by
   the team; the completed photographs remain available through the full gallery. */
.page-home .mosaic > a[href*="mantri-pinnacle"] { display: none; }

/* A compact editorial plate identifies the room currently in view. It is kept
   separate from the headline so the hero remains an introduction first, and a
   gallery second. */
.hero-project-card {
  position: absolute; right: var(--space-s); bottom: var(--space-l);
  display: grid; gap: 5px; width: min(280px, 28vw); padding: 18px 20px;
  border: 1px solid rgba(255,255,255,.28); border-radius: 3px;
  background: rgba(7,7,35,.54); box-shadow: 0 18px 40px rgba(0,0,0,.18);
  backdrop-filter: blur(12px); color: var(--white); transition: opacity .28s var(--ease), transform .38s var(--ease);
}
.hero-project-card.is-swapping { opacity: 0; transform: translateY(8px); }
.hero-project-kicker { color: var(--gold); font-size: 10px; font-weight: 700; letter-spacing: .17em; text-transform: uppercase; }
.hero-project-card strong { font-family: 'Fraunces', Georgia, serif; font-size: clamp(1.35rem, 1.1rem + .8vw, 1.85rem); font-weight: 400; line-height: 1.05; letter-spacing: -.02em; }
.hero-project-card > span:not(.hero-project-kicker) { color: rgba(255,255,255,.76); font-size: 12px; letter-spacing: .04em; }
.hero-project-card a { display: inline-flex; align-items: center; gap: 8px; width: fit-content; margin-top: 6px; color: var(--white); font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; }
.hero-project-card a span { transition: transform .3s var(--ease); }
.hero-project-card a:hover span { transform: translateX(4px); }

/* The project panel is supporting detail, not permanent hero copy. On devices
   with a mouse it appears when the visitor explores the hero; keyboard focus
   follows the same path. Touch devices keep it visible because they have no
   hover state to reveal it. */
@media (hover: hover) and (pointer: fine) {
  .hero-project-card {
    opacity: 0;
    transform: translateY(10px);
    pointer-events: none;
  }
  .hero:hover .hero-project-card:not(.is-swapping),
  .hero-project-card:focus-within {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }
  .hero:hover .hero-project-card.is-swapping {
    opacity: 0;
    transform: translateY(8px);
  }
}

.hero-controls { display: grid; grid-template-columns: 44px minmax(0, auto) 44px; align-items: center; gap: 6px; }
.hero-controls .hero-dots { width: 100%; }
.hero-arrow { display: inline-grid; place-items: center; width: 44px; height: 44px; border: 1px solid rgba(255,255,255,.32); border-radius: 50%; background: rgba(20,19,42,.3); color: var(--white); cursor: pointer; font-size: 19px; line-height: 1; transition: background-color .25s var(--ease), border-color .25s var(--ease), transform .25s var(--ease); }
.hero-arrow:hover { border-color: var(--white); background: rgba(255,255,255,.14); transform: translateY(-2px); }
.hero-arrow:focus-visible { outline-color: var(--white); }

@media (max-width: 880px) {
  .hero-project-card { position: static; width: min(100%, 360px); margin-top: var(--space-s); opacity: 1; transform: none; pointer-events: auto; }
  .hero-feature { align-items: flex-start; flex-direction: column; gap: 4px; }
  .hero-controls { width: 100%; grid-template-columns: 44px minmax(0, 1fr) 44px; }
  .hero-dots { gap: 2px; margin-top: 0; }
}

/* Flex, not the previous fixed four-track grid. The band carries one stat now
   (Projects Delivered); a four-column grid would leave it in a quarter-width
   cell with three empty columns beside it. Flex lays out whatever is there. */
.hero-stats {
  display: flex; flex-wrap: wrap;
  gap: var(--space-s) var(--space-l);
  margin-top: var(--space-m); padding-top: var(--space-s);
  border-top: 1px solid rgba(255,255,255,.18); color: rgba(255,255,255,.95);
  position: relative; z-index: 1;
}
.hero-stats .stat { min-width: 0; }
.stat .num { font-weight: 700; font-size: var(--step-3); letter-spacing: -.045em; line-height: 1; }
.stat .num .dot { color: #f4d19d; }
.stat .lbl { margin-top: 8px; color: rgba(255,255,255,.85); font-size: 13px; letter-spacing: .06em; text-transform: uppercase; }
/* The original stat block remains in the markup for a no-JS-safe source, but
   the visible version now lives beside the slideshow controls. */
.hero > .wrap > .hero-stats { display: none; }
.hero-feature .hero-stats--inline {
  margin: 0;
  padding: 0 0 0 18px;
  border: 0;
  border-left: 1px solid rgba(255,255,255,.24);
}
.hero-stats--inline .stat { white-space: nowrap; }
@media (max-width: 880px) { .hero-stats { gap: var(--space-s) var(--space-m); } }

@media (max-width: 880px) {
  .hero-feature .hero-stats--inline {
    padding: var(--space-s) 0 0;
    border-left: 0;
    border-top: 1px solid rgba(255,255,255,.24);
  }
}

.hero-feature { position: relative; min-height: 1px; }
.hero-feature-cap {
  position: absolute; left: 16px; bottom: 16px; padding: 8px 14px; border-radius: 3px;
  background: rgba(20,19,42,.78); backdrop-filter: blur(4px); color: var(--paper);
  font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
}

/* ---------- Intro ---------- */
.intro-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr));
  gap: var(--space-m); align-items: center;
}
.intro-text p { margin-top: 22px; color: var(--ink-soft); font-size: var(--step-0); }

/* ---------- Home service cards ----------
   Scoped under .svc-band so they cannot collide with the Services hub, which
   uses the same .svc-grid / .svc-card class names for a different component. */
.svc-band { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--paper); }
.svc-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: var(--space-m); }
.svc-band .svc-grid,
.svc-band .svc-grid-sub {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px; margin: 0; padding: 0; list-style: none;
  background: transparent; border: 0;
}
.svc-band .svc-card {
  display: flex; flex-direction: column; justify-content: flex-start;
  min-height: 0; padding: 0; overflow: hidden; border:1px solid var(--line); border-radius:10px;
  background: var(--white); position: relative;
  box-shadow: 0 2px 8px rgba(20,19,42,.04);
  transition: background .4s var(--ease), transform .4s var(--ease), box-shadow .4s var(--ease);
}
.svc-band .svc-card:hover { background: #fff; transform: translateY(-5px); border-color:color-mix(in srgb, var(--clay) 42%, var(--line)); box-shadow:0 18px 36px rgba(20,19,42,.12); z-index: 1; }
.svc-band .svc-card-media { aspect-ratio: 16 / 10; background: var(--ink); }
.svc-band .svc-card-media img { height: 100%; aspect-ratio: auto; }
.svc-band .svc-card-content { display:flex; flex:1 1 auto; flex-direction:column; min-width:0; padding:24px 24px 26px; }
.svc-band .svc-card .idx { color: var(--clay); font-size:11px; font-weight:600; letter-spacing:.2em; text-transform:uppercase; }
.svc-band .svc-card h3 { margin:13px 0 11px; font-size:clamp(24px, 1.8vw, 29px); line-height:1.1; text-wrap:balance; }
.svc-band .svc-card p { color: var(--ink-soft); font-size:15px; line-height:1.6; margin-block-start:auto; max-width:none; display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:3; overflow:hidden; }
.svc-band .svc-card-content::after { content:'Explore service  \2192'; margin-top:20px; color:var(--clay); font-size:11px; font-weight:700; letter-spacing:.13em; text-transform:uppercase; }
.svc-sub-head { margin: var(--space-m) 0 22px; }

@media (min-width: 1181px) {
  .svc-band .svc-grid > .svc-card:last-child:nth-child(4n + 1) { flex-direction:row; }
  .svc-band .svc-grid > .svc-card:last-child:nth-child(4n + 1) .svc-card-media { flex:0 0 34%; aspect-ratio:auto; }
}

@media (hover: none) { .svc-band .svc-card:hover { transform:none; box-shadow:0 2px 8px rgba(20,19,42,.04); } }

/* Nine services do not divide evenly into four columns. Let the ninth card
   deliberately complete the row as a wide callout rather than leaving three
   empty-looking grid cells. */
.svc-band .svc-grid > .svc-card:last-child:nth-child(4n + 1) {
  grid-column: 1 / -1;
  min-height: 190px;
}

@media (max-width: 1180px) {
  .svc-band .svc-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .svc-band .svc-grid > .svc-card:last-child:nth-child(4n + 1) { grid-column: auto; }
}

@media (max-width: 760px) {
  .svc-band .svc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .svc-band .svc-grid > .svc-card:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .svc-band .svc-card-content { padding:20px; }
  .svc-band .svc-card h3 { font-size:23px; }
}

/* Below 520px a two-up picture card is ~230px wide â€” too narrow for a 23px
   serif heading and a three-line description. Match the industries grid and go
   single column, so both card rows behave the same way on a phone. */
@media (max-width: 520px) {
  .svc-band .svc-grid { grid-template-columns: minmax(0, 1fr); }
  .svc-band .svc-grid > .svc-card:last-child:nth-child(odd) { grid-column: auto; }
}

@media (max-width: 520px) {
  .svc-band .svc-grid { grid-template-columns: 1fr; }
  .svc-band .svc-grid > .svc-card:last-child:nth-child(odd) { grid-column: auto; }
}

/* ---------- Featured projects ----------
   Four across, matching the industries row. The card shell, media, type, hover
   and the grid itself all come from the shared picture-card rules above; only
   the CTA wording is specific to this section. */
/* Arrows in generated content are written as CSS unicode escapes, never as
   literal characters. This file has been through an encoding round-trip at some
   point in its history — several comments still carry the scars — and a literal
   arrow here came out the other side as "Ã¢â‚¬ â€™", which was rendering on every
   industry, project and service card on the site. An escape is decoded by the
   CSS parser from ASCII and cannot be corrupted by re-encoding the file. */
.proj-card-body::after { content: 'View project  \2192'; }

/* ---------- Why band ---------- */
.why { padding-block: var(--space-l); background: var(--ink); color: var(--paper); }
.why .eyebrow { color: #c9a36a; }
.why .eyebrow::before { background: #c9a36a; }
.why-item h3 { margin-bottom: 12px; color: var(--paper); font-size: var(--step-1); }
.why-item p { color: #b5afa0; font-size: var(--step--1); }
.why-item .k { color: #c9a36a; font-weight: 600; font-size: 13px; letter-spacing: .1em; }

/* ---------- Closing CTA ---------- */
.cta { padding-block: var(--space-l); text-align: center; }
.cta h2 { max-width: 18ch; margin: 0 auto 14px; font-size: var(--step-4); }
.cta p { color: var(--ink-soft); max-width: 54ch; margin: 0 auto 30px; font-size: var(--step-0); }

/* .hero-feature carried the only visible project caption and was display:none
   below 880px, so the caption vanished on phones. Rather than reserve 200px of
   empty box for an absolutely-positioned label, the caption becomes a static
   chip under the hero copy â€” it adapts instead of disappearing. */
@media (max-width: 880px) {
  .hero-feature { min-height: 0; }
  .hero-feature-cap { position: static; display: inline-block; margin-top: 4px; }
}

/* ============================================================
   SHARED PAGE HERO  (About, Contact)
   About and Contact each defined a near-identical .page-hero block inline.
   Consolidated into one component here.
   ============================================================ */
.page-hero { padding-block: var(--space-l) var(--space-m); }
.page-hero .eyebrow { justify-content: flex-start; }
/* 16ch held every page hero to about a third of the row, so each one broke into
   two short lines with a wide empty band beside it â€” the same cap that was
   throttling .section-title. 22ch plus `pretty` (which fills a line rather than
   balancing evenly) lets these sit on one line at desktop width. The font-size
   clamp floors well below 22ch on phones, so mobile wrapping is unaffected. */
.page-hero h1 { font-size: var(--step-5); max-width: 22ch; text-wrap: pretty; }
.page-hero p { font-size: var(--step-0); color: var(--ink-soft); max-width: 56ch; margin-top: var(--space-s); }

/* ============================================================
   ABOUT  (about.php)
   ============================================================ */
.story-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr));
  gap: var(--space-m); align-items: center;
}
.story-text p { color: var(--ink-soft); margin-top: 20px; font-size: var(--step-0); }

.who-bullets { list-style: none; padding: 0; margin-top: 24px; }
.who-bullets li {
  padding: 14px 0; border-bottom: 1px solid var(--line);
  color: var(--ink-soft); font-size: var(--step-0); line-height: 1.6;
}
.who-bullets li:first-child { border-top: 1px solid var(--line); }
.who-bullets li strong { font-weight: 600; }

.approach { background: var(--white); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.approach-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: var(--space-m); margin-top: var(--space-m);
}
.approach-item .n { font-weight: 700; font-size: var(--step-3); letter-spacing: -.045em; color: var(--clay); line-height: 1; }
.approach-item h3 { font-size: var(--step-1); margin: 16px 0 10px; }
.approach-item p { color: var(--ink-soft); font-size: var(--step--1); }/* Container background and hairlines come from the shared hairline-grid rules. */
.cred { background: var(--paper); padding: 36px 30px; }
.cred .lbl { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--clay); }
.cred .val { font-weight: 600; font-size: var(--step-1); letter-spacing: -.015em; margin-top: 10px; word-break: break-word; }
.clients-band .eyebrow { color: #c9a36a; }
.clients-band .eyebrow::before { background: #c9a36a; }
.client .nm { font-weight: 600; font-size: var(--step-1); letter-spacing: -.015em; color: var(--white); }
.client .ty { font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: #c9a36a; white-space: nowrap; }

.trust-text { color: var(--ink-soft); font-size: var(--step-0); line-height: 1.7; max-width: 68ch; margin-top: 22px; }

/* ============================================================
   CONTACT  (contact.php)
   ============================================================ */
.contact-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr));
  gap: var(--space-m); align-items: start;
}

.detail-block { margin-bottom: var(--space-m); padding-bottom: var(--space-m); border-bottom: 1px solid var(--line); }
.detail-block:last-child { border-bottom: none; }
.detail-block .lbl { font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: var(--clay); font-weight: 600; margin-bottom: 12px; }
.detail-block .val { font-weight: 600; font-size: var(--step-2); letter-spacing: -.02em; }
.detail-block .val a { display: inline-flex; align-items: center; min-height: 44px; transition: color .3s; }
.detail-block .val a:hover { color: var(--clay); }
.detail-block .sub { color: var(--ink-soft); font-size: var(--step--1); margin-top: 6px; }

.wa {
  display: inline-flex; align-items: center; gap: 10px; margin-top: 14px; min-height: 44px;
  background: #1f8f4e; color: #fff; padding: 12px 22px; border-radius: 2px;
  font-size: 14px; font-weight: 600; letter-spacing: .03em; transition: background .3s;
}
.wa:hover { background: #176e3c; }

/* 10px to match the picture cards on the home page. A 4px card next to 10px
   cards reads as an inconsistency rather than a deliberate difference. */
.form-card {
  background: var(--white); border: 1px solid var(--line); border-radius: 10px;
  padding: clamp(24px, 3vw, 44px); box-shadow: var(--shadow);
}
.form-card h2 { font-size: var(--step-2); margin-bottom: 8px; }
.form-card .hint { color: var(--ink-soft); font-size: var(--step--1); margin-bottom: var(--space-s); }
.field { margin-bottom: 20px; }
.field label { display: block; font-size: 13px; font-weight: 600; letter-spacing: .04em; margin-bottom: 8px; }
.field input, .field select, .field textarea {
  width: 100%; min-height: 48px; padding: 14px 16px;
  font-family: 'Montserrat', sans-serif; font-size: 16px; /* 16px stops iOS zooming on focus */
  border: 1px solid var(--line); border-radius: 2px; background: var(--paper); color: var(--ink);
  transition: border-color .3s, background .3s;
}
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--clay); background: var(--white); }
.field textarea { resize: vertical; min-height: 110px; }

/* The two send buttons used to be inline-block with an inline margin-left on the
   second, which misaligned them. Now a wrapping flex row, full width on phones. */
.form-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 8px; }
.form-actions .btn { flex: 1 1 200px; justify-content: center; min-height: 48px; }
.form-note { font-size: 12px; color: var(--ink-soft); margin-top: 16px; text-align: center; }

.hours { display: grid; grid-template-columns: 1fr auto; gap: 8px 20px; font-size: var(--step--1); }
.hours .d { color: var(--ink); }
.hours .t { color: var(--ink-soft); }

/* ============================================================
   MINIMUM HIT AREAS
   Everything interactive gets at least 44px of height. Collected here so the
   rule is auditable in one place rather than scattered per component.
   ============================================================ */
.btn { min-height: 44px; }
.nav-cta { min-height: 44px; }
.breadcrumb a,
.breadcrumb [aria-current='page'] { display: inline-flex; align-items: center; min-height: 44px; }
.page-faq-list summary { min-height: 44px; }
.choose-list li, .db-points li, .who-bullets li { max-width: none; }

/* Long unbroken strings (GSTIN, emails, URLs) must not force a track wider
   than its column â€” this is the other common source of page-level overflow. */
.footer-col a, .footer-col span, .cred .val, .detail-block .val { overflow-wrap: anywhere; }

/* ---------- Remaining hit-area fixes (measured, not assumed) ----------
   The responsive harness flagged three interactive elements still under 44px:
   the brand link, the mobile menu toggle at <=420px, and the service-card
   headings on the homepage. */

/* Brand lockup: the link was only as tall as the logo image (34-38px). */
.brand { min-height: 44px; }

/* The homepage service-card title links were ~29px tall. Rather than pad the
   anchor, stretch it over its whole card â€” the entire card becomes the target,
   which is what a visitor expects to be able to tap anyway. */
.svc-band .svc-card { position: relative; }
.svc-band .svc-card h3 a::after { content: ''; position: absolute; inset: 0; }
.svc-band .svc-card:focus-within { background: #fbfaf9; }

@media (max-width: 420px) {
  /* Was height:42px here, just under the minimum. */
  .menu-toggle { min-width: 88px; height: 44px; padding: 0 11px; }
}

/* ============================================================
   MOTION ON TOUCH DEVICES
   On a touchscreen there is no pointer to leave, so a :hover transform latches
   on after a tap and stays until you tap elsewhere â€” cards sit lifted, images
   sit zoomed. Gate the movement to devices that can actually hover; colour and
   focus feedback are untouched, so keyboard and pointer users lose nothing.
   ============================================================ */
@media (hover: none) {
  .svc-card-link:hover,
  .btn-dark:hover,
  .nav-cta:hover { transform: none; }
  .proj-card:hover img,
  .svc-card-link:hover .svc-card-media img { transform: none; }
  .btn:hover .arr,
  .nav-cta:hover span,
  .services-menu-all:hover span,
  .svc-card-link:hover .svc-card-arrow { transform: none; }

  /* Give the tap itself a fast, honest acknowledgement instead. */
  .svc-card-link:active { transform: scale(.995); transition-duration: .1s; }
  .btn:active { transform: translateY(1px); transition-duration: .1s; }
}

/* Pointer devices keep the full treatment, but the card lift is promoted so it
   composites cleanly rather than repainting the shadow each frame. */
@media (hover: hover) {
  .svc-card-link { will-change: transform; }
}

/* ============================================================
   SOCIAL LINKS  (header nav + footer)
   Inline SVG inheriting currentColor, so one component works on the light
   header and the dark footer without a second icon set.
   ============================================================ */

/* Label that is read aloud but not shown â€” an icon alone tells a screen reader
   nothing, and "link, link, link, link, link" is a useless nav. */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

.social-links { display: flex; align-items: center; list-style: none; margin: 0; padding: 0; }
.social-link {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 999px;
  color: inherit;
  transition: color .28s var(--ease), background-color .28s var(--ease),
              transform .28s var(--ease);
}
.social-link svg { display: block; }
.social-link::after { display: none !important; }   /* cancel the nav underline */
.social-link--awareness { opacity: .58; }
.social-link--awareness:hover, .social-link--awareness:focus-visible { opacity: 1; }

/* ---------- Header ---------- */
.nav-social { display: flex; align-items: center; }
.nav-social-title { display: none; }
.nav-social .social-links { gap: 0; }
/* Narrower than tall in the bar: 44px of height keeps the hit area legal while
   the row stays compact enough to sit beside the CTA on a 1024px laptop. */
.nav-social .social-link { width: 34px; height: 44px; color: var(--ink-soft); }
.nav-social .social-link svg { width: 18px; height: 18px; }
.nav-social .social-link:hover,
.nav-social .social-link:focus-visible {
  color: var(--clay); background: var(--paper-warm); transform: translateY(-2px);
}
/* A hairline divider so the icons read as a separate group from the nav links
   rather than as more navigation. */
.nav-social::before {
  content: ''; align-self: center;
  width: 1px; height: 22px; margin-inline: 14px 6px;
  background: var(--line);
}

@media (max-width: 880px) {
  .nav-social {
    display: block; width: 100%; margin-top: 28px; padding-top: 24px;
    border-top: 1px solid var(--line);
  }
  .nav-social::before { display: none; }
  .nav-social-title {
    display: block; margin-bottom: 10px;
    color: var(--clay); font-size: 11px; font-weight: 700;
    letter-spacing: .2em; text-transform: uppercase;
  }
  .nav-social .social-links { gap: 12px; }
  .nav-social .social-link {
    width: 48px; height: 48px;
    border: 1px solid var(--line); background: var(--white);
  }
  .nav-social .social-link svg { width: 20px; height: 20px; }
  .nav-social .social-link:hover,
  .nav-social .social-link:focus-visible { border-color: var(--clay); transform: none; }
}

/* ---------- Footer ---------- */
.footer-social {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--space-s) var(--space-m);
  padding-block: var(--space-m);
  border-bottom: 1px solid rgba(255,255,255,.12);
}
.footer-social-copy h3 {
  font-family: 'Montserrat', sans-serif; font-size: 12px; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase; color: #fff; margin-bottom: 6px;
}
.footer-social-copy p { color: #b5afa0; font-size: 15px; margin: 0; max-width: 44ch; }

.footer-social .social-links { gap: 10px; }
.footer-social .social-link {
  width: 46px; height: 46px;
  color: var(--paper-warm);
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.14);
}
/* Each button lights up in its own platform colour â€” instantly recognisable,
   and the only place on the site where non-brand colour is allowed. */
.footer-social .social-link:hover,
.footer-social .social-link:focus-visible {
  color: #fff;
  background: var(--brand);
  border-color: var(--brand);
  transform: translateY(-3px);
}
/* X's brand colour is near-black and would vanish on the navy footer. */
.footer-social .social-link[style*="#0f0f0f"]:hover,
.footer-social .social-link[style*="#0f0f0f"]:focus-visible {
  background: #fff; border-color: #fff; color: #0f0f0f;
}

@media (max-width: 640px) {
  .footer-social { flex-direction: column; align-items: flex-start; gap: 18px; padding-block: 28px; }
  .footer-social-copy p { font-size: 14px; line-height: 1.55; }
  .footer-social .social-links { width: 100%; flex-wrap: wrap; gap: 10px; }
.footer-social .social-link { width: 48px; height: 48px; }
}

/* The closing signature band (repeated logo, oversized wordmark and a drifting
   project photo) sat between the social row and the copyright line. Removed at
   the client's request â€” the footer now runs columns -> social -> copyright.
   Its markup came out of footer.php with it. */

@media (hover: none) {
  .social-link:hover { transform: none; }
}

/* ============================================================
   ENQUIRY FORM
   ============================================================ */
/* Honeypot. Off-screen rather than display:none, because some bots skip hidden
   fields. The input is collapsed too, so accessibility audits do not read it as
   an undersized control. */
.hp { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }
.hp input { width: 1px; height: 1px; min-height: 0; padding: 0; border: 0; }

.form-status {
  display: block; padding: 16px 18px; margin-bottom: 20px;
  border-radius: 3px; font-size: 15px; line-height: 1.5;
}
.form-status strong { display: block; font-weight: 700; margin-bottom: 2px; }
.form-status span { color: inherit; opacity: .85; }
.form-status--ok    { background: #e8f3ec; border-left: 3px solid #1f8f4e; color: #14432a; }
.form-status--error { background: #fbeaea; border-left: 3px solid #b3261e; color: #5c1512; }

.field .req { color: #b3261e; }
.field input[aria-invalid="true"],
.field textarea[aria-invalid="true"] { border-color: #b3261e; background: #fdf7f7; }
.field-error { margin-top: 6px; color: #b3261e; font-size: 13.5px; font-weight: 600; max-width: none; }

/* The WhatsApp option is an <a> styled as a button â€” keep it the same height. */
.form-actions .btn { text-decoration: none; }

/* ============================================================
   STICKY MOBILE CONTACT BAR
   On a phone the fastest route to an enquiry is a thumb on "Call". This keeps
   both routes permanently reachable without hunting for the footer. Hidden on
   the contact page itself, where the form is already on screen.
   ============================================================ */
.mobile-cta {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 120;
  display: none; grid-template-columns: 1fr 1fr;
  border-top: 1px solid rgba(255,255,255,.14);
  background: var(--ink);
  padding-bottom: env(safe-area-inset-bottom, 0);
}
.mobile-cta a {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 56px; padding: 10px 12px;
  color: var(--white); font-size: 14px; font-weight: 700; letter-spacing: .03em;
}
.mobile-cta a + a { border-left: 1px solid rgba(255,255,255,.14); }
.mobile-cta .is-wa { background: #1f8f4e; }
.mobile-cta svg { flex: 0 0 auto; }

@media (max-width: 880px) {
  body:not(.page-contact) .mobile-cta { display: grid; }
  /* Stop the bar covering the last of the footer. */
  body:not(.page-contact) .site-footer { padding-bottom: calc(var(--space-m) + 56px); }
}

/* ---------------------------------------------------------------
   Footer â€” Services split across two columns (5 + 4) in one row
   The block needs roughly double the width of the other footer
   columns. That width comes from its grid track being sized ~1.85fr
   (see .footer-grid), never from a span: a spanning item does not
   fit the four-column footer and pushed the last column off the row.
   The two sub-columns hold at every step, down to the single-column
   phone footer where the whole section is full width anyway.
   --------------------------------------------------------------- */
.footer-services {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 var(--space-s);
  align-items: start;
}

/* Narrowest point of the two-column tablet footer: sub-columns reach ~130px
   there and "Luxury & Premium Interiors Designers" takes three lines at 15px, standing
   proud of every other row. Same smaller type the phone footer already uses. */
@media (min-width: 641px) and (max-width: 700px) {
  .footer-services { column-gap: 12px; }
  .footer-services a { font-size: 13px; line-height: 1.3; overflow-wrap: anywhere; }
}/* ============================================================
   BALANCED CONTENT GRIDS
   Shared bordered grids appear throughout the service detail, About and
   supporting pages. Four fixed desktop tracks are easier to scan; these
   rules also fill incomplete final rows instead of leaving blank cells.
   ============================================================ *//* One remaining card fills the row; two share it; three use a 2 + 1 + 1
   rhythm. The DOM order remains exactly the same. *//* Bounded at the bottom as well as the top. These row-filling spans are
   !important and out-specify the plain `> *` reset below, so an unbounded
   max-width query left three-column spans applied inside the two-column
   layout â€” a four-item grid stretched its last card across both tracks, and a
   two-item grid stacked instead of sitting side by side. */

@media (max-width: 760px) {/* Clear the three- and four-column row-filling spans before the two-column
     rule below re-applies its own. Without this reset a four-item grid keeps
     the 3n + 1 span from the 1180px block and stretches its last card across
     both tracks, even though four items already fill two rows exactly. */
}/* The About-page client list uses the same bordered-grid treatment. *//* Restore the intrinsic track definitions after the legacy balanced-grid
   rules above. Those fixed 4/3/2-column rules and last-row spans caused cards
   to jump or stretch as the viewport crossed arbitrary breakpoints. */

/* ============================================================
   MOTION LAYER + PHASE 1 COMPONENTS
   Appended rather than woven in, so the whole layer can be read â€” or reverted â€”
   as one block. Two rules govern everything below:

   1. Only `transform` and `opacity` are animated. Both are composited, so no
      frame costs a layout or a paint. Animating width/height/top/box-shadow on
      anything large janks on the mid-range Android phones that are a large
      share of this audience.
   2. Motion is an enhancement. Every element below is fully readable and fully
      reachable with the animation removed â€” see the reduced-motion block at
      the foot of this file, which is the real behaviour for anyone who has
      asked their OS for less movement.
   ============================================================ */

/* ---------- Floating WhatsApp ----------
   Every page, every breakpoint. Sits above the phone-only call bar where that
   bar is showing, and drops to the normal offset where it is not. */
.wa-float {
  position: fixed; z-index: 130;
  right: 22px; bottom: 22px;
  display: inline-flex; align-items: center; gap: 0;
  height: 56px; min-width: 56px; padding: 0 14.5px;
  border-radius: 999px;
  background: #25D366; color: #fff;
  box-shadow: 0 6px 20px rgba(20,19,42,.28);
  /* Hidden until scrolled; main.js adds .is-in. Kept in the DOM and in the
     accessibility tree throughout â€” never display:none. */
  opacity: 0; transform: translateY(14px);
  transition: opacity .45s var(--ease), transform .45s var(--ease),
              background-color .3s var(--ease);
  pointer-events: none;
}
.wa-float.is-in { opacity: 1; transform: none; pointer-events: auto; }
.wa-float:hover { background: #1eb757; }
.wa-float svg { position: relative; z-index: 1; flex: 0 0 auto; }

/* The label is width-animated via max-width on a flex item, which does cost a
   layout â€” but only on one small element, only on hover, and only on pointer
   devices. The alternative (a transform) cannot reflow the pill around it. */
.wa-float-label {
  position: relative; z-index: 1;
  max-width: 0; overflow: hidden; white-space: nowrap;
  font-size: 13.5px; font-weight: 600; letter-spacing: .015em;
  transition: max-width .4s var(--ease), margin-left .4s var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .wa-float:hover .wa-float-label,
  .wa-float:focus-visible .wa-float-label { max-width: 130px; margin-left: 9px; }
}

/* Slow pulse, every 6s. Purely decorative, so it is the first thing the
   reduced-motion block switches off. */
.wa-float-ring {
  position: absolute; inset: 0; border-radius: inherit;
  background: #25D366; opacity: .55;
  animation: waPulse 6s var(--ease) infinite;
}
@keyframes waPulse {
  0%, 70% { transform: scale(1);    opacity: 0;  }
  74%     { transform: scale(1);    opacity: .5; }
  100%    { transform: scale(1.75); opacity: 0;  }
}

/* Clear the phone-only call bar, which is 56px plus the safe-area inset.
   That bar is suppressed on the contact page, so there the float drops back. */
@media (max-width: 880px) {
  body:not(.page-contact) .wa-float {
    bottom: calc(78px + env(safe-area-inset-bottom, 0px));
  }
  .wa-float { right: 16px; }
}

/* ---------- Header compaction ----------
   main.js adds .is-stuck past 80px. The header is already sticky; this only
   tightens it and firms up the hairline so it separates from the content. */
.site-header {
  transition: box-shadow .35s var(--ease), background-color .35s var(--ease);
}
.site-header .nav {
  transition: height .35s var(--ease);
}
.site-header.is-stuck {
  background: rgba(244,241,234,.94);
  box-shadow: 0 1px 0 var(--line), 0 6px 24px rgba(20,19,42,.06);
}
.site-header.is-stuck .nav { height: 62px; }
.site-header .brand img { transition: height .35s var(--ease); }
.site-header.is-stuck .brand img { height: 38px; }

/* ---------- Page fade ----------
   Kills the white flash between page loads. Scoped to html.js so a scripting
   failure can never leave the body at opacity 0. */
.js body { animation: pageIn .4s var(--ease) both; }
@keyframes pageIn { from { opacity: 0; } to { opacity: 1; } }

/* ---------- Count-up statistics ----------
   The value is rendered server-side and animated from 0 by main.js. If JS never
   runs, the final number is already in the markup and simply sits there. */
.stat .num[data-count] { font-variant-numeric: tabular-nums; }

/* ---------- Magnetic buttons ----------
   main.js writes --mx/--my as the pointer moves near the button. Declared here
   so the transform exists even before any pointer movement. */
@media (hover: hover) and (pointer: fine) {
  .btn.is-magnetic {
    transform: translate3d(var(--mx, 0px), var(--my, 0px), 0);
    transition: transform .35s var(--ease), background-color .3s var(--ease),
                color .3s var(--ease), border-color .3s var(--ease);
  }
}/* ============================================================
   SERVICE-PAGE DISCLOSURE CARDS
   The heading is the card; its explanation opens underneath.
   Collapsed, never deleted â€” see the note in service-page-template.php.
   ============================================================ *//* A plus that becomes a minus. Two spans would need markup; two pseudo-elements
   on one span do it with none. *//* The lead paragraph of a section, before anything is opened. */

/* Chips on a service page carry short labels rather than place names, so they
   sit a little tighter and wrap more densely. */
.chips--tight { margin-top: 22px; gap: 8px; }
.chips--tight li { padding: 8px 14px; min-height: 36px; font-size: 12.5px; }
.dark-band .chips--tight li { border-color: rgba(255,255,255,.22); color: rgba(255,255,255,.85); }
@media (hover: hover) {
  .dark-band .chips--tight li:hover { background: var(--gold); border-color: var(--gold); color: var(--clay); }
}/* Longer bare labels: a compact two-column list rather than pills. Columns, not
   a grid, so the list flows down one column and up the next and any number of
   items balances itself. */

/* Project blurbs run to ninety words. Three lines is the hook; the full text
   stays in the DOM and is read out in full by a screen reader â€” line-clamp is a
   visual truncation, not a content one. */
.project-card p {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden;
}/* On the navy bands the same component, inverted. *//* These grids held cards with their bodies always open, so they were multi-
   column. As single-line rows they read better as one stacked list. *//* ---------- "Read more" on the service intro ---------- */

/* ============================================================
   MASKED HEADING REVEAL
   The heading's text sits inside a wrapper that main.js inserts, and rises out
   from behind the heading's own edge rather than simply fading in. It is the
   one piece of motion on the site that people read as craft.

   Two things keep it safe:
   - The wrapper is added by JS. If scripting fails there is no wrapper, no
     clip and no transform, and the heading is simply text.
   - `clip-path` rather than `overflow: hidden`, because overflow on a heading
     crops descenders and any focus ring inside it.
   ============================================================ */
.js .mask-head { display: block; clip-path: inset(-0.25em -0.2em -0.15em -0.2em); }
.js .mask-head > .mask-inner {
  display: block;
  transform: translateY(105%);
  transition: transform .78s cubic-bezier(.22, 1, .28, 1);
}
.js .mask-head.is-revealed > .mask-inner { transform: none; }

/* ---------- Hero entrance ----------
   The hero's own pieces arrive in sequence on load rather than all at once:
   tag, headline, line, button. Each is a transform and an opacity, both
   composited, and the whole sequence is done inside 900ms. */
.js .hero-content > * { --in-delay: 0ms; }
.js .hero-in .hero-tag,
.js .hero-in .hero-lead,
.js .hero-in .hero-actions,
.js .hero-in .hero-stats,
.js .hero-in .hero-feature {
  opacity: 0; transform: translateY(18px);
  animation: heroPieceIn .8s var(--ease) forwards;
  animation-delay: var(--in-delay);
}
@keyframes heroPieceIn { to { opacity: 1; transform: none; } }
.js .hero-in .hero-tag     { --in-delay: 120ms; }
.js .hero-in .hero-lead    { --in-delay: 380ms; }
.js .hero-in .hero-actions { --in-delay: 480ms; }
.js .hero-in .hero-feature { --in-delay: 600ms; }
.js .hero-in .hero-stats   { --in-delay: 700ms; }

/* ---------- Scroll cue ---------- */
.hero-cue {
  position: absolute; left: 50%; bottom: 22px; z-index: 2;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  transform: translateX(-50%);
  color: rgba(255,255,255,.7);
  font-size: 9.5px; font-weight: 600; letter-spacing: .22em; text-transform: uppercase;
  pointer-events: none;
}
.hero-cue-rail {
  width: 1px; height: 42px; background: rgba(255,255,255,.28);
  position: relative; overflow: hidden;
}
.hero-cue-rail::after {
  content: ''; position: absolute; inset: 0;
  background: var(--gold);
  animation: cueRun 2.4s var(--ease) infinite;
}
@keyframes cueRun {
  0%   { transform: translateY(-100%); }
  60%  { transform: translateY(100%); }
  100% { transform: translateY(100%); }
}
@media (max-width: 880px) { .hero-cue { display: none; } }

/* ---------- Slide counter ---------- */
.hero-count {
  display: flex; align-items: baseline; gap: 5px; margin-right: 18px;
  color: rgba(255,255,255,.72);
  font-size: 11px; font-weight: 600; letter-spacing: .16em; font-variant-numeric: tabular-nums;
}
.hero-count .cur { color: var(--white); font-size: 15px; }

/* ---------- Parallax ----------
   Removed from the feature plate along with its bleed. Parallax needs an image
   larger than its frame to drift inside; on a contained, sharply-capped image
   the 1.12 scale it depended on would have reintroduced exactly the upscaling
   the plate exists to avoid. Kept as a hook for any future full-bleed art
   built from higher-resolution photography. */

@media (prefers-reduced-motion: reduce) {
  .js .mask-head { clip-path: none; }
  .js .mask-head > .mask-inner { transform: none; transition: none; }
  .js .hero-in .hero-tag, .js .hero-in .hero-lead, .js .hero-in .hero-actions,
  .js .hero-in .hero-stats, .js .hero-in .hero-feature {
    opacity: 1; transform: none; animation: none;
  }
  .hero-cue-rail::after { animation: none; }
}

/* ============================================================
   CURSOR ACCENT
   A navy dot that trails the pointer and swells to read "View" over image
   grids. Pointer devices only, aria-hidden, pointer-events:none â€” it is
   decoration painted over the page and must never intercept a click or be
   announced. The real cursor is left visible: hiding it is what makes these
   feel broken when the script hiccups.
   ============================================================ */
.cursor-dot {
  position: fixed; top: 0; left: 0; z-index: 190;
  width: 76px; height: 76px; margin: -38px 0 0 -38px;
  border-radius: 50%; background: var(--clay); color: var(--white);
  display: grid; place-items: center;
  font-size: 10px; font-weight: 600; letter-spacing: .18em; text-transform: uppercase;
  pointer-events: none;
  opacity: 0; transform: translate3d(var(--x, 0), var(--y, 0), 0) scale(.2);
  transition: opacity .3s var(--ease), transform .18s var(--ease);
  will-change: transform;
}
.cursor-dot.is-on { opacity: 1; transform: translate3d(var(--x, 0), var(--y, 0), 0) scale(1); }
@media (hover: none), (pointer: coarse) { .cursor-dot { display: none; } }

/* ============================================================
   PAGE TRANSITION
   A navy panel wipes across on navigation, so moving between pages reads as one
   continuous surface rather than a white flash and a reload.

   Scoped to html.js and driven by a class, so the panel can never be left
   covering the page if scripting fails â€” and every exit has a hard timeout in
   main.js so a slow response cannot strand a visitor behind it.
   ============================================================ */
.page-wipe {
  position: fixed; inset: 0; z-index: 210;
  background: var(--clay);
  transform: scaleY(0); transform-origin: bottom center;
  pointer-events: none;
  transition: transform .24s cubic-bezier(.7, 0, .3, 1);
}
.page-wipe.is-out { transform: scaleY(1); transform-origin: bottom center; }

@media (prefers-reduced-motion: reduce) {
  .cursor-dot { display: none; }
  .page-wipe { display: none; }
}/* ============================================================
   LIGHTBOX
   Gallery photographs open full-screen. Built as a dialog with a focus trap,
   Escape to close, arrow keys to move, and focus returned to the thumbnail that
   opened it â€” the things that separate a lightbox from a trap.
   ============================================================ *//* Touch has no hover, and a permanent scrim over every photograph would defeat
   the point of a gallery â€” so the cue simply does not appear there. The button
   still opens the lightbox on tap. */

.lb {
  position: fixed; inset: 0; z-index: 200;
  display: grid; grid-template-rows: 1fr auto;
  background: rgba(0,0,59,.96);
  opacity: 0; pointer-events: none;
  transition: opacity .3s var(--ease);
}
.lb.is-open { opacity: 1; pointer-events: auto; }
.lb-stage { position: relative; display: grid; place-items: center; padding: clamp(16px, 4vw, 56px); min-height: 0; }
.lb-stage img {
  max-width: 100%; max-height: 100%; width: auto; height: auto;
  object-fit: contain; border-radius: 3px;
  transform: scale(.97); opacity: 0;
  transition: transform .4s var(--ease), opacity .3s var(--ease);
}
.lb.is-open .lb-stage img { transform: none; opacity: 1; }
.lb-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 16px clamp(16px, 4vw, 40px) calc(16px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid rgba(255,255,255,.14);
}
.lb-cap { color: rgba(255,255,255,.8); font-size: 13.5px; line-height: 1.5; max-width: 60ch; }
.lb-count { color: var(--gold); font-size: 11px; font-weight: 600; letter-spacing: .18em; font-variant-numeric: tabular-nums; }
.lb-actions { display: flex; gap: 10px; flex: 0 0 auto; }
.lb-btn {
  width: 48px; height: 48px; display: grid; place-items: center;
  border: 1px solid rgba(255,255,255,.28); border-radius: 50%;
  background: none; color: var(--white); cursor: pointer;
  transition: background-color .25s var(--ease), border-color .25s var(--ease), opacity .25s var(--ease);
}
.lb-btn:hover:not(:disabled) { background: var(--gold); border-color: var(--gold); color: var(--clay); }
.lb-btn:disabled { opacity: .3; cursor: default; }
.lb-btn:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }
.lb-btn svg { width: 16px; height: 16px; }
.lb-close { position: absolute; top: clamp(12px, 2vw, 22px); right: clamp(12px, 2vw, 22px); z-index: 2; }
body.lb-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .lb, .lb-stage img { transition: none; }
  .lb-stage img { transform: none; }
}

/* ============================================================
   STICKY STORY
   A pinned image beside text "beats". As each beat reaches the middle of the
   viewport it comes to full opacity and the pinned image crossfades to match.
   One scroll gesture drives a three-image sequence â€” which is what lets three
   short lines carry what used to be four paragraphs.

   Below 880px it collapses to an ordinary stacked layout with every beat at
   full opacity and each image inline above its own text. Sticky positioning on
   a phone-height viewport pins an image that then has nowhere to travel.
   ============================================================ */
.sticky-story .ss-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(32px, 6vw, 90px);
  align-items: start;
}
.ss-media {
  position: sticky; top: 96px;
  aspect-ratio: 4 / 5; border-radius: 6px; overflow: hidden;
  background: var(--ink);
}
.ss-media img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0;
  transition: opacity .7s var(--ease), transform 1.1s var(--ease);
  transform: scale(1.04);
}
.ss-media img.is-active { opacity: 1; transform: scale(1); }

.ss-beat {
  display: flex; flex-direction: column; justify-content: center;
  min-height: 70svh;
  opacity: .28;
  transition: opacity .5s var(--ease);
}
.ss-beat.is-active { opacity: 1; }
.ss-beat .n {
  font-size: 11px; font-weight: 600; letter-spacing: .2em; color: var(--clay);
  margin-bottom: 14px;
}
/* Weight 400, not 700. This is a display element and now renders in Fraunces,
   whose wght axis is pinned at 400 â€” asking for 700 got a synthesised faux bold
   here, the one smeared heading on the page. Presence comes from the size and
   the tracking. Do not raise this while the display face is a static 400. */
.ss-beat h3 {
  font-size: clamp(24px, 3vw, 40px); font-weight: 400;
  letter-spacing: -.022em; line-height: 1.12; text-wrap: balance;
}
.ss-beat p {
  margin-top: 14px; max-width: 40ch;
  color: var(--ink-soft); font-size: clamp(15px, 1.4vw, 16.5px); line-height: 1.7;
}

@media (max-width: 880px) {
  .sticky-story .ss-grid { grid-template-columns: 1fr; gap: var(--space-m); }
  /* The media column is emptied by main.js at this breakpoint and each image is
     moved inline above its beat, so the section reads top to bottom. */
  .ss-media { display: none; }
  .ss-beat { min-height: 0; opacity: 1; margin-bottom: var(--space-m); }
  .ss-beat-img {
    display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
    border-radius: 6px; margin-bottom: 20px;
  }
}
@media (min-width: 881px) { .ss-beat-img { display: none; } }

@media (prefers-reduced-motion: reduce) {
  .ss-media img { transition: none; transform: none; }
  .ss-beat { opacity: 1; transition: none; }
}

/* ============================================================
   EDITORIAL LAYOUT COMPONENTS
   Uniform card grids read as a directory. These four exist so that a page of
   photographs reads as a composition instead: an irregular mosaic, a rail that
   scrolls sideways, a ribbon that drifts, and a full-bleed break.
   ============================================================ */

/* ---------- Feature plate ----------
   This was a full-bleed band. At 1440 it displayed a 1400px photograph across
   1596 CSS px â€” asking for 3,192 device pixels on a 2x screen from a file that
   has 1400. It was the softest image on the site, in the position meant to be
   the most striking.

   It is now a contained plate: the image is capped at 700px, which is exactly
   what a 1400px source serves at 2x, and the space that used to be filled by
   stretched pixels is filled by margin instead. Generous whitespace beside a
   genuinely sharp photograph reads as considered; a soft photograph stretched
   edge to edge reads as cheap. Restore the bleed only if the photography is
   rebuilt at 3000px+. */
.feature-shot {
  display: grid;
  /* The caption gets a floor of 300px. Without one the image track claimed its
     full 700px max at every width above the stacking breakpoint and squeezed the
     caption to ~158px at 960 â€” three or four words a line. The image shrinking
     below 700 costs nothing; it only ever gets sharper. */
  grid-template-columns: minmax(0, 700px) minmax(300px, 1fr);
  gap: clamp(28px, 5vw, 72px);
  align-items: center;
  padding-block: var(--space-l);
}
.feature-shot > img {
  width: 100%; max-width: 700px;
  aspect-ratio: 3 / 2; object-fit: cover;
  border-radius: 4px;
}
.feature-shot-cap { color: var(--ink); }
.feature-shot-cap .eyebrow { color: var(--clay); }
.feature-shot-cap .eyebrow::before { background: var(--clay); }
.feature-shot-cap h2 {
  max-width: 16ch; color: var(--ink);
  font-size: var(--step-3); line-height: 1.08;
}
.feature-shot-cap p {
  max-width: 40ch; margin-top: 16px;
  color: var(--ink-soft); font-size: var(--step-0);
}
@media (max-width: 900px) {
  .feature-shot { grid-template-columns: 1fr; gap: var(--space-s); }
  .feature-shot-cap { padding-inline: 0; }
}

/* ---------- Mosaic ----------
   Six columns with a rhythm that repeats every six children.

   VARIETY COMES FROM ASPECT RATIO, NOT FROM WIDTH â€” and that is a hard
   constraint, not a preference. Every source photograph on this site is 1400px
   on its long edge. A tile displayed at 600 CSS px asks for 1200 device pixels
   on a 2x screen and is therefore genuinely sharp; the full-width panoramic
   tile that used to sit at 6n+6 was displayed at ~1200 CSS px, asked for 2400,
   and was being upscaled 1.7x. It read as soft in exactly the position meant to
   be the most impressive on the page.

   So no tile now spans more than 3 of 6 columns (~600px inside the 1240
   container), and the composition is built from portrait, square and landscape
   crops instead. Raise these spans only if the photography is rebuilt at a
   higher resolution. */
.mosaic { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 14px; margin-top: var(--space-m); }
.mosaic > * { grid-column: span 2; }
.mosaic > :nth-child(6n + 1) { grid-column: span 3; aspect-ratio: 4 / 5; }
.mosaic > :nth-child(6n + 2) { grid-column: span 3; aspect-ratio: 16 / 11; }
.mosaic > :nth-child(6n + 3) { aspect-ratio: 1 / 1; }
.mosaic > :nth-child(6n + 4) { aspect-ratio: 4 / 3; }
.mosaic > :nth-child(6n + 5) { aspect-ratio: 3 / 4; }
.mosaic > :nth-child(6n + 6) { grid-column: span 3; aspect-ratio: 16 / 10; }
@media (max-width: 900px) {
  .mosaic { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .mosaic > * { grid-column: span 2; aspect-ratio: 4 / 3; }
  .mosaic > :nth-child(6n + 1), .mosaic > :nth-child(6n + 2) { grid-column: span 2; aspect-ratio: 4 / 3; }
  .mosaic > :nth-child(6n + 6) { grid-column: span 4; aspect-ratio: 16 / 9; }
}
@media (max-width: 560px) {
  .mosaic { grid-template-columns: 1fr; gap: 10px; }
  .mosaic > *, .mosaic > :nth-child(6n + 1), .mosaic > :nth-child(6n + 2), .mosaic > :nth-child(6n + 6) {
    grid-column: 1 / -1; aspect-ratio: 4 / 3;
  }
}
/* The `.mosaic > :nth-child(...)` rules above are (0,2,0) and already out-specify
   the card's own (0,1,0) `aspect-ratio: 3/4`, so no override is needed here.
   An earlier `aspect-ratio: auto; height: 100%` on this selector collapsed every
   tile to 2px: `auto` removed the ratio the grid was sizing rows from, and
   `height: 100%` then resolved against an auto row that had nothing left to
   measure. Do not reintroduce it. */

/* ---------- Homepage work composition ----------
   The home page intentionally hides two Mantri Pinnacle cards. The old repeating
   mosaic still counted those hidden positions, leaving the visible work looking
   accidental. This feature-led arrangement is defined by the cards that remain:
   one large lead image, two supporting frames and one panoramic closing frame. */
.home-work {
  overflow: hidden;
  padding-bottom: clamp(38px, 4.5vw, 62px);
}
.home-work .mosaic + div { margin-top: clamp(24px, 2.5vw, 34px) !important; }
.home-work .section-title {
  margin-bottom: clamp(28px, 3vw, 42px);
  font-family: 'Montserrat', sans-serif;
  font-size:clamp(28px, 3.1vw, 42px);
  font-weight: 400;
  letter-spacing: -.04em;
  line-height: 1.05;
}

/* ---------- Service discovery ----------
   An asymmetric four-card atlas lets visitors understand the studio's core
   sectors in one glance. Every card remains a normal link; hover/focus only
   enriches it with a gentle depth cue and never hides the service itself. */
.service-showcase { background:var(--paper-warm); border-block:1px solid var(--line); }
.service-showcase-head { display:flex; align-items:end; justify-content:space-between; gap:24px; margin-bottom:clamp(26px, 3vw, 40px); }
.service-showcase-kicker { margin:0 0 10px; color:var(--clay); font-size:10px; font-weight:600; letter-spacing:.18em; text-transform:uppercase; }
.service-showcase-head h2 { max-width:21ch; font-size:clamp(25px, 2.6vw, 36px); font-weight:400; letter-spacing:-.035em; line-height:1.12; }
.service-showcase-link { display:inline-flex; align-items:center; gap:10px; flex:none; min-height:44px; color:var(--ink); font-size:12px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; border-bottom:1px solid var(--ink); }
.service-showcase-link span { font-size:16px; transition:transform .3s var(--ease); }
.service-showcase-link:hover span, .service-showcase-link:focus-visible span { transform:translateX(4px); }
.service-showcase-grid { display:grid; grid-template-columns:repeat(12, minmax(0, 1fr)); grid-auto-rows:clamp(108px, 10vw, 148px); gap:clamp(10px, 1.3vw, 18px); }
.service-showcase-card { position:relative; display:block; overflow:hidden; min-width:0; border-radius:9px; background:var(--noir); isolation:isolate; }
.service-showcase-card--residential { grid-column:span 5; grid-row:span 2; }
.service-showcase-card--villa { grid-column:span 4; grid-row:span 1; }
.service-showcase-card--healthcare { grid-column:span 3; grid-row:span 1; }
.service-showcase-card--commercial { grid-column:span 7; grid-row:span 1; }
.service-showcase-card--government { grid-column:span 4; grid-row:span 1; }
.service-showcase-card--luxury { grid-column:span 3; grid-row:span 1; }
.service-showcase-card--residential-build { grid-column:span 5; grid-row:span 1; }
.service-showcase-card--commercial-build { grid-column:span 7; grid-row:span 1; }
.service-showcase-card--office { grid-column:span 5; grid-row:span 1; }
.service-showcase-card img { position:absolute; inset:0; z-index:-2; width:100%; height:100%; object-fit:cover; transition:transform .9s var(--ease-soft), filter .6s var(--ease); }
.service-showcase-shade { position:absolute; inset:0; z-index:-1; background:linear-gradient(180deg,rgba(5,5,31,.04) 18%,rgba(5,5,31,.76) 100%); transition:background .45s var(--ease); }
.service-showcase-copy { position:absolute; inset:auto clamp(16px, 2vw, 26px) clamp(16px, 2vw, 24px); display:grid; gap:7px; color:var(--white); }
.service-showcase-copy small { color:var(--gold-lit); font-size:9px; font-weight:600; letter-spacing:.18em; text-transform:uppercase; }
.service-showcase-copy strong { font-size:clamp(17px, 1.6vw, 23px); font-weight:500; letter-spacing:-.025em; line-height:1.15; }
.service-showcase-copy em { max-height:0; overflow:hidden; color:rgba(255,255,255,.84); font-size:12px; font-style:normal; line-height:1.45; opacity:0; transform:translateY(8px); transition:max-height .45s var(--ease), opacity .35s ease, transform .45s var(--ease); }
.service-showcase-copy i { position:absolute; right:0; bottom:0; display:grid; place-items:center; width:30px; height:30px; border:1px solid rgba(255,255,255,.45); border-radius:50%; font-size:15px; font-style:normal; transition:transform .4s var(--ease), background .4s var(--ease); }
@media (hover:hover) { .service-showcase-card:hover img, .service-showcase-card:focus-visible img { transform:scale(1.07); filter:brightness(.9); } .service-showcase-card:hover .service-showcase-shade, .service-showcase-card:focus-visible .service-showcase-shade { background:linear-gradient(180deg,rgba(5,5,31,.12) 8%,rgba(5,5,31,.9) 100%); } .service-showcase-card:hover em, .service-showcase-card:focus-visible em { max-height:40px; opacity:1; transform:none; } .service-showcase-card:hover i, .service-showcase-card:focus-visible i { transform:rotate(-45deg); background:var(--gold); color:var(--noir); border-color:var(--gold); } }
@media (max-width:900px) { .service-showcase-grid { grid-template-columns:repeat(2, minmax(0, 1fr)); grid-auto-rows:clamp(180px, 28vw, 260px); } .service-showcase-card--residential, .service-showcase-card--villa, .service-showcase-card--healthcare, .service-showcase-card--commercial, .service-showcase-card--government, .service-showcase-card--luxury, .service-showcase-card--residential-build, .service-showcase-card--commercial-build, .service-showcase-card--office { grid-column:span 1; grid-row:span 1; } .service-showcase-card--residential { grid-column:1 / -1; } }
@media (max-width:560px) { .service-showcase-head { align-items:start; flex-direction:column; gap:14px; margin-bottom:24px; } .service-showcase-head h2 { font-size:clamp(23px, 6.4vw, 28px); } .service-showcase-link { min-height:38px; font-size:11px; } .service-showcase-grid { grid-template-columns:1fr; grid-auto-rows:auto; gap:10px; } .service-showcase-card--residential, .service-showcase-card--villa, .service-showcase-card--healthcare, .service-showcase-card--commercial, .service-showcase-card--government, .service-showcase-card--luxury, .service-showcase-card--residential-build, .service-showcase-card--commercial-build, .service-showcase-card--office { grid-column:1 / -1; min-height:210px; } .service-showcase-card--residential { min-height:270px; } .service-showcase-copy em { max-height:40px; opacity:1; transform:none; } .service-showcase-copy i { background:rgba(5,5,31,.3); } .home-work .section-title { font-size:clamp(24px, 6.6vw, 30px); line-height:1.14; } }
.page-home .home-work .mosaic {
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-auto-rows: clamp(42px, 3.8vw, 56px);
  gap: clamp(10px, 1.3vw, 18px);
  margin-top: 0;
}
.page-home .home-work .mosaic > .proj-card {
  grid-column: span 3;
  grid-row: span 3;
  min-height: 0;
  aspect-ratio: auto;
  border-radius: 12px;
}
.page-home .home-work .mosaic > :nth-child(6n + 2) {
  grid-column: 1 / span 7;
  grid-row: span 7;
}
.page-home .home-work .mosaic > :nth-child(6n + 3) {
  grid-column: 8 / span 5;
  grid-row: span 4;
}
.page-home .home-work .mosaic > :nth-child(6n + 4) {
  grid-column: 8 / span 5;
  grid-row: span 3;
}
.page-home .home-work .mosaic > :nth-child(6n + 6) {
  grid-column: 1 / -1;
  grid-row: span 4;
}

@media (max-width: 900px) {
  .page-home .home-work .mosaic {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-rows: clamp(86px, 17vw, 136px);
  }
  .page-home .home-work .mosaic > :nth-child(6n + 2) {
    grid-column: 1 / -1;
    grid-row: span 3;
  }
  .page-home .home-work .mosaic > :nth-child(6n + 3),
  .page-home .home-work .mosaic > :nth-child(6n + 4) {
    grid-column: span 1;
    grid-row: span 2;
  }
  .page-home .home-work .mosaic > :nth-child(6n + 6) {
    grid-column: 1 / -1;
    grid-row: span 2;
  }
}

@media (max-width: 560px) {
  .home-work .section-title { font-size:clamp(24px, 6.6vw, 30px); line-height:1.14; }
  .page-home .home-work .mosaic {
    grid-template-columns: 1fr;
    grid-auto-rows: auto;
  }
  .page-home .home-work .mosaic > .proj-card,
  .page-home .home-work .mosaic > :nth-child(6n + 2),
  .page-home .home-work .mosaic > :nth-child(6n + 3),
  .page-home .home-work .mosaic > :nth-child(6n + 4),
  .page-home .home-work .mosaic > :nth-child(6n + 6) {
    grid-column: 1 / -1;
    grid-row: auto;
    aspect-ratio: 4 / 3;
  }
}

/* ---------- Gallery-to-feature transition ----------
   The panel immediately after the gallery is a destination, not a second
   generic section. A single framed image and a warm editorial caption give the
   page a clear visual pause without the old double section-padding gap. */
.feature-project-section {
  padding-block: clamp(28px, 4vw, 54px) clamp(40px, 5vw, 70px);
  background: linear-gradient(135deg, rgba(217,195,154,.18), transparent 48%);
}
.feature-project-section .feature-shot {
  grid-template-columns: minmax(0, 1.28fr) minmax(300px, .72fr);
  gap: 0;
  min-height: clamp(370px, 37vw, 520px);
  padding: clamp(8px, 1vw, 14px);
  border: 1px solid rgba(20,19,42,.12);
  border-radius: 14px;
  background: var(--white);
  box-shadow: 0 24px 55px rgba(20,19,42,.10);
}
.feature-project-section .feature-shot > img {
  max-width: none;
  height: 100%;
  min-height: 0;
  aspect-ratio: auto;
  border-radius: 8px;
}
.feature-project-section .feature-shot-cap {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-self: stretch;
  padding: clamp(30px, 4vw, 68px);
  background: linear-gradient(145deg, #17162f, #090824);
  color: var(--paper);
  overflow: hidden;
}
.feature-project-section .feature-shot-cap::before {
  content: 'Featured project';
  position: absolute;
  top: 22px;
  right: 24px;
  color: rgba(217,195,154,.72);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.feature-project-section .feature-shot-cap::after {
  content: '';
  position: absolute;
  right: -42px;
  bottom: -42px;
  width: 170px;
  height: 170px;
  border: 1px solid rgba(217,195,154,.36);
  border-radius: 50%;
}
.feature-project-section .feature-shot-cap .eyebrow { color: var(--gold); }
.feature-project-section .feature-shot-cap .eyebrow::before { background: var(--gold); }
.feature-project-section .feature-shot-cap h2 {
  position: relative;
  z-index: 1;
  max-width: 11ch;
  color: var(--white);
  font-family: 'Montserrat', sans-serif;
  font-size: clamp(29px, 3.2vw, 48px);
  font-weight: 400;
  letter-spacing: -.04em;
  line-height: 1.06;
}
.feature-project-section .feature-shot-cap p {
  position: relative;
  z-index: 1;
  margin-top: 18px;
  color: rgba(255,255,255,.74);
  font-size: 15px;
}
.feature-project-section + .studio-section { padding-top: clamp(52px, 6vw, 76px); }
@media (max-width: 900px) {
  .feature-project-section .feature-shot { grid-template-columns: 1fr; min-height: 0; }
  .feature-project-section .feature-shot > img { height: auto; aspect-ratio: 16 / 10; }
  .feature-project-section .feature-shot-cap { min-height: 300px; }
}
@media (max-width: 560px) {
  .feature-project-section { padding-block: 24px 42px; }
  .feature-project-section .feature-shot { padding: 6px; border-radius: 10px; }
  .feature-project-section .feature-shot-cap { min-height: 270px; padding: 34px 26px; }
  .feature-project-section .feature-shot-cap::before { top: 18px; right: 20px; }
}

/* ---------- Rail ----------
   Native overflow + scroll-snap. No scroll hijacking: trackpad, touch, the
   scrollbar itself and the arrow keys all behave exactly as the visitor
   expects, and the arrow buttons are an addition rather than the only way in.

   The padding is what makes it look designed: the rail bleeds to the viewport
   edge while its first tile lines up with the page's content column. */
.rail-wrap { position: relative; margin-top: var(--space-m); }
.rail {
  display: flex; gap: 14px;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  padding-inline: max(var(--space-s), calc((100% - var(--maxw)) / 2 + var(--space-s)));
  /* Must match the padding above. scroll-snap-align:start snaps to the item's
     own start edge and ignores the container's padding otherwise â€” which parks
     the rail a few pixels in on load, knocks the first tile out of line with
     the content column, and leaves the "scroll left" button live at the start
     of the track. */
  scroll-padding-inline: max(var(--space-s), calc((100% - var(--maxw)) / 2 + var(--space-s)));
  margin-inline: calc(50% - 50vw + var(--sbw) / 2);
  width: calc(100vw - var(--sbw)); max-width: calc(100vw - var(--sbw));
  padding-bottom: 6px;
  scrollbar-width: thin;
}
.rail > * {
  flex: 0 0 clamp(230px, 25vw, 320px);
  scroll-snap-align: start;
}
.rail-nav { display: flex; gap: 10px; justify-content: flex-end; margin-top: 18px; }
.rail-btn {
  width: 46px; height: 46px; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 50%; background: transparent;
  color: var(--ink); cursor: pointer;
  transition: background-color .25s var(--ease), border-color .25s var(--ease),
              color .25s var(--ease), opacity .25s var(--ease);
}
.rail-btn:hover:not(:disabled) { background: var(--clay); border-color: var(--clay); color: var(--white); }
.rail-btn:disabled { opacity: .3; cursor: default; }
.rail-btn svg { width: 15px; height: 15px; }

/* ---------- Marquee ----------
   The track is duplicated and translated by exactly half its width, so the loop
   is seamless. The copy is aria-hidden â€” a screen reader should hear the client
   list once, not twice. */
.marquee {
  position: relative; overflow: hidden;
  margin-inline: calc(50% - 50vw + var(--sbw) / 2);
  width: calc(100vw - var(--sbw)); max-width: calc(100vw - var(--sbw));
  padding-block: var(--space-m);
  background: var(--clay); color: var(--white);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee-track {
  display: flex; width: max-content;
  animation: marqueeDrift 42s linear infinite;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee-item {
  display: flex; align-items: baseline; gap: 14px;
  padding-inline: clamp(24px, 3vw, 46px);
  white-space: nowrap;
}
.marquee-item .nm { font-size: clamp(19px, 2vw, 27px); font-weight: 600; letter-spacing: -.02em; }
.marquee-item .ty { font-size: 10.5px; font-weight: 600; letter-spacing: .2em; text-transform: uppercase; color: var(--gold); }
@keyframes marqueeDrift { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* ---------- Timeline ----------
   The connecting rule draws itself as the section scrolls, and each dot lights
   as the rule reaches it. Progress is computed in main.js from the section's
   position, and written here as --draw. */
.timeline { position: relative; margin-top: var(--space-l); }
.timeline-track {
  position: absolute; left: 0; right: 0; top: 13px; height: 2px;
  background: var(--line);
}
.timeline-track::after {
  content: ''; position: absolute; inset: 0;
  background: var(--clay);
  transform: scaleX(var(--draw, 0)); transform-origin: left center;
}
/* An <ol> for the semantics â€” these steps genuinely are ordered â€” but the
   browser's own "1. 2. 3." markers sat alongside the numbered dots, so the page
   showed each step's number twice. */
.timeline-steps {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-m);
  list-style: none; padding: 0; margin: 0;
}
.timeline-step { position: relative; padding-top: 44px; }
.timeline-step::before {
  content: ''; position: absolute; left: 0; top: 6px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--paper); border: 2px solid var(--line);
  transition: background-color .4s var(--ease), border-color .4s var(--ease), transform .4s var(--ease);
}
.timeline-step.is-lit::before { background: var(--clay); border-color: var(--clay); transform: scale(1.15); }
.timeline-step .n {
  font-size: 11px; font-weight: 600; letter-spacing: .2em; color: var(--ink-soft);
  transition: color .4s var(--ease);
}
.timeline-step.is-lit .n { color: var(--clay); }
.timeline-step h3 { margin-top: 8px; font-size: clamp(17px, 1.5vw, 21px); font-weight: 600; letter-spacing: -.015em; }
@media (max-width: 900px) {
  /* Vertical below 900px: four columns of two words each is unreadable. */
  .timeline-track { left: 7px; right: auto; top: 0; bottom: 0; width: 2px; height: auto; }
  .timeline-track::after { transform: scaleY(var(--draw, 0)); transform-origin: center top; }
  .timeline-steps { grid-template-columns: 1fr; gap: var(--space-s); }
  .timeline-step { padding: 0 0 var(--space-s) 38px; }
  .timeline-step::before { top: 2px; }
}

@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation: none; }
  /* Without the drift the ribbon must still be reachable, so it becomes a
     normal horizontally-scrollable list. */
  .marquee { overflow-x: auto; -webkit-mask-image: none; mask-image: none; }
  .timeline-track::after { transform: none; }
  .timeline-step::before, .timeline-step .n { transition: none; }
  .timeline-step::before { background: var(--clay); border-color: var(--clay); }
}

/* ---------- Scroll progress ----------
   A 2px navy rule across the top showing read position. Scale, not width, so it
   is a compositor property and costs nothing per frame on a long page. */
.scroll-progress {
  position: fixed; top: 0; left: 0; right: 0; z-index: 140;
  height: 2px; background: var(--clay);
  transform: scaleX(var(--p, 0)); transform-origin: left center;
  pointer-events: none;
}

/* ---------- Image wipe ----------
   Photographs reveal bottom-to-top behind a moving edge rather than simply
   fading. clip-path is composited, and because the element's box never changes
   the surrounding layout is untouched.

   Scoped to html.js: the clipped starting state must only ever exist where
   there is scripting to remove it, or a JS failure would leave every image on
   the site invisible. */
.js .wipe {
  opacity: 1;
  clip-path: none;
  filter: blur(14px);
  transform: scale(1.035);
  transition: filter .68s var(--ease-soft), transform .82s var(--ease-soft);
  will-change: filter, transform;
}
.js .wipe.is-wiped { opacity:1; clip-path:none; filter:none; transform:none; }
.js .wipe.is-wiped { will-change:auto; }

/* The other entrance: a photograph that has NOT finished downloading when it
   reaches the fold. main.js adds .is-held, and the reserved box — already the
   right size, because every image carries width/height from image-manifest.php —
   holds a moving tonal sheen instead of sitting empty. No placeholder file, no
   extra request: the shimmer is the img element's own background, visible for
   exactly as long as it has no bitmap to paint over it.

   These rules must stay AFTER .is-wiped. A held image can also pick up that
   class from the load sweep, and the held state has to win, or the photograph
   would drop back to the wipe's hidden state and flash. */
.js .wipe.is-held {
  opacity: 1;
  clip-path: none;
  /* The same scale the clip wipe settles from. Below the fold this entrance
     replaces that one, and it has to belong to the same motion family rather
     than reading as a different effect bolted on. */
  transform: scale(1.035);
  filter: blur(14px) saturate(.92);
  background-color: transparent;
  background-image: none;
  animation: none;
  will-change: filter, transform;
}
/* Decoded. The blur clears over most of a second — the photograph resolves
   rather than appearing — and the sheen stops the moment there is a real image
   to look at. */
.js .wipe.is-held.is-developed {
  filter: blur(0) saturate(1);
  transform: none;
  background-image: none;
  background-color: transparent;
  animation: none;
  transition: filter .85s var(--ease-soft), transform .95s var(--ease-soft);
  will-change: auto;
}
@keyframes media-hold {
  from { background-position: 130% 0; }
  to   { background-position: -30% 0; }
}

/* ---------- Headings set line by line ----------
   main.js splits each qualifying h2 into its rendered lines: .lnw is the mask,
   .ln is the line that rises through it. Both are display:block so the heading
   still breaks where it always did.

   Everything is scoped to html.js and .line-head is only added by script, so
   without JavaScript the heading is ordinary text — never a mask hiding copy
   that has nothing left to reveal it. */
/* clip-path with a negative bleed, not overflow:hidden. Section titles are set
   at a tight line-height, so a box-edge mask shaves the descenders off every g,
   y and p — the same reason .mask-head above is clipped this way rather than
   scrolled. The bleed is far smaller than the 105% the line starts at, so
   nothing appears early. */
.js .line-head .lnw { display: block; clip-path: inset(0 -0.22em -0.16em -0.22em); }
.js .line-head .ln {
  display: block;
  transform: translate3d(0, 105%, 0);
  /* The sitewide beat, then this line's place in the heading. main.js zeroes
     --load-delay on a heading that is on the first screen. */
  transition: transform .78s var(--ease-soft) calc(var(--load-delay, 0ms) + var(--i, 0) * 85ms);
  will-change: transform;
}
.js .line-head.is-lines-in .ln { transform: none; }
/* Released after the last line lands: the mask goes back to visible so a later
   re-wrap — a resize, a zoom, a font finally swapping — is never clipped. */
.js .line-head.is-lines-done .lnw { clip-path: none; }
.js .line-head.is-lines-done .ln { will-change: auto; }
@media (max-width: 560px) {
  .js .line-head .ln { transition-duration: .62s; transition-delay: calc(var(--load-delay, 0ms) + var(--i, 0) * 65ms); }
}

/* A restrained editorial lift for copy that has not already been given a
   component-specific reveal. It is added by main.js only after it confirms
   motion is allowed, so copy remains immediately readable without scripting. */
.js .scroll-copy {
  opacity:0;
  transform:translate3d(0, 14px, 0);
  transition:opacity .45s ease var(--copy-delay, 0ms), transform .7s var(--ease-soft) var(--copy-delay, 0ms);
  will-change:opacity, transform;
}
.js .scroll-copy.is-copy-in { opacity:1; transform:none; }
.js .scroll-copy.is-copy-done { will-change:auto; }
@media (max-width:560px) {
  .js .wipe { transform:translate3d(0, 8px, 0) scale(1.025); }
  .js .scroll-copy { transform:translate3d(0, 9px, 0); }
}

/* ---------- Locality chips ----------
   Replaces a 90-word paragraph of place names. Same names, same search value,
   read in a second rather than a paragraph. They stagger in 32ms apart; the
   delay is set by main.js as a custom property so the count can vary. */
.chips {
  display: flex; flex-wrap: wrap; gap: 9px;
  list-style: none; padding: 0; margin-top: 26px;
}
.chips li {
  padding: 9px 15px; min-height: 38px;
  display: inline-flex; align-items: center;
  border: 1px solid var(--line); border-radius: 999px;
  color: var(--ink-soft); font-size: 13px; font-weight: 500;
  background: transparent;
  transition: color .25s var(--ease), background-color .25s var(--ease),
              border-color .25s var(--ease), transform .25s var(--ease);
}
@media (hover: hover) {
  .chips li:hover {
    background: var(--clay); border-color: var(--clay); color: var(--white);
    transform: translateY(-2px);
  }
}
/* Entry stagger. Scoped to html.js, so with scripting off the chips are simply
   present â€” they are never hidden by a rule nothing will ever undo. */
.js .chips.is-staggered li {
  opacity: 0; transform: translateY(10px);
  animation: chipIn .42s var(--ease) forwards;
  animation-delay: calc(var(--i, 0) * 32ms);
}
@keyframes chipIn { to { opacity: 1; transform: none; } }

/* ============================================================
   HOVER-REVEAL CARDS
   The card IS the photograph. Its text sits in an overlay that is invisible
   until the card is hovered or focused, so a grid reads as a wall of work
   rather than as a directory of captioned thumbnails.

   Three rules make this safe rather than merely fashionable:

   1. The overlay is `opacity: 0`, NEVER `display:none` or `visibility:hidden`.
      It stays in the DOM and in the accessibility tree at all times, so screen
      readers announce it and search engines index it. Hiding it properly would
      silently delete this copy from the page for both.
   2. `:focus-within` fires the identical state, so every card's detail is
      reachable by keyboard alone.
   3. Touch devices have no hover state, so a hover-gated detail there is
      content that simply does not exist. Below, `@media (hover: none)` pins the
      overlay permanently open and the card reads as a captioned image.
   ============================================================ */
.industry-card, .proj-card, .svc-band .svc-card {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: 10px;
  overflow: hidden;
  background: var(--ink);
}
/* The media fills the whole card rather than sitting in a band at the top. */
.industry-card-media, .proj-card-media, .svc-band .svc-card-media {
  position: absolute; inset: 0;
  aspect-ratio: auto;
  height: 100%;
}
.industry-card-media img, .proj-card-media img, .svc-band .svc-card-media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .7s var(--ease);
}
.industry-card:hover .industry-card-media img,
.proj-card:hover .proj-card-media img,
.svc-band .svc-card:hover .svc-card-media img { transform: scale(1.07); }

/* Scrim. Its own layer so it can fade independently of the text above it. */
.industry-card::before, .proj-card::before, .svc-band .svc-card::before {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg,
    rgba(0,0,59,0) 28%, rgba(0,0,59,.62) 62%, rgba(0,0,59,.93) 100%);
  opacity: 0;
  transition: opacity .5s var(--ease);
}

/* The overlay itself. */
.industry-card-body, .proj-card-body, .svc-band .svc-card-content {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  display: flex; flex-direction: column; flex: 0 1 auto;
  padding: 24px 22px 26px;
  opacity: 0;
  transition: opacity .45s var(--ease);
}
.industry-card .idx, .proj-card .meta, .svc-band .svc-card .idx {
  color: var(--gold); font-size: 10px; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase;
}
.industry-card h3, .proj-card h3, .svc-band .svc-card h3 {
  margin: 10px 0 8px; color: var(--white);
  font-size: clamp(19px, 1.5vw, 23px); font-weight: 600;
  letter-spacing: -.015em; line-height: 1.2; text-wrap: balance;
  transform: translateY(10px);
  transition: transform .45s var(--ease);
}
.industry-card p, .proj-card p, .svc-band .svc-card p {
  color: rgba(255,255,255,.88); font-size: 13.5px; line-height: 1.45;
  max-width: none;
  /* Two lines. A card is a hook, not the page. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
  transform: translateY(12px);
  transition: transform .45s var(--ease) .06s;
}
.industry-card-body::after, .proj-card-body::after,
.svc-band .svc-card-content::after {
  margin-top: 14px; padding-top: 0;
  color: var(--gold); font-size: 10px; font-weight: 600; letter-spacing: .18em;
}

/* Hover / focus: everything arrives together, staggered by 60ms. */
.industry-card:hover::before, .industry-card:focus-within::before,
.proj-card:hover::before, .proj-card:focus-within::before,
.svc-band .svc-card:hover::before, .svc-band .svc-card:focus-within::before { opacity: 1; }

.industry-card:hover .industry-card-body, .industry-card:focus-within .industry-card-body,
.proj-card:hover .proj-card-body, .proj-card:focus-within .proj-card-body,
.svc-band .svc-card:hover .svc-card-content,
.svc-band .svc-card:focus-within .svc-card-content { opacity: 1; }

.industry-card:hover h3, .industry-card:focus-within h3,
.proj-card:hover h3, .proj-card:focus-within h3,
.svc-band .svc-card:hover h3, .svc-band .svc-card:focus-within h3,
.industry-card:hover p, .industry-card:focus-within p,
.proj-card:hover p, .proj-card:focus-within p,
.svc-band .svc-card:hover p, .svc-band .svc-card:focus-within p { transform: translateY(0); }

/* Gold underline drawing in from the left. */
.industry-card::after, .proj-card::after, .svc-band .svc-card::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  height: 2px; background: var(--gold);
  transform: scaleX(0); transform-origin: left center;
  transition: transform .55s var(--ease);
}
.industry-card:hover::after, .industry-card:focus-within::after,
.proj-card:hover::after, .proj-card:focus-within::after,
.svc-band .svc-card:hover::after, .svc-band .svc-card:focus-within::after { transform: scaleX(1); }

/* The title colour-change and white card background from the old flat layout no
   longer apply â€” the card is a photograph now. */
.industry-card:hover h3, .proj-card:hover h3 { color: var(--white); }
.svc-band .svc-card:hover, .svc-band .svc-card:focus-within { background: var(--ink); }

/* ---------- Services hub variant ----------
   services.php builds its cards differently â€” the media and body sit inside an
   <a> rather than beside each other â€” so the selectors above miss it entirely,
   and the hub was still showing flat captioned cards while the homepage showed
   hover reveals. Same component, same behaviour, matched to that markup.

   EVERY rule below is gated on :has(.svc-card-media). 404.php reuses .svc-grid
   for a purely typographic list of the nine services with no images at all â€”
   ungated, these rules turned that page into nine blank 813px dark tiles whose
   text only appeared on hover. A hover card with no photograph is not a card,
   it is a hole. Text-only cards keep the plain treatment further up the file. */
.svc-grid .svc-card:has(.svc-card-media) { border: 0; background: none; box-shadow: none; }
.svc-grid .svc-card-link:has(.svc-card-media) {
  position: relative; display: block;
  aspect-ratio: 3 / 4; border-radius: 10px; overflow: hidden;
  background: var(--ink);
}
.svc-grid .svc-card-media { position: absolute; inset: 0; display: block; }
.svc-grid .svc-card-media img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease); }
.svc-grid .svc-card-link:has(.svc-card-media):hover .svc-card-media img { transform: scale(1.07); }
.svc-grid .svc-card-link:has(.svc-card-media)::before {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(0,0,59,0) 28%, rgba(0,0,59,.62) 62%, rgba(0,0,59,.93) 100%);
  opacity: 0; transition: opacity .5s var(--ease);
}
.svc-grid .svc-card-link:has(.svc-card-media) .svc-card-body {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  display: flex; flex-direction: column; padding: 24px 22px 26px;
  opacity: 0; transition: opacity .45s var(--ease);
}
.svc-grid .svc-card-link:has(.svc-card-media) .svc-card-title {
  color: var(--white); font-size: clamp(19px, 1.5vw, 23px); font-weight: 600;
  letter-spacing: -.015em; line-height: 1.2;
  transform: translateY(10px); transition: transform .45s var(--ease);
}
.svc-grid .svc-card-link:has(.svc-card-media) .svc-card-copy {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
  margin-top: 8px; color: rgba(255,255,255,.88); font-size: 13.5px; line-height: 1.45;
  transform: translateY(12px); transition: transform .45s var(--ease) .06s;
}
.svc-grid .svc-card-tags { display: none; }   /* the overlay has no room for them */
.svc-grid .svc-card-cta { margin-top: 14px; color: var(--gold); font-size: 10px; font-weight: 600; letter-spacing: .18em; text-transform: uppercase; }
.svc-grid .svc-card-link:has(.svc-card-media)::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  height: 2px; background: var(--gold);
  transform: scaleX(0); transform-origin: left center;
  transition: transform .55s var(--ease);
}
.svc-grid .svc-card-link:has(.svc-card-media):hover::before, .svc-grid .svc-card-link:has(.svc-card-media):focus-visible::before { opacity: 1; }
.svc-grid .svc-card-link:has(.svc-card-media):hover .svc-card-body, .svc-grid .svc-card-link:has(.svc-card-media):focus-visible .svc-card-body { opacity: 1; }
.svc-grid .svc-card-link:has(.svc-card-media):hover .svc-card-title, .svc-grid .svc-card-link:has(.svc-card-media):focus-visible .svc-card-title,
.svc-grid .svc-card-link:has(.svc-card-media):hover .svc-card-copy, .svc-grid .svc-card-link:has(.svc-card-media):focus-visible .svc-card-copy { transform: translateY(0); }
.svc-grid .svc-card-link:has(.svc-card-media):hover::after, .svc-grid .svc-card-link:has(.svc-card-media):focus-visible::after { transform: scaleX(1); }

/* ---------- Touch: no hover exists, so nothing may depend on it ---------- */
@media (hover: none), (pointer: coarse) {
  .industry-card::before, .proj-card::before, .svc-band .svc-card::before { opacity: .95; }
  .industry-card-body, .proj-card-body, .svc-band .svc-card-content { opacity: 1; }
  .industry-card h3, .proj-card h3, .svc-band .svc-card h3,
  .industry-card p, .proj-card p, .svc-band .svc-card p { transform: none; }
  .industry-card::after, .proj-card::after, .svc-band .svc-card::after { transform: scaleX(1); }

  .svc-grid .svc-card-link:has(.svc-card-media)::before { opacity: .95; }
  .svc-grid .svc-card-link:has(.svc-card-media) .svc-card-body { opacity: 1; }
  .svc-grid .svc-card-title, .svc-grid .svc-card-link:has(.svc-card-media) .svc-card-copy { transform: none; }
  .svc-grid .svc-card-link:has(.svc-card-media)::after { transform: scaleX(1); }
}

/* ============================================================
   ============================================================
   CINEMATIC LAYER
   ============================================================

   The brief for this pass was "Awwwards-level, cinematic, luxurious". The
   temptation with that brief is a repaint — dark background, gold everything,
   done. That was rejected: the navy/paper/gold palette above IS the identity
   and does not change.

   What changes is LIGHT. An interior is only ever as good as the way it is lit,
   and that is the metaphor the whole page now runs on. The page alternates
   between lit rooms (paper, warm, open) and dark rooms (deep navy, gold-lit,
   theatrical), and every transition between the two is staged rather than
   abrupt. The drama comes from the cut between them, not from a new hex code.

   Everything below is additive. Not one existing selector is redefined, so the
   site renders exactly as it did if this entire block is deleted.
   ============================================================ */

:root {
  /* Two steps below --clay, for full-bleed cinematic bands. --clay is the brand
     navy and stays exactly what it is; these are the same hue taken down for
     depth, so a dark band reads as the brand lit low rather than as black. */
  --noir:    #05051f;
  --noir-2:  #0b0b2e;

  /* Gold, lifted. --gold is correct on navy at text sizes; at hairline widths
     and on moving elements it disappears, so specular highlights use this. */
  --gold-lit: #e8d5a8;

  /* Glass. One set of values used by the header, the menu and every floating
     panel, so "glass" means one specific thing across the site rather than six
     slightly different blurs. */
  --glass:      rgba(255,255,255,.055);
  --glass-line: rgba(255,255,255,.14);
  /* Saturation is deliberately low. The canonical "Apple glass" recipe is
     saturate(180%), which is tuned for blurring UI chrome; over full-bleed
     interior photography it amplifies every hue behind the bar and the header
     turns into a rainbow smear as you scroll past a blue wall and a wood floor.
     120% keeps the sense of depth without the prism. */
  --glass-blur: saturate(120%) blur(20px);

  /* The house easing curves. --ease already exists and is the expressive one;
     these two are its quieter siblings, for movement that should not draw
     attention to itself. */
  --ease-soft: cubic-bezier(.32,.72,0,1);
  --ease-out:  cubic-bezier(.22,1,.36,1);

  /* ---- Scroll load cadence: the two knobs that time the whole page ----
     --load-delay  the beat between an element crossing its trigger and its
                   entrance starting. Added AHEAD of each module's own stagger,
                   never instead of it.
     --hold-min    the minimum time a photograph shows its placeholder before it
                   resolves, so the loading state is seen on a warm cache and a
                   fast connection instead of only on a slow one.

     main.js reads both at boot rather than restating the numbers, so retuning
     the cadence sitewide is these two lines and nothing else. Both are deliberate
     waiting: keep them short, and note that the first viewport at load is
     exempt from both — that screen decides whether the site feels fast. */
  --load-delay: 130ms;
  --hold-min: 240ms;

  /* Written by main.js from Lenis: normalised scroll velocity, signed. Drives
     the marquee's skew and the cursor's stretch, so the whole page reacts to
     how hard the visitor is scrolling rather than merely that they are. */
  --vel: 0;
}

/* ============================================================
   CINEMATIC BANDS
   A full-bleed dark room. Used by the statistics band, the pinned portfolio and
   the testimonial stage. The gradient is not decoration: it is a soft key light
   from upper-left, which is what stops a large dark area reading as a flat void.
   ============================================================ */
.band-noir {
  position: relative;
  isolation: isolate;
  background: var(--noir);
  color: var(--white);
  overflow: hidden;
}
.band-noir::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(120% 80% at 12% 0%,  rgba(217,195,154,.13), transparent 58%),
    radial-gradient(90%  70% at 88% 100%, rgba(27,27,92,.85),  transparent 62%);
}
/* A slow drift on the key light. 34 seconds — long enough that it is felt as
   the room being alive rather than seen as an animation. */
.band-noir::after {
  content: '';
  position: absolute;
  inset: -30%;
  z-index: -1;
  background: radial-gradient(closest-side, rgba(217,195,154,.09), transparent);
  animation: band-drift 34s ease-in-out infinite alternate;
  pointer-events: none;
}
@keyframes band-drift {
  from { transform: translate3d(-14%, -8%, 0) scale(1); }
  to   { transform: translate3d( 14%,  8%, 0) scale(1.18); }
}

.band-noir .eyebrow { color: var(--gold); }
.band-noir .section-title, .band-noir h2, .band-noir h3 { color: var(--white); }
.band-noir p { color: rgba(255,255,255,.72); }

/* ============================================================
   HERO — CINEMATIC
   Three additions to the existing slideshow: the image now breathes, the whole
   scene has depth that answers the pointer, and the headline arrives a word at
   a time instead of as a block.
   ============================================================ */

/* ---------- Cinematic hero motion ----------
   Each active still moves in a different direction. The changing camera path,
   shallow zoom and restrained light pass make the short slideshow read like a
   sequence of moving shots while keeping the hero as light as photographs. */
.hero-slide .hero-bg { will-change: auto; }
.hero-slide::after {
  content: '';
  position: absolute;
  inset: -18%;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(112deg, transparent 39%, rgba(255,255,255,.13) 50%, transparent 61%);
  mix-blend-mode: screen;
  transform: translate3d(-54%, 0, 0) skewX(-12deg);
}
.hero-slide.is-active::after { animation: hero-light-pass 3.2s linear both; }
.hero-slide.is-active .hero-bg { animation: hero-glide-right 4.6s cubic-bezier(.22,.72,.19,1) both; }
.hero-slide[data-motion="glide-left"].is-active .hero-bg { animation-name: hero-glide-left; }
.hero-slide[data-motion="rise"].is-active .hero-bg { animation-name: hero-rise; }
.hero-slide[data-motion="descend"].is-active .hero-bg { animation-name: hero-descend; }
.hero-slide[data-motion="sweep"].is-active .hero-bg { animation-name: hero-sweep; }
@keyframes hero-glide-right {
  from { transform: scale(1.04) translate3d(-1.5%, .7%, 0); }
  to   { transform: scale(1.12) translate3d(.9%, -.7%, 0); }
}
@keyframes hero-glide-left {
  from { transform: scale(1.11) translate3d(1.1%, .6%, 0); }
  to   { transform: scale(1.04) translate3d(-1.3%, -.8%, 0); }
}
@keyframes hero-rise {
  from { transform: scale(1.11) translate3d(0, 1.8%, 0); }
  to   { transform: scale(1.04) translate3d(-.5%, -1.1%, 0); }
}
@keyframes hero-descend {
  from { transform: scale(1.04) translate3d(.5%, -1.7%, 0); }
  to   { transform: scale(1.11) translate3d(-.8%, .8%, 0); }
}
@keyframes hero-sweep {
  from { transform: scale(1.06) translate3d(-1.2%, -.4%, 0); }
  to   { transform: scale(1.12) translate3d(1.1%, .5%, 0); }
}
@keyframes hero-light-pass {
  0% { opacity: 0; transform: translate3d(-54%, 0, 0) skewX(-12deg); }
  18% { opacity: .42; }
  62% { opacity: .1; }
  100% { opacity: 0; transform: translate3d(55%, 0, 0) skewX(-12deg); }
}

/* ---------- Minimal type + continuous hero polish ----------
   Applied late so every page shares a calm, light Montserrat system even where
   earlier component rules set a heavier default. The emphasis is created by
   spacing, image contrast and motion rather than bold type. */
body { font-weight: 400; }
h1, h2, .section-title, .feature-shot-cap h2, .cta h2, .cta-panel h2 {
  font-family: 'Montserrat', sans-serif;
  font-weight: 400 !important;
  letter-spacing: -.04em;
}
h3, h4, .proj-card h3, .industry-card h3, .svc-card h3, .post-card h3 {
  font-weight: 500 !important;
}
p, li, input, textarea, select { font-weight: 400 !important; }
.eyebrow, .meta, .idx { font-weight: 500 !important; }
.btn, .nav-links a, .site-header a, .gallery-jump a { font-weight: 500; }
.hero-actions .btn-dark { animation: hero-button-glow 3.8s ease-in-out infinite; }
@keyframes hero-button-glow {
  0%, 100% { box-shadow: 0 12px 30px rgba(16,12,36,.34), inset 0 1px rgba(255,255,255,.45); }
  50% { box-shadow: 0 16px 38px rgba(225,184,109,.34), inset 0 1px rgba(255,255,255,.58); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-vignette, .hero-bloom, .hero-actions .btn-dark { animation: none; }
}

/* ---------- Pointer depth ----------
   --px/--py are written by main.js, normalised to roughly -1..1 from the
   pointer's offset from centre. Each layer takes a different multiple, which is
   what produces parallax rather than a single sliding plane.

   The transition is the important part: without it the layers snap to each new
   pointer sample and the effect reads as jitter. With it, the scene lags the
   cursor slightly and reads as weight. */
/* The overscan below (scale 1.045) is what stops the parallax translate from
   dragging the photograph's edge into view. It also makes .hero-cine wider than
   the viewport, and .hero-cine's own overflow:hidden clips its CHILDREN, not
   itself — so without this the section overflowed the document by 10px and put
   a horizontal scrollbar on every page. The hero clips its own layers. */
.hero {
  --px: 0; --py: 0;
  overflow: hidden;
  /* Keeps the scaled parallax layer from becoming document-level overflow
     without introducing an overflow:clip scrolling context on mobile. */
  contain: paint;
}
.hero-cine {
  transform: translate3d(calc(var(--px) * -14px), calc(var(--py) * -10px), 0) scale(1.025);
  transition: transform .9s var(--ease-soft);
}
.hero .hero-content {
  transform: translate3d(calc(var(--px) * 7px), calc(var(--py) * 5px), 0);
  transition: transform 1.1s var(--ease-soft);
}
.hero .hero-feature {
  transform: translate3d(calc(var(--px) * 12px), calc(var(--py) * 8px), 0);
  transition: transform 1.2s var(--ease-soft);
}

/* ---------- Dynamic lighting ----------
   A bloom that tracks the pointer, as if the cursor were a light source moving
   across the room. screen blend so it lifts the image rather than washing a
   grey film over it. */
.hero-bloom {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: .5;
  background: radial-gradient(
    30% 40% at calc(50% + var(--px) * 24%) calc(48% + var(--py) * 22%),
    rgba(232,213,168,.20), transparent 70%
  );
  transition: background .5s linear;
  animation: hero-bloom-breathe 8s ease-in-out infinite alternate;
}
@keyframes hero-bloom-breathe {
  from { opacity: .32; transform: scale(.96); }
  to   { opacity: .6; transform: scale(1.06); }
}

/* A deepening vignette, so the corners fall away and the eye is pushed to the
   headline. Sits above the photograph and below the copy. */
.hero-vignette {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
     radial-gradient(130% 100% at 50% 42%, transparent 44%, rgba(16,16,16,.42) 100%),
     linear-gradient(180deg, rgba(16,16,16,.30) 0%, transparent 26%, transparent 62%, rgba(16,16,16,.46) 100%);
  animation: hero-vignette-breathe 12s ease-in-out infinite alternate;
}
@keyframes hero-vignette-breathe {
  from { opacity: .78; transform: scale(1); }
  to   { opacity: 1; transform: scale(1.025); }
}

/* ---------- Ambient motes ----------
   Six of them, not a particle system. A canvas of drifting dust over a hero is
   a well-known way to spend 8% of a phone's CPU on something nobody consciously
   notices; six absolutely-positioned divs on compositor-only transforms cost
   effectively nothing and read the same.

   Each is placed and timed by an --i custom property from the markup, so the
   pattern is irregular without six hand-written rules. */
.hero-motes { position: absolute; inset: 0; z-index: 2; pointer-events: none; overflow: hidden; }
.hero-mote {
  position: absolute;
  top: var(--t);
  left: var(--l);
  width: var(--s);
  height: var(--s);
  border-radius: 50%;
  background: var(--gold-lit);
  opacity: 0;
  filter: blur(.4px);
  box-shadow: 0 0 10px 1px rgba(232,213,168,.5);
  animation: mote-drift var(--d) ease-in-out var(--delay) infinite;
}
@keyframes mote-drift {
  0%        { opacity: 0;   transform: translate3d(0, 18px, 0) scale(.6); }
  18%, 72%  { opacity: .55; }
  100%      { opacity: 0;   transform: translate3d(14px, -70px, 0) scale(1.1); }
}

/* ---------- Split headline ----------
   main.js wraps every word in .w > .wi. The outer element is the mask, the
   inner one does the travelling. Because each word masks independently, the
   line does not have to be a single block — descenders and ascenders are never
   clipped by a neighbour's box.

   The 3D rotation is what separates this from a plain slide: the word pivots up
   from below the baseline, which reads as type being set rather than type being
   moved. */
/* Scoped to .is-split, which main.js applies to whichever heading it split —
   NOT to .hero. This site has five hero components and the styling must not
   have to know which one it landed in. */
.is-split .w {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: .06em;      /* room for descenders inside the mask */
  margin-bottom: -.06em;
}
.is-split .wi {
  display: inline-block;
  transform: translate3d(0, 110%, 0) rotate(4deg);
  opacity: 0;
  transform-origin: left bottom;
  transition:
    transform 1.05s var(--ease-soft) var(--wd, 0ms),
    opacity   .7s  linear           var(--wd, 0ms);
}
.is-split.is-split-in .wi { transform: translate3d(0,0,0) rotate(0); opacity: 1; }

/* Applied by main.js when the page resolves in a hidden tab. Killing the
   transition is the whole point: with no frames being produced there is nothing
   to advance it, and a heading half-way through a transition it can never
   finish is an invisible heading. */
.is-split.is-split-instant .wi { transition: none; }

/* The gold rule under the eyebrow draws itself once the headline has landed. */
.hero-tag { position: relative; }
.hero-tag::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -8px;
  height: 1px;
  width: 100%;
  background: linear-gradient(90deg, var(--gold), transparent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1.2s var(--ease-soft) .5s;
}
.hero-in .hero-tag::after { transform: scaleX(1); }

/* ---------- Scroll cue ----------
   Existing element, given a travelling fill so it reads as an invitation rather
   than a label. */
.hero-cue .hero-cue-rail { position: relative; overflow: hidden; }
.hero-cue .hero-cue-rail::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--gold-lit);
  animation: cue-run 2.4s var(--ease-soft) infinite;
}
@keyframes cue-run {
  0%        { transform: translate3d(0,-100%,0); }
  55%, 100% { transform: translate3d(0, 100%,0); }
}

/* ============================================================
   INNER-PAGE HEROES
   The homepage was the whole brief, but a site is not its homepage. These rules
   carry the same opening gesture to the other fifteen pages, in the register
   each one actually calls for — which is emphatically NOT "make every page a
   fullscreen cinematic hero". A service page has to be scannable and has to
   rank; burying its H1 under 100vh of photograph would cost more than it buys.
   ============================================================ */

/* ---------- Lit rooms: About, Contact, Gallery, 404 ----------
   These are flat paper blocks. Next to the reworked homepage they read as
   unfinished — not because they are badly set, but because nothing in them is
   lit. One soft warm source from the upper left, the same key light the dark
   bands use, inverted for paper. */
.page-hero,
.gallery-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}
.page-hero::before,
.gallery-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(70% 120% at 8% -10%, rgba(217,195,154,.30), transparent 62%),
    radial-gradient(50% 90%  at 96% 110%, rgba(0,0,59,.055),   transparent 66%);
}/* ---------- Photographic heroes: 9 service pages + services hub ----------
   These already carry a full-bleed photograph and a gradient overlay, and they
   are already close to the new direction. What they lack is life: the picture
   sits perfectly still while every comparable surface on the homepage breathes.

   The image moves off the section's own background and onto an ::after layer,
   because a background-image cannot be transformed and animating
   background-size/position is a per-frame repaint of a full-bleed photograph.
   On a pseudo-element it is one compositor layer and effectively free.

   Layer order inside the section's stacking context (isolation:isolate):
     section background   #14132a, the fallback behind everything
     ::after   z-index -2  the photograph, drifting
     ::before  z-index -1  the existing gradient overlay, untouched
     content               breadcrumb, eyebrow, H1, lede
   The overlay stays ABOVE the photograph, so text contrast is unchanged. */
/* Slower and shallower than the homepage's ken-burns: that one is the headline
   act on a page people scroll through, these are the backdrop to text people
   have come to read. */
@keyframes hero-drift {
  from { transform: scale(1.03) translate3d(0, 0, 0); }
  to   { transform: scale(1.08) translate3d(-1%, -1.2%, 0); }
}

/* Header stays as one clean, solid navigation bar at every scroll position. */
.site-header.is-stuck {
  background: var(--paper);
  border-bottom-color: var(--line);
  box-shadow: 0 1px 0 var(--line), 0 4px 16px rgba(20,19,42,.045);
}
.site-header.is-stuck .nav {
  height: 72px;
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
.site-header.is-stuck .brand img { height:auto; }
@media (max-width:560px) { .site-header.is-stuck .brand img { height:auto; } }

/* The nav underline is NOT redefined here. It already exists further up the file
   as a left-origin scaleX on .nav-links a::after, and it is already correct —
   including its :focus-visible state. A second rule here would win on cascade
   order and silently flip the origin to centre, which is a different design
   decision wearing the costume of an enhancement. Left as authored.

   The logo answers the pointer. Scale only — a mark that rotates or bounces
   stops being a mark. */
.brand img { transition: transform .6s var(--ease-soft), opacity .4s; }
.brand:hover img { transform: scale(1.045); }

/* Minimal mobile navigation: a solid sheet, compact type and no decorative
   colour treatment. The existing JavaScript still handles focus and Escape. */
@media (max-width: 880px) {
  .nav-links {
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    clip-path: none;
    transition: transform .35s var(--ease), opacity .2s ease, visibility .2s;
  }
  .nav-links.open { transform: none; }
  .nav-links::before { display:none; }
  body.menu-open .site-header { background:var(--paper); border-bottom-color:var(--line); }
  body.menu-open .menu-toggle { background:var(--white); border-color:var(--line); color:var(--ink); }
  body.menu-open .menu-toggle-icon span { background:var(--ink); }
  body.menu-open .brand img { filter:none; }
  .nav-links > a:not(.nav-cta),
  .nav-services-trigger > a {
    font-family: 'Montserrat', sans-serif;
    font-size:17px;
    font-weight: 400;
    letter-spacing: -.01em;
    color: var(--ink);
    border-bottom-color: var(--line);
  }
  .nav-links > a.active,
  .nav-services-trigger > a.active { color: var(--clay); }
  .nav-services { border-bottom-color: var(--line); }
  .services-toggle { color: var(--ink-soft); border-left-color:var(--line); }
  .nav-services.services-open .services-toggle { color:var(--clay); }
  .services-col-title { color:var(--clay); }
  .services-menu a {
    color: var(--ink-soft) !important;
    border-left-color: var(--line);
    font-family: 'Montserrat', sans-serif;
  }
  .services-menu a:hover,
  .services-menu a:focus-visible,
  .services-menu a.is-current { color:var(--clay) !important; border-left-color:var(--clay); }
  .services-menu a.is-current { box-shadow:inset 1px 0 0 var(--clay); }

  .nav-links .nav-cta {
    background:var(--noir);
    color:var(--white) !important;
    box-shadow:none;
  }
  .nav-social { border-top-color:var(--line); }
  .nav-social-title { color:var(--clay); }
  .nav-social .social-link {
    background:var(--white);
    border-color:var(--line);
    color:var(--ink-soft);
  }
}

/* ============================================================
   STATISTICS BAND
   Every figure here is real and comes from site-config.php. There is no
   "500+ Happy Clients" and no "12 Awards", because a studio founded in 2024
   claiming a decade of trophies is the fastest way to lose the one visitor who
   checks. The count-up uses the existing [data-count] module.
   ============================================================ */
.stats-band { padding-block: var(--space-xl); }
.stats-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: rgba(255,255,255,.12);      /* the gaps become the hairlines */
  border: 1px solid rgba(255,255,255,.12);
}
.stat-cell {
  background: var(--noir);
  padding: clamp(30px, 4.4vw, 54px) clamp(20px, 2.6vw, 34px);
  text-align: center;
  position: relative;
  overflow: hidden;
}
/* A light that sweeps across on entry, once. Gives the band a sense of being
   switched on rather than merely appearing. */
.stat-cell::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 38%, rgba(232,213,168,.12) 50%, transparent 62%);
  transform: translate3d(-130%, 0, 0);
}
.stats-grid.is-lit .stat-cell::before {
  animation: stat-sweep 1.5s var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 130ms + 200ms);
}
@keyframes stat-sweep { to { transform: translate3d(130%, 0, 0); } }

.stat-figure {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 2px;
  font-family: 'Fraunces', Georgia, serif;
  font-size: clamp(44px, 6.4vw, 82px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -.03em;
  color: var(--white);
  font-variant-numeric: tabular-nums;
}
.stat-figure .suffix { color: var(--gold); font-size: .48em; }
.stat-label {
  margin-top: 16px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: rgba(255,255,255,.56);
}
.stat-note { margin-top: 8px; font-size: 13px; color: rgba(255,255,255,.42); line-height: 1.5; }

@media (max-width: 760px) {
  .stats-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   PINNED HORIZONTAL PORTFOLIO
   The section pins and the track travels sideways under GSAP ScrollTrigger.

   The markup is a plain overflow-x scroller. That matters: if GSAP does not
   load, if the viewport is narrow, or if the visitor asks for reduced motion,
   this is still a perfectly good native horizontal gallery with scroll-snap,
   touch and keyboard support. main.js adds .is-pinned only once it has actually
   taken control, and every rule that breaks native scrolling hangs off it.
   ============================================================ */
.hscroll { position: relative; padding-block: var(--space-xl) 0; }
.hscroll-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-s);
  margin-bottom: clamp(28px, 4vw, 52px);
}
.hscroll-viewport {
  position: relative;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: var(--space-xl);
}
.hscroll-viewport::-webkit-scrollbar { display: none; }
.hscroll-track {
  display: flex;
  gap: clamp(16px, 2vw, 28px);
  width: max-content;
  padding-inline: 2px;
}
.hscroll[data-autoplay="true"].is-reel-ready .hscroll-viewport {
  overflow:hidden;
  cursor:default;
  scroll-snap-type:none;
  scroll-behavior:auto;
  overflow-anchor:none;
  overscroll-behavior-inline:none;
}
.hscroll[data-autoplay="true"].is-reel-ready .hcard { scroll-snap-align:none; }
.hscroll[data-autoplay="true"].is-reel-ready:not(.is-gsap-reel) .hscroll-track {
  animation: rooms-reel var(--reel-duration, 180s) linear infinite;
  will-change: transform;
  backface-visibility:hidden;
  transform:translate3d(0, 0, 0);
}
.hscroll[data-autoplay="true"].is-gsap-reel .hscroll-track {
  animation:none;
  transform:none;
}
@keyframes rooms-reel { to { transform: translate3d(var(--reel-distance, -50%), 0, 0); } }

/* Minimal, image-led automatic room reel. Captions stay off the photograph
   until a visitor deliberately explores a card. */
.hscroll[data-autoplay="true"] { padding-block: clamp(18px, 3vw, 32px); }
.hscroll[data-autoplay="true"] .hscroll-viewport { padding-bottom: 0; }
.hscroll[data-autoplay="true"] .hcard::after {
  opacity: 0;
  background: none;
}
.hscroll[data-autoplay="true"] .hcard-body {
  padding: 18px clamp(18px, 2vw, 26px);
  background: none;
  border: 0;
  box-shadow: none;
  backdrop-filter: none;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .28s var(--ease), transform .28s var(--ease);
}
.hscroll[data-autoplay="true"] .hcard-idx { display: none; }
.hscroll[data-autoplay="true"] .hcard-body h3 {
  font-family: 'Montserrat', sans-serif;
  font-size: clamp(15px, 1.15vw, 18px);
  font-weight: 400;
  letter-spacing: -.015em;
  line-height: 1.25;
}
.hscroll[data-autoplay="true"] .hcard-body p {
  margin-top: 5px;
  font-family: 'Montserrat', sans-serif;
  font-size: clamp(11px, .85vw, 13px);
  font-weight: 400;
  color: rgba(255,255,255,.88);
  line-height: 1.5;
}
.hscroll[data-autoplay="true"] .hcard:hover .hcard-body,
.hscroll[data-autoplay="true"] .hcard:focus-visible .hcard-body,
.hscroll[data-autoplay="true"] .hcard.is-detail .hcard-body {
  opacity: 1;
  transform: translateY(0);
}
.hscroll[data-autoplay="true"] .hcard-body h3,
.hscroll[data-autoplay="true"] .hcard-body p {
  text-shadow: 0 2px 12px rgba(0,0,0,.72);
}
.hscroll-orbit {
  position: absolute; left: clamp(20px, 8vw, 120px); top: 50%; z-index: 5;
  display: grid; place-items: center; width: 96px; height: 96px;
  margin-top: -48px; border-radius: 50%; pointer-events: none;
  background: conic-gradient(from 0deg, var(--gold), rgba(217,195,154,.12) 22%, transparent 45%, var(--gold) 78%, rgba(217,195,154,.12));
  animation: hscroll-orbit 8s linear infinite;
  box-shadow: 0 0 0 1px rgba(255,255,255,.16), 0 12px 30px rgba(0,0,0,.2);
}
.hscroll-orbit::before { content: ''; position: absolute; inset: 3px; border-radius: inherit; background: var(--noir); }
.hscroll-orbit span { position: relative; z-index: 1; color: var(--white); font-size: 10px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; animation: hscroll-orbit-label 8s linear infinite reverse; }
@keyframes hscroll-orbit { to { transform: rotate(360deg); } }
@keyframes hscroll-orbit-label { to { transform: rotate(360deg); } }
.hscroll-viewport:hover .hscroll-orbit,
.hscroll-viewport:hover .hscroll-orbit span { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .hscroll-orbit, .hscroll-orbit span { animation: none; }
}
.hscroll.is-pinned .hscroll-viewport { overflow: hidden; scroll-snap-type: none; }

.hcard {
  scroll-snap-align: center;
  flex: 0 0 auto;
  width: clamp(268px, 30vw, 430px);
  position: relative;
  display: block;
  border-radius: 4px;
  overflow: hidden;
  background: var(--noir-2);
  aspect-ratio: 3 / 4;
  isolation: isolate;
}
.hcard img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Each card's image counter-drifts against the track, so the gallery has
     internal depth instead of sliding as one flat strip. --hp is written per
     card by main.js from the card's position across the viewport. */
  transform: scale(1.14) translate3d(calc(var(--hp, 0) * 26px), 0, 0);
  backface-visibility:hidden;
  will-change:transform;
  transition: transform .26s cubic-bezier(.2,.65,.2,1), filter .45s var(--ease);
}
.hcard::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(5,5,31,0) 40%, rgba(5,5,31,.55) 68%, rgba(5,5,31,.94) 100%);
}
.hcard-body {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 1;
  padding: clamp(20px, 2.4vw, 30px);
}
.hcard-idx {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 10px;
}
.hcard-body h3 {
  color: var(--white);
  font-size: clamp(18px, 1.7vw, 24px);
  font-weight: 600;
  letter-spacing: -.015em;
  line-height: 1.2;
}
.hcard-body p {
  margin-top: 8px;
  color: rgba(255,255,255,.7);
  font-size: 13.5px;
  line-height: 1.5;
  max-width: 34ch;
  /* Held back until hover on pointer devices, always visible on touch. */
  opacity: 0;
  transform: translate3d(0, 10px, 0);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.hcard:hover p, .hcard:focus-visible p { opacity: 1; transform: none; }
.hcard:hover img { filter: brightness(1.06); }
@media (hover: none), (pointer: coarse) {
  .hscroll[data-autoplay="true"] .hcard { cursor:pointer; }
  .hscroll[data-autoplay="true"] .hcard.is-detail::after { opacity:1; }
  .hscroll[data-autoplay="true"] .hcard.is-detail .hcard-body { opacity:1; transform:none; }
  .hscroll[data-autoplay="true"] .hcard.is-detail .hcard-body p { opacity:1; transform:none; }
}

/* Progress rail under the track. Fed by --p from main.js. */
.hscroll-rail {
  position: relative;
  height: 1px;
  background: rgba(255,255,255,.16);
  margin-top: 8px;
}
.hscroll-rail::after {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 100%;
  background: var(--gold);
  transform: scaleX(var(--p, 0));
  transform-origin: left center;
}
.hscroll-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 14px;
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(255,255,255,.5);
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   3D TILT
   --tx/--ty are written by main.js per card, in degrees.

   Two rules make this feel like an object rather than a CSS trick: perspective
   is set on the PARENT (so cards in a row share one vanishing point and tilt as
   a group toward the same viewer, instead of each having its own private
   camera), and the card returns on a longer curve than it tilts on.
   ============================================================ */
.tilt-scene { perspective: 1400px; }
.tilt {
  transform:
    perspective(1400px)
    rotateX(var(--ty, 0deg))
    rotateY(var(--tx, 0deg))
    translate3d(0, 0, 0);
  transform-style: preserve-3d;
  transition: transform .7s var(--ease-soft), box-shadow .5s var(--ease);
}
.tilt.is-tilting { transition: transform .12s linear, box-shadow .5s var(--ease); }
.tilt.is-tilting { box-shadow: 0 30px 60px -20px rgba(20,19,42,.4); }

/* A specular sheen that tracks the tilt — this is what sells the surface as
   glass rather than as a rotated rectangle. */
.tilt-sheen {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(
    var(--sheen-a, 120deg),
    transparent 32%,
    rgba(255,255,255,.16) 48%,
    transparent 64%
  );
  transition: opacity .45s var(--ease);
}
.tilt.is-tilting .tilt-sheen { opacity: 1; }

/* ============================================================
   BEFORE / AFTER
   Two photographs of the same space, one clipped over the other, with a handle.
   Driven by --split (0..1) written from pointer, touch and — importantly — the
   arrow keys, because a slider that only answers a mouse is a slider half the
   audience cannot use.
   ============================================================ */
.ba {
  position: relative;
  overflow: hidden;
  border-radius: 4px;
  aspect-ratio: 16 / 10;
  background: var(--noir-2);
  cursor: ew-resize;
  touch-action: none;         /* we own the horizontal drag */
  --split: .5;
}
.ba img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  user-select: none;
  -webkit-user-drag: none;
}
.ba-after { clip-path: inset(0 0 0 calc(var(--split) * 100%)); }
.ba-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--split) * 100%);
  width: 2px;
  background: var(--gold-lit);
  transform: translateX(-1px);
  z-index: 2;
  box-shadow: 0 0 22px rgba(232,213,168,.55);
}
.ba-knob {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 52px;
  height: 52px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: rgba(5,5,31,.55);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border: 1px solid var(--gold-lit);
  display: grid;
  place-items: center;
  color: var(--gold-lit);
  transition: transform .4s var(--ease-soft), background .3s;
}
.ba:hover .ba-knob { transform: translate(-50%, -50%) scale(1.08); }
.ba-knob:focus-visible { outline: 2px solid var(--gold-lit); outline-offset: 4px; }
.ba-knob svg { width: 20px; height: 20px; }
.ba-tag {
  position: absolute;
  top: 16px;
  z-index: 1;
  padding: 7px 13px;
  border-radius: 100px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  background: rgba(5,5,31,.62);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--white);
  border: 1px solid rgba(255,255,255,.16);
}
.ba-tag--before { left: 16px; }
.ba-tag--after  { right: 16px; color: var(--gold); }

/* ============================================================
   PLACEHOLDER SECTIONS
   Testimonials, awards and journal are built and styled but hold no invented
   content — see the note in index.php. This treatment makes an empty shell read
   as "deliberately reserved" rather than as "broken", and makes it obvious in
   the browser which blocks still need real material.
   ============================================================ */
.reserved {
  border: 1px dashed rgba(255,255,255,.22);
  border-radius: 4px;
  padding: clamp(30px, 5vw, 62px);
  text-align: center;
  background: rgba(255,255,255,.02);
}
.reserved--light {
  border-color: color-mix(in srgb, var(--ink) 18%, transparent);
  background: color-mix(in srgb, var(--ink) 2%, transparent);
}
.reserved-tag {
  display: inline-block;
  padding: 6px 12px;
  border-radius: 100px;
  background: rgba(217,195,154,.14);
  border: 1px solid rgba(217,195,154,.34);
  color: var(--gold);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  margin-bottom: 18px;
}
.reserved--light .reserved-tag {
  background: color-mix(in srgb, var(--clay) 8%, transparent);
  border-color: color-mix(in srgb, var(--clay) 26%, transparent);
  color: var(--clay);
}
.reserved h3 {
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 400;
  font-size: clamp(21px, 2.6vw, 30px);
  letter-spacing: -.02em;
  margin-bottom: 12px;
}
.reserved p { max-width: 56ch; margin-inline: auto; font-size: 15px; line-height: 1.65; }

/* ---------- Testimonials ---------- */
.testimonial-section { position:relative; overflow:hidden; }
.testimonial-section::before {
  content:'CLIENT VOICES';
  position:absolute;
  right:-.04em;
  top:-.2em;
  color:rgba(255,255,255,.025);
  font:400 clamp(90px, 17vw, 240px)/1 'Fraunces', Georgia, serif;
  letter-spacing:-.07em;
  white-space:nowrap;
  pointer-events:none;
}
.testimonial-head {
  position:relative;
  display:grid;
  grid-template-columns:minmax(0, 1fr) minmax(260px, 430px);
  align-items:end;
  gap:clamp(30px, 7vw, 100px);
  margin-bottom:clamp(34px, 5vw, 64px);
}
.testimonial-head .section-title { max-width:13ch; margin:0; color:var(--white); }
.testimonial-head__copy { color:rgba(255,255,255,.68); font-size:clamp(14px, 1.25vw, 17px); line-height:1.72; }
.testimonial-grid {
  display: grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:1px;
  border:1px solid rgba(255,255,255,.14);
  background:rgba(255,255,255,.14);
}
.testimonial-card {
  display:grid;
  grid-template-rows:auto 1fr auto;
  min-height:clamp(360px, 37vw, 520px);
  padding:clamp(28px, 4vw, 54px);
  border:0;
  border-radius:0;
  background:rgba(6,6,31,.84);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  position: relative;
  isolation:isolate;
  overflow:hidden;
  transition:background-color .45s var(--ease), transform .55s var(--ease-soft);
}
.testimonial-card:hover { background:rgba(13,12,48,.94); }
.testimonial-card--featured { grid-column:1 / -1; min-height:clamp(420px, 45vw, 620px); padding-right:min(46%, 520px); }
.testimonial-card::before {
  content: '\201C';
  position: absolute;
  top:clamp(42px, 6vw, 78px);
  right:clamp(26px, 4vw, 58px);
  z-index:-1;
  font-family: 'Fraunces', Georgia, serif;
  font-size:clamp(100px, 13vw, 180px);
  line-height: 1;
  color:rgba(217,195,154,.12);
}
.testimonial-card__meta { display:flex; justify-content:space-between; gap:20px; padding-bottom:24px; border-bottom:1px solid rgba(255,255,255,.13); color:var(--gold-lit); font-size:9px; font-weight:700; letter-spacing:.15em; text-transform:uppercase; }
.testimonial-card blockquote {
  align-self:center;
  max-width:29ch;
  padding-block:clamp(30px, 5vw, 62px);
  font-family: 'Fraunces', Georgia, serif;
  font-size:clamp(23px, 2.7vw, 38px);
  line-height:1.28;
  letter-spacing:-.025em;
  color:rgba(255,255,255,.94);
}
.testimonial-card figcaption { display:flex; align-items:center; gap:13px; margin-top:22px; }
.testimonial-card__avatar { display:grid; place-items:center; flex:0 0 42px; width:42px; height:42px; border:1px solid rgba(255,255,255,.24); border-radius:50%; color:var(--gold-lit); font:600 12px/1 'Montserrat', sans-serif; }
.testimonial-card__person { display:grid; gap:3px; }
.testimonial-card .nm { color: var(--white); font-size: 13px; font-weight: 700; }
.testimonial-card .ro {
  color: var(--gold);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.testimonial-card__image { position:absolute; inset:0 0 0 auto; z-index:-2; width:43%; overflow:hidden; }
.testimonial-card__image::after { content:''; position:absolute; inset:0; background:linear-gradient(90deg, rgba(6,6,31,1), rgba(6,6,31,.12) 56%, rgba(6,6,31,.16)); }
.testimonial-card__image img { width:100%; height:100%; object-fit:cover; filter:saturate(.82); transform:scale(1.025); transition:transform 1.1s var(--ease-soft), filter .6s var(--ease); }
.testimonial-card:hover .testimonial-card__image img { filter:saturate(1); transform:scale(1.06); }

.testimonial-preview { position:relative; max-width:900px; margin-inline:auto; padding:clamp(32px, 5vw, 64px); border:1px dashed rgba(255,255,255,.26); background:rgba(255,255,255,.035); color:var(--white); }
.testimonial-preview::before { content:'\201C'; position:absolute; right:32px; top:12px; color:rgba(217,195,154,.16); font:400 110px/1 'Fraunces', Georgia, serif; }
.testimonial-preview__tag { display:inline-block; margin-bottom:26px; padding:7px 10px; background:rgba(217,195,154,.12); color:var(--gold-lit); font-size:9px; font-weight:700; letter-spacing:.15em; text-transform:uppercase; }
.testimonial-preview blockquote { position:relative; max-width:28ch; font:400 clamp(24px, 3.2vw, 42px)/1.3 'Fraunces', Georgia, serif; letter-spacing:-.025em; }
.testimonial-preview__person { display:flex; align-items:center; gap:13px; margin-top:30px; }
.testimonial-preview__person > span { display:grid; place-items:center; width:42px; height:42px; border:1px solid rgba(255,255,255,.25); border-radius:50%; color:var(--gold-lit); font-size:10px; font-weight:700; }
.testimonial-preview__person div { display:grid; gap:3px; }
.testimonial-preview__person strong { font-size:13px; }
.testimonial-preview__person small { color:var(--gold); font-size:9px; font-weight:600; letter-spacing:.13em; text-transform:uppercase; }
.testimonial-preview > p { max-width:58ch; margin-top:30px; padding-top:22px; border-top:1px solid rgba(255,255,255,.12); color:rgba(255,255,255,.62); font-size:13px; line-height:1.65; }
.testimonial-preview code { color:var(--gold-lit); }

@media (max-width:760px) {
  .testimonial-head { grid-template-columns:1fr; gap:18px; }
  .testimonial-grid { grid-template-columns:1fr; }
  .testimonial-card--featured { grid-column:auto; padding-right:clamp(28px, 4vw, 54px); }
  .testimonial-card__image { position:relative; inset:auto; z-index:0; order:-1; width:calc(100% + clamp(56px, 8vw, 108px)); height:220px; margin:calc(clamp(28px, 4vw, 54px) * -1) calc(clamp(28px, 4vw, 54px) * -1) 28px; }
  .testimonial-card__image::after { background:linear-gradient(180deg, rgba(6,6,31,.02), rgba(6,6,31,.9)); }
  .testimonial-card blockquote { font-size:clamp(22px, 6vw, 30px); }
}

/* Animated testimonial carousel. The cards remain normal readable figures if
   JavaScript is unavailable; script only advances the flex track and updates
   the controls. */
.testimonial-stage { --testimonial-hold:6500ms; position:relative; }
.testimonial-viewport { overflow:hidden; border:1px solid rgba(255,255,255,.14); touch-action:pan-y; }
.testimonial-track { display:flex; width:100%; transform:translate3d(calc(var(--testimonial-index, 0) * -100%),0,0); transition:transform .85s var(--ease-soft); will-change:transform; }
.testimonial-stage .testimonial-card { flex:0 0 100%; width:100%; min-height:clamp(440px, 48vw, 650px); padding-right:min(46%, 520px); }
.testimonial-stage .testimonial-card blockquote,
.testimonial-stage .testimonial-card figcaption,
.testimonial-stage .testimonial-card__meta { opacity:.45; transform:translateY(14px); transition:opacity .7s var(--ease), transform .85s var(--ease-soft); }
.testimonial-stage .testimonial-card.is-active blockquote,
.testimonial-stage .testimonial-card.is-active figcaption,
.testimonial-stage .testimonial-card.is-active .testimonial-card__meta { opacity:1; transform:none; }
.testimonial-stage .testimonial-card.is-active blockquote { transition-delay:.12s; }
.testimonial-stage .testimonial-card.is-active figcaption { transition-delay:.22s; }
.testimonial-stage .testimonial-card.is-active .testimonial-card__image img { animation:testimonial-cinema var(--testimonial-hold) var(--ease-soft) both; }
@keyframes testimonial-cinema { from { transform:scale(1.025); } to { transform:scale(1.095); } }
.testimonial-controls { display:grid; grid-template-columns:48px minmax(120px, 1fr) auto 48px; align-items:center; gap:14px; margin-top:20px; }
.testimonial-controls button { display:grid; place-items:center; width:48px; height:48px; border:1px solid rgba(255,255,255,.3); border-radius:50%; background:rgba(255,255,255,.035); color:var(--white); cursor:pointer; font-size:20px; transition:background .3s var(--ease), border-color .3s var(--ease), transform .3s var(--ease); }
.testimonial-controls button:hover,
.testimonial-controls button:focus-visible { border-color:var(--gold-lit); background:rgba(217,195,154,.12); transform:translateY(-2px); }
.testimonial-progress { height:1px; overflow:hidden; background:rgba(255,255,255,.2); }
.testimonial-progress i { display:block; width:100%; height:100%; background:var(--gold-lit); transform:scaleX(0); transform-origin:left; }
.testimonial-stage.is-playing .testimonial-progress i { animation:testimonial-progress var(--testimonial-hold) linear forwards; }
@keyframes testimonial-progress { to { transform:scaleX(1); } }
.testimonial-count { display:flex; align-items:baseline; gap:6px; color:var(--white); font-size:12px; font-weight:700; letter-spacing:.12em; }
.testimonial-count b { color:rgba(255,255,255,.35); font-weight:400; }

@media (max-width:760px) {
  .testimonial-stage .testimonial-card { min-height:auto; padding-right:clamp(28px, 4vw, 54px); }
  .testimonial-stage .testimonial-card__image { position:relative; inset:auto; z-index:0; order:-1; width:calc(100% + clamp(56px, 8vw, 108px)); height:220px; margin:calc(clamp(28px, 4vw, 54px) * -1) calc(clamp(28px, 4vw, 54px) * -1) 28px; }
  .testimonial-controls { grid-template-columns:44px minmax(70px, 1fr) auto 44px; gap:10px; }
  .testimonial-controls button { width:44px; height:44px; }
}

@media (prefers-reduced-motion:reduce) {
  .testimonial-track,
  .testimonial-stage .testimonial-card blockquote,
  .testimonial-stage .testimonial-card figcaption,
  .testimonial-stage .testimonial-card__meta { transition:none; }
  .testimonial-stage .testimonial-card.is-active .testimonial-card__image img,
  .testimonial-stage.is-playing .testimonial-progress i { animation:none; }
  .testimonial-progress i { transform:scaleX(1); }
}

/* ---------- Premium review-gallery treatment ---------- */
.testimonial-stage {
  --testimonial-hold:7600ms;
  position:relative;
  isolation:isolate;
}
.testimonial-stage::before {
  content:'';
  position:absolute;
  inset:-28px 12% auto;
  z-index:-1;
  height:160px;
  border-radius:50%;
  background:rgba(217,195,154,.12);
  filter:blur(70px);
  pointer-events:none;
}
.testimonial-stage .testimonial-viewport {
  overflow:hidden;
  border:1px solid rgba(255,255,255,.18);
  border-radius:18px;
  background:#f5f1e8;
  box-shadow:0 34px 90px rgba(0,0,0,.34);
  touch-action:pan-y;
}
.testimonial-stage .testimonial-track {
  transition:transform .9s cubic-bezier(.22,.75,.2,1);
}
.testimonial-stage .testimonial-card {
  min-height:clamp(510px, 50vw, 680px);
  padding:clamp(34px, 5vw, 68px) min(48%, 590px) clamp(34px, 5vw, 68px) clamp(30px, 5vw, 70px);
  background:
    radial-gradient(circle at 11% 10%, rgba(210,174,111,.15), transparent 24%),
    linear-gradient(135deg, #faf7f0, #f0eadf);
  color:#17172b;
  overflow:hidden;
}
.testimonial-stage .testimonial-card::before {
  top:auto;
  right:auto;
  bottom:-.26em;
  left:.08em;
  color:rgba(16,16,49,.055);
  font-size:clamp(190px, 30vw, 430px);
}
.testimonial-card__number {
  position:absolute;
  z-index:2;
  top:clamp(28px, 4vw, 54px);
  right:clamp(24px, 3.5vw, 50px);
  color:rgba(255,255,255,.88);
  font:500 clamp(42px, 6vw, 80px)/1 'Fraunces', Georgia, serif;
  letter-spacing:-.06em;
  text-shadow:0 4px 28px rgba(0,0,0,.28);
}
.testimonial-stage .testimonial-card__meta {
  position:relative;
  z-index:2;
  color:#7c6338;
  border-bottom-color:rgba(19,19,47,.13);
}
.testimonial-card__identity {
  position:relative;
  z-index:2;
  display:flex;
  align-items:center;
  gap:14px;
  margin-top:clamp(26px, 4vw, 42px);
}
.testimonial-stage .testimonial-card__avatar {
  flex-basis:52px;
  width:52px;
  height:52px;
  border:0;
  background:linear-gradient(145deg, #141431, #343460);
  box-shadow:0 7px 22px rgba(17,17,48,.18);
  color:#f4d19d;
  font-size:14px;
}
.testimonial-stage .testimonial-card .nm { color:#17172b; font-size:14px; }
.testimonial-stage .testimonial-card .ro { color:#777383; font-size:9px; }
.testimonial-card__stars {
  position:relative;
  z-index:2;
  display:flex;
  align-items:center;
  gap:3px;
  margin-top:22px;
  color:#d09b37;
  font-size:17px;
  line-height:1;
}
.testimonial-card__stars small {
  margin-left:8px;
  color:#777383;
  font-size:9px;
  font-weight:700;
  letter-spacing:.11em;
  text-transform:uppercase;
}
.testimonial-stage .testimonial-card blockquote {
  position:relative;
  z-index:2;
  align-self:center;
  max-width:31ch;
  padding-block:clamp(24px, 3.5vw, 44px);
  color:#17172b;
  font-size:clamp(23px, 2.45vw, 38px);
  line-height:1.34;
}
.testimonial-stage .testimonial-card figcaption {
  position:relative;
  z-index:2;
  display:flex;
  align-items:center;
  gap:8px;
  margin:0;
  color:#777383;
  font-size:9px;
  font-weight:700;
  letter-spacing:.12em;
  text-transform:uppercase;
}
.testimonial-stage .testimonial-card__image {
  inset:0 0 0 auto;
  z-index:0;
  width:43%;
  clip-path:inset(0 0 0 12%);
  transition:clip-path 1.1s cubic-bezier(.22,.75,.2,1);
}
.testimonial-stage .testimonial-card__image::after {
  background:
    linear-gradient(90deg, #f0eadf 0, rgba(240,234,223,.55) 9%, transparent 34%),
    linear-gradient(180deg, rgba(5,5,24,.04), rgba(5,5,24,.22));
}
.testimonial-stage .testimonial-card__image img { filter:saturate(.82) contrast(1.02); }
.testimonial-stage .testimonial-card.is-active .testimonial-card__image { clip-path:inset(0); }
.testimonial-stage .testimonial-card__meta,
.testimonial-stage .testimonial-card__identity,
.testimonial-stage .testimonial-card__stars,
.testimonial-stage .testimonial-card blockquote,
.testimonial-stage .testimonial-card figcaption {
  opacity:.15;
  transform:translateY(22px);
  transition:opacity .65s var(--ease), transform .85s cubic-bezier(.22,.75,.2,1);
}
.testimonial-stage .testimonial-card.is-active .testimonial-card__meta,
.testimonial-stage .testimonial-card.is-active .testimonial-card__identity,
.testimonial-stage .testimonial-card.is-active .testimonial-card__stars,
.testimonial-stage .testimonial-card.is-active blockquote,
.testimonial-stage .testimonial-card.is-active figcaption { opacity:1; transform:none; }
.testimonial-stage .testimonial-card.is-active .testimonial-card__identity { transition-delay:.08s; }
.testimonial-stage .testimonial-card.is-active .testimonial-card__stars { transition-delay:.14s; }
.testimonial-stage .testimonial-card.is-active blockquote { transition-delay:.2s; }
.testimonial-stage .testimonial-card.is-active figcaption { transition-delay:.28s; }
.testimonial-stage .testimonial-card.is-active .testimonial-card__stars span { animation:testimonial-star-in .48s var(--ease-soft) both; }
.testimonial-stage .testimonial-card.is-active .testimonial-card__stars span:nth-child(2) { animation-delay:.05s; }
.testimonial-stage .testimonial-card.is-active .testimonial-card__stars span:nth-child(3) { animation-delay:.1s; }
.testimonial-stage .testimonial-card.is-active .testimonial-card__stars span:nth-child(4) { animation-delay:.15s; }
.testimonial-stage .testimonial-card.is-active .testimonial-card__stars span:nth-child(5) { animation-delay:.2s; }
.testimonial-stage .testimonial-card.is-active .testimonial-card__image img { animation:testimonial-cinema var(--testimonial-hold) var(--ease-soft) both; }
@keyframes testimonial-star-in {
  from { opacity:0; transform:translateY(5px) scale(.6) rotate(-12deg); }
  to { opacity:1; transform:none; }
}
.testimonial-chapters {
  display:grid;
  grid-template-columns:repeat(8, 1fr);
  gap:8px;
  margin-top:18px;
}
.testimonial-chapters button {
  position:relative;
  min-height:38px;
  padding:0;
  border:0;
  background:transparent;
  color:rgba(255,255,255,.42);
  cursor:pointer;
  text-align:left;
  transition:color .3s var(--ease);
}
.testimonial-chapters button::before {
  content:'';
  position:absolute;
  inset:0 0 auto;
  height:2px;
  background:rgba(255,255,255,.15);
  transition:background .3s var(--ease), transform .35s var(--ease);
  transform-origin:left;
}
.testimonial-chapters button span {
  display:block;
  padding-top:12px;
  font-size:9px;
  font-weight:700;
  letter-spacing:.12em;
}
.testimonial-chapters button:hover,
.testimonial-chapters button:focus-visible,
.testimonial-chapters button.is-active { color:var(--gold-lit); }
.testimonial-chapters button:hover::before,
.testimonial-chapters button:focus-visible::before { background:rgba(217,195,154,.5); }
.testimonial-chapters button.is-active::before { background:var(--gold-lit); transform:scaleY(2); }

@media (max-width:760px) {
  .testimonial-stage .testimonial-viewport { border-radius:13px; }
  .testimonial-stage .testimonial-card {
    display:grid;
    min-height:auto;
    padding:0 clamp(24px, 7vw, 38px) clamp(32px, 9vw, 48px);
  }
  .testimonial-stage .testimonial-card__image {
    position:relative;
    inset:auto;
    z-index:0;
    order:-1;
    width:calc(100% + clamp(48px, 14vw, 76px));
    height:clamp(210px, 61vw, 310px);
    margin:0 calc(clamp(24px, 7vw, 38px) * -1);
    clip-path:inset(0 0 12%);
  }
  .testimonial-stage .testimonial-card__image::after { background:linear-gradient(180deg, rgba(5,5,24,.02), rgba(5,5,24,.24)); }
  .testimonial-card__number { top:24px; right:24px; font-size:48px; }
  .testimonial-stage .testimonial-card__meta { margin-top:24px; padding-bottom:18px; }
  .testimonial-card__identity { margin-top:22px; }
  .testimonial-stage .testimonial-card blockquote { padding-block:24px; font-size:clamp(22px, 6.7vw, 30px); }
  .testimonial-chapters { gap:5px; }
  .testimonial-chapters button span { font-size:8px; }
}

@media (prefers-reduced-motion:reduce) {
  .testimonial-stage .testimonial-card__image,
  .testimonial-stage .testimonial-card__identity,
  .testimonial-stage .testimonial-card__stars { transition:none; }
  .testimonial-stage .testimonial-card.is-active .testimonial-card__stars span { animation:none; }
}

/* ---------- Awards ---------- */
.award-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.award-card {
  position: relative;
  overflow: hidden;
  background: var(--white);
  padding: clamp(24px, 3vw, 38px);
}
.award-year {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .2em;
  color: var(--clay);
  margin-bottom: 12px;
}
.award-card h3 { font-size: clamp(17px, 1.6vw, 21px); font-weight: 600; letter-spacing: -.015em; }
.award-card p { margin-top: 10px; font-size: 14px; line-height: 1.55; color: var(--ink-soft); }

/* ---------- Journal ---------- */
.post-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(272px, 1fr));
  gap: clamp(18px, 2.4vw, 32px);
}
.post-card {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: 4px;
  background: var(--white);
  border: 1px solid var(--line);
}
.post-card-media { aspect-ratio: 3 / 2; overflow: hidden; }
.post-card-media img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease); }
.post-card:hover .post-card-media img { transform: scale(1.06); }
.post-card-body { padding: clamp(20px, 2.2vw, 28px); }
.post-card-body .meta {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--clay);
  margin-bottom: 10px;
}
.post-card-body h3 { font-size: clamp(17px, 1.6vw, 21px); font-weight: 600; letter-spacing: -.015em; line-height: 1.25; }
.post-card-body p { margin-top: 10px; font-size: 14px; line-height: 1.55; color: var(--ink-soft); }

.reserved code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .88em;
  padding: 2px 6px;
  border-radius: 3px;
  background: rgba(217,195,154,.14);
  color: var(--gold);
}
.reserved--light code { background: color-mix(in srgb, var(--clay) 9%, transparent); color: var(--clay); }

/* ============================================================
   STUDIO DELIVERY LOOP
   Three completed interiors share one frame, matching the team-led delivery
   story without putting one person at the centre of the section.
   ============================================================ */
.studio-grid {
  display: grid;
  grid-template-columns: minmax(0, .82fr) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 76px);
  align-items: center;
}
.studio-media-loop {
  position: relative;
  overflow: hidden;
  border-radius: 8px;
  aspect-ratio: 4 / 5;
  background: var(--paper-warm);
}
.studio-media-loop img {
  position:absolute;
  inset:0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity:0;
  transform:scale(1.04);
  animation:studio-frame 15s var(--ease-soft) infinite;
}
.studio-media-loop img:nth-child(2) { animation-delay:5s; }
.studio-media-loop img:nth-child(3) { animation-delay:10s; }
@keyframes studio-frame {
  0%, 27% { opacity:1; transform:scale(1); }
  33%, 100% { opacity:0; transform:scale(1.045); }
}
.studio-media-loop::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(200deg, rgba(217,195,154,.16), transparent 52%);
  pointer-events: none;
}
.studio-legacy-quote, .studio-legacy-copy, .studio-legacy-action { display:none; }
.studio-copy { max-width:50ch; }
.studio-copy .studio-lead { margin:0; color:var(--ink); font-size:clamp(24px, 2.5vw, 34px); font-weight:400; letter-spacing:-.035em; line-height:1.25; }
.studio-description { margin-top:20px; color:var(--ink-soft); font-size:16px; line-height:1.7; }
.studio-action { margin-top:28px; }
@media (max-width: 860px) {
  .studio-grid { grid-template-columns:1fr; gap:30px; }
  .studio-media-loop { max-width:620px; aspect-ratio:16 / 10; }
}
@media (max-width:560px) {
  .studio-section .section-title { max-width:15ch; margin-bottom:26px !important; }
  .studio-grid { gap:24px; }
  .studio-media-loop { width:100%; max-width:none; aspect-ratio:4 / 3; border-radius:6px; }
  .studio-copy .studio-lead { font-size:clamp(23px, 7vw, 29px); line-height:1.28; }
  .studio-description { margin-top:16px; font-size:15px; line-height:1.65; }
  .studio-action { margin-top:22px; }
  .studio-action .btn { width:100%; justify-content:space-between; }
}

/* ============================================================
   ENQUIRY FORM — FLOATING LABELS
   :placeholder-shown is what makes this work with no JavaScript at all: the
   label sits over an empty field and lifts the instant there is content or
   focus. The placeholder text stays in the markup as the fallback, hidden only
   while the label is down over it.
   ============================================================ */
/* Scoped with :has() to fields that are actually shaped for this — a label plus
   a single-line control. `.field` is used only by the two enquiry forms (home
   and contact), so this reaches both without touching anything else.

   The sibling combinator this originally used (`input:not(:placeholder-shown)
   + label`) was simply wrong: the markup puts the label BEFORE the input, so
   the selector matched nothing and the labels never floated. :has() reads the
   state off the field itself and does not care about source order. */
.field:has(> label):has(> input, > select) {
  position: relative;
}

/* Room INSIDE the control for the floated label to land in. Without this the
   label has to travel out of the box to get clear of the text, and lands on top
   of the field above it. */
.field:has(> label):has(> input, > select) > input,
.field:has(> label):has(> input, > select) > select {
  min-height: 50px;
  padding-top: 21px;
  padding-bottom: 5px;
}

.field:has(> label):has(> input, > select) > label {
  position: absolute;
  left: 17px;
  top: 15px;
  z-index: 1;
  margin: 0;
  pointer-events: none;              /* clicks must reach the input beneath */
  transform-origin: left top;
  color: var(--ink-soft);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0;
  white-space: nowrap;
  transition: transform .3s var(--ease-soft), color .3s ease;
}

/* Floated: focused, or holding a value. :placeholder-shown is what makes the
   filled state work with no JavaScript at all — every one of these inputs
   carries a placeholder, so the field knows whether it is empty on its own.
   <select> has no such state, hence .has-value, written by main.js. */
.field:has(> label):has(> input, > select):focus-within > label,
.field:has(> input:not(:placeholder-shown)) > label,
.field.has-value > label {
  transform: translate3d(0, -9px, 0) scale(.74);
  color: var(--clay);
}

/* The placeholder only appears once the label has moved off it, so the two are
   never legible at the same time. */
.field:has(> label) > input::placeholder { opacity: 0; transition: opacity .25s ease .1s; }
.field:has(> label) > input:focus::placeholder { opacity: .45; }

/* A <select> is never visually empty — it always renders an option, here
   "Select a service". So its label has nowhere to rest without colliding with
   that text, and is floated permanently rather than on interaction. This is
   also why the select needs no JavaScript state: there is no resting position
   to return to. */
.field:has(> label) > select ~ label,
.field:has(> select) > label {
  transform: translate3d(0, -9px, 0) scale(.74);
}
.field:has(> select):focus-within > label { color: var(--clay); }

.home-contact-form input:focus,
.home-contact-form select:focus,
.home-contact-form textarea:focus,
.field input:focus,
.field select:focus,
.field textarea:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--clay) 12%, transparent);
}

/* Submit affordance. The button is disabled visually but NOT with the disabled
   attribute — a disabled submit that fires before the POST completes is how a
   slow connection turns into a lead nobody ever sees. */
.btn.is-sending { opacity: .72; pointer-events: none; }
.btn.is-sending .arr { animation: send-arrow .7s var(--ease-soft) infinite; }
@keyframes send-arrow {
  0%   { transform: translateX(0);   opacity: 1; }
  55%  { transform: translateX(10px); opacity: 0; }
  56%  { transform: translateX(-10px); opacity: 0; }
  100% { transform: translateX(0);   opacity: 1; }
}

/* Submit success. The tick draws itself with a dash offset — no image, no
   sprite, and it scales to any size cleanly. */
.form-sent {
  display: grid;
  place-items: center;
  gap: 14px;
  padding: clamp(30px, 5vw, 56px);
  text-align: center;
}
.form-sent svg { width: 56px; height: 56px; color: var(--clay); }
.form-sent .tick {
  stroke-dasharray: 32;
  stroke-dashoffset: 32;
  animation: tick-draw .6s var(--ease-out) .18s forwards;
}
.form-sent .ring {
  stroke-dasharray: 132;
  stroke-dashoffset: 132;
  animation: tick-draw .8s var(--ease-out) forwards;
}
@keyframes tick-draw { to { stroke-dashoffset: 0; } }

/* ============================================================
   FOOTER — OVERSIZED BRANDING
   The wordmark is set at the full width of the container and clipped by the
   viewport edge, which is the one typographic gesture that reliably reads as
   "studio" rather than "business". It is aria-hidden: the accessible name of
   this site is already in the logo above it and in every page title, and a
   screen reader does not need to hear "Candidscape" a third time.
   ============================================================ */
.footer-wordmark {
  display: block;
  margin-top: clamp(42px, 6vw, 80px);
  font-family: 'Montserrat', sans-serif;
  font-weight: 300;
  font-size: clamp(50px, 12.5vw, 190px);
  line-height: .82;
  letter-spacing: -.045em;
  text-align: center;
  white-space: nowrap;
  color: transparent;
  -webkit-text-stroke: 1px rgba(255,255,255,.18);
  user-select: none;
  overflow: hidden;
}
/* Filled gradient sweeps across on entry, so the outline "lights up". */
.footer-wordmark span {
  display: inline-block;
  background: linear-gradient(100deg,
    rgba(255,255,255,0) 23%,
    rgba(255,255,255,.82) 41%,
    rgba(232,213,168,.92) 50%,
    rgba(255,255,255,.78) 59%,
    rgba(255,255,255,0) 77%) no-repeat;
  background-size: 230% 100%;
  background-position: 130% 0;
  -webkit-background-clip: text;
  background-clip: text;
  animation: footer-name-loop 10s linear infinite;
}
.footer-wordmark.is-lit span { background-position: -30% 0; }
@keyframes footer-name-loop { from { background-position: 120% 0; } to { background-position: -120% 0; } }

/* The floating WhatsApp button is fixed to the bottom-right and the GSTIN sits
   at the right end of the last footer row, so at the very bottom of the page —
   the one scroll position every visitor reaches — the button was sitting on top
   of the registration number. Reserve the corner it occupies. */
.footer-bottom { padding-right: 0; }
@media (min-width: 881px) {
  /* Keep the final footer row above the fixed Call / WhatsApp dock. */
  .footer-bottom { padding-right: 0; padding-bottom: 96px; }
}
@media (max-width: 720px) {
  /* The row is already stacked left-aligned below 640px, and the phone-only
     call/WhatsApp bar replaces the floating button, so no corner to reserve. */
  .footer-bottom { padding-right: 0; }
}

/* Footer links get a wipe underline rather than a colour change. */
.footer-col a { position: relative; }
.footer-col a::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 2px;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform .45s var(--ease-soft);
}
.footer-col a:hover::after,
.footer-col a:focus-visible::after { transform: scaleX(1); transform-origin: left center; }

/* ============================================================
   CURSOR — MORPHING
   The dot already existed as a "View" pill over media. It now has states: it
   grows over media, becomes a drag affordance over the horizontal gallery, and
   stretches along the axis of travel when the pointer moves fast.
   ============================================================ */
.cursor-dot { transition: opacity .3s, width .4s var(--ease-soft), height .4s var(--ease-soft), background .3s; }
.cursor-dot.is-drag::after { content: ''; }
.cursor-dot[data-label]::after { content: attr(data-label); }

/* ============================================================
   MARQUEE — VELOCITY REACTIVE
   --vel is the normalised scroll velocity written by main.js. The ribbon skews
   into the direction of travel and settles when scrolling stops, so it belongs
   to the page's movement instead of running at a constant rate beside it.
   ============================================================ */
.marquee-track {
  transform: skewX(calc(var(--vel, 0) * -7deg));
  transition: transform .5s var(--ease-soft);
}

/* ============================================================
   BLUR REVEAL
   A softer alternative to the existing clip-path wipe, used on the editorial
   and founder blocks. Blur is expensive to animate, so this is applied to a
   handful of elements deliberately and never to a grid of them.
   ============================================================ */
.js .blur-in {
  opacity: 0;
  filter: blur(14px);
  transform: translate3d(0, 22px, 0) scale(1.02);
  transition:
    opacity   .9s var(--ease-out),
    filter    1.1s var(--ease-out),
    transform 1.1s var(--ease-soft);
}
.js .blur-in.is-in { opacity: 1; filter: blur(0); transform: none; }

/* ============================================================
   SECTION EYEBROW RULE
   A gold hairline that draws itself beside every eyebrow as its section
   arrives. One rule, applied everywhere, which is what gives the page a
   consistent "grammar" from section to section.
   ============================================================ */
.eyebrow { position: relative; }
.eyebrow::after { display:none; }

/* ---------- Homepage rhythm ----------
   A single, quiet spacing scale keeps each portfolio section aligned to the
   next. The work section is intentionally tighter so its heading and first
   project read as one composition instead of two unrelated blocks. */
.page-home main > .section:not(.hscroll) { padding-block:clamp(48px, 5.5vw, 76px); }
.page-home main > .home-work:not(.hscroll) { padding-top:clamp(36px, 3.5vw, 52px); padding-bottom:clamp(44px, 4.5vw, 64px); }
.page-home main > .home-work .eyebrow { margin-bottom:12px; }
.page-home main > .home-work .section-title { margin-top:0; margin-bottom:clamp(22px, 2.2vw, 30px); }
.page-home main > .home-work .mosaic { align-items:stretch; }
@media (max-width:560px) {
  .page-home main > .section:not(.hscroll) { padding-block:42px; }
  .page-home main > .home-work:not(.hscroll) { padding-top:38px; padding-bottom:44px; }
  .page-home main > .home-work .section-title { margin-bottom:20px; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .wa-float { opacity: 1; transform: none; pointer-events: auto; transition: none; }
  .wa-float-ring { animation: none; opacity: 0; }
  .wa-float-label { transition: none; }

  .site-header, .site-header .nav, .site-header .brand img { transition: none; }
  .js body { animation: none; }
  .btn.is-magnetic { transform: none; transition: background-color .3s, color .3s, border-color .3s; }

  /* Hover cards still reveal â€” the detail is content, and withholding it would
     be a content decision, not a motion one. It just appears instantly, with no
     slide, no scale and no drawn underline. */
  .industry-card-media img, .proj-card-media img, .svc-band .svc-card-media img { transition: none; }
  .industry-card:hover .industry-card-media img,
  .proj-card:hover .proj-card-media img,
  .svc-band .svc-card:hover .svc-card-media img { transform: none; }
  .industry-card::before, .proj-card::before, .svc-band .svc-card::before,
  .industry-card-body, .proj-card-body, .svc-band .svc-card-content,
  .industry-card h3, .proj-card h3, .svc-band .svc-card h3,
  .industry-card p, .proj-card p, .svc-band .svc-card p,
  .industry-card::after, .proj-card::after, .svc-band .svc-card::after { transition: none; }
  .industry-card h3, .proj-card h3, .svc-band .svc-card h3,
  .industry-card p, .proj-card p, .svc-band .svc-card p { transform: none; }

  .svc-grid .svc-card-media img, .svc-grid .svc-card-link:has(.svc-card-media)::before,
  .svc-grid .svc-card-body, .svc-grid .svc-card-title,
  .svc-grid .svc-card-copy, .svc-grid .svc-card-link:has(.svc-card-media)::after { transition: none; }
  .svc-grid .svc-card-link:has(.svc-card-media):hover .svc-card-media img { transform: none; }
  .svc-grid .svc-card-title, .svc-grid .svc-card-link:has(.svc-card-media) .svc-card-copy { transform: none; }

  /* Images are simply there â€” never clipped, never waiting on a transition. */
  .js .wipe, .js .wipe.is-wiped { clip-path: none; transition: none; }
  /* Nobody who has asked for less motion should be made to wait for any of it.
     Zeroing the two knobs here covers every consumer at once — the CSS calcs and
     the JS, which reads these same properties at reveal time. */
  :root { --load-delay: 0ms; --hold-min: 0ms; }

  /* main.js never adds these two under reduced motion. Neutralised here as well
     so a setting changed after load cannot leave a shimmer running or a line
     stranded below its mask. */
  .js .wipe.is-held { filter: none; transform: none; background-image: none; animation: none; }
  .js .line-head .lnw { clip-path: none; }
  .js .line-head .ln { transform: none; transition: none; }
  .js .chips.is-staggered li { opacity: 1; transform: none; animation: none; }
  .chips li { transition: none; }
  .scroll-progress { display: none; }

  .band-noir::after { animation: none; }

  /* The hero holds still. Every layer that answered the pointer or breathed on
     a timer is pinned to its resting state. */
  .hero-slide.is-active .hero-bg { animation: none; transform: none; }/* Inner-page photographs hold still too. The scale is kept so the framing
     matches the animated state and nothing shifts if the preference changes. */
  .hero-cine, .hero .hero-content, .hero .hero-feature { transform: none; transition: none; }
  .hero-bloom, .hero-motes { display: none; }
  .hero-cue .hero-cue-rail::after { animation: none; transform: none; opacity: .5; }
  .hero-tag::after { transform: scaleX(1); transition: none; }

  /* Split headline: words present, masks released, no travel. This also covers
     the case where main.js split the text before the media query was consulted
     — the words must never be left at opacity 0 waiting on a suppressed
     transition, which would blank the H1 outright. */
  .is-split .wi { transform: none; opacity: 1; transition: none; }
  .is-split .w { overflow: visible; }

  /* Menu opens as a plain panel. clip-path here is a reveal, not a decoration,
     so it is set open rather than animated to open. */
  .nav-links { transition: opacity .001s; }
  .nav-links.open { clip-path: none; }
  .nav-links > a, .nav-links > .nav-services, .nav-links > .nav-social {
    opacity: 1; transform: none; transition: none;
  }

  .stats-grid.is-lit .stat-cell::before { animation: none; opacity: 0; }

  /* The horizontal gallery reverts to what the markup already is: a native
     scroller. main.js never pins under reduced motion, so .is-pinned should not
     exist here — this is belt-and-braces against one left over from a resize. */
  .hscroll.is-pinned .hscroll-viewport { overflow-x: auto; scroll-snap-type: x mandatory; }
  .hcard img { transform: scale(1.02); transition: none; }
  .hcard-body p { opacity: 1; transform: none; transition: none; }

  .tilt, .tilt.is-tilting { transform: none; transition: none; box-shadow: none; }
  .tilt-sheen { display: none; }

  /* The comparison slider keeps working — it is a control, not an effect.
     Only its easing goes. */
  .ba-knob, .ba:hover .ba-knob { transition: none; transform: translate(-50%, -50%); }

  .studio-media-loop img { animation:none; opacity:0; transform:scale(1.02); }
  .studio-media-loop img:first-child { opacity:1; }

  .field:has(> label):has(> input, > select) > label { transition: none; }
  .btn.is-sending .arr { animation: none; }
  .form-sent .tick, .form-sent .ring { animation: none; stroke-dashoffset: 0; }

  .footer-wordmark span { animation: none; background-position: -30% 0; }
  .site-footer::before { animation: none; }
  .footer-col a::after { transition: none; }

  .marquee-track { transform: none; transition: none; }
  .cursor-dot { transition: none; }

  .js .blur-in { opacity: 1; filter: none; transform: none; transition: none; }
  .eyebrow::after { transform: scaleX(1); transition: none; }
}

/* ============================================================
   COMPACT RESPONSIVE SYSTEM — 2026-08
   A single final calibration layer for the existing components. It uses the
   shared tokens above and reduces page length without removing semantic copy.
   ============================================================ */
body { font-size:var(--text-base); line-height:1.62; }
.section { padding-block:var(--section-space); }
.section > .wrap > .section-title { margin-bottom:clamp(24px, 3vw, 36px); }
.page-hero { padding-block:clamp(52px, 6vw, 76px) clamp(38px, 4vw, 56px); }
.page-hero h1 { max-width:20ch; font-size:clamp(38px, 4.5vw, 60px); line-height:1.04; }
.page-hero p { max-width:62ch; font-size:clamp(14px, 1.15vw, 16px); line-height:1.62; }
.btn { min-height:44px; }
.field { margin-bottom:16px; }
.field input,
.field select { height:48px; min-height:48px; padding:10px 14px; }
.field textarea { min-height:108px; padding:12px 14px; }
.form-card { padding:clamp(24px, 3vw, 34px); }
.form-card .hint { margin-bottom:18px; }

.site-header .nav { height:68px; }
.site-header.is-stuck .nav { height:68px; }
.site-header.is-stuck .brand img { height:auto; }
.res-copy .section-title { font-size:var(--heading-md); }

/* Shared footer: same information, substantially less travel. */
.site-footer { padding-block:clamp(52px, 5vw, 72px) 24px; }
.footer-grid { gap:clamp(24px, 3.5vw, 48px); padding-bottom:32px; }
.footer-brand { margin-bottom:8px; }
.footer-col h3 { margin-bottom:10px; }
.footer-col a { min-height:38px; font-size:13px; }
.footer-col span { font-size:13px; }
.footer-social { padding-block:24px; }
.footer-bottom { padding-top:16px; font-size:11px; }

/* Homepage: keep the sequence immersive, but let the next section enter view. */
.page-home .hero {
  min-height:min(88svh, 780px);
  padding-block:clamp(54px, 7vh, 82px) clamp(26px, 4vh, 40px);
}
.page-home .hero h1 { font-size:clamp(40px, 4.5vw, 62px); }
.page-home .home-system__intro .section-title { font-size:clamp(34px, 3.8vw, 50px); }
.home-system__lede { margin-top:16px; font-size:var(--text-base); line-height:1.62; }
.home-system__intro .btn { margin-top:20px; }
.home-system__image { min-height:clamp(320px, 40vw, 520px); }
.home-system__steps li { min-height:66px; }
.home-system__steps strong { font-size:clamp(17px, 1.45vw, 21px); }
.hscroll[data-autoplay="true"] .hcard { flex:0 0 clamp(260px, 30vw, 380px); }
.service-showcase-grid { grid-auto-rows:clamp(96px, 8.5vw, 126px); }
.home-work { padding-bottom:var(--section-space-small); }
.home-work-lede { font-size:var(--text-base); line-height:1.62; }
.home-enquiry-intro { margin-bottom:24px; }
.home-contact-card { padding:clamp(22px, 2.5vw, 30px); }
.page-faq-list summary { min-height:60px; }
.page-faq-list p { font-size:14px; line-height:1.62; }
.cta { padding-block:var(--section-space-small); }
.cta h2 { max-width:20ch; font-size:clamp(28px, 3.5vw, 42px); }
.cta p { margin-bottom:22px; font-size:var(--text-base); }

/* Testimonials: one editorial review viewport, without an unsupported score. */
.testimonial-section { padding-block:clamp(60px, 6vw, 80px); }
.testimonial-head { margin-bottom:clamp(26px, 3vw, 38px); }
.testimonial-head .section-title { max-width:16ch; font-size:clamp(30px, 3.5vw, 44px); }
.testimonial-head__copy { font-size:var(--text-base); line-height:1.62; }
.testimonial-stage .testimonial-card {
  min-height:clamp(390px, 38vw, 470px);
  padding:clamp(28px, 3.4vw, 44px) min(43%, 520px) clamp(28px, 3.4vw, 44px) clamp(28px, 4vw, 52px);
}
.testimonial-stage .testimonial-card__image { width:38%; }
.testimonial-card__number { top:26px; right:28px; font-size:clamp(36px, 4vw, 54px); }
.testimonial-card__identity { margin-top:22px; }
.testimonial-stage .testimonial-card__avatar { flex-basis:46px; width:46px; height:46px; }
.testimonial-card__source {
  position:relative;
  z-index:2;
  display:flex;
  align-items:center;
  gap:8px;
  margin-top:16px;
  color:#7c6338;
  font-size:10px;
  font-weight:700;
  letter-spacing:.11em;
  text-transform:uppercase;
}
.testimonial-card__source small { color:#777383; font-size:9px; font-weight:600; }
.testimonial-card__source small::before { content:'·'; margin-right:8px; }
.testimonial-stage .testimonial-card blockquote {
  max-width:38ch;
  padding-block:clamp(18px, 2.2vw, 28px);
  font-size:clamp(20px, 2vw, 28px);
  line-height:1.38;
}
.testimonial-quote details { display:inline; }
.testimonial-quote details > summary { display:none; }
.testimonial-quote details > .testimonial-quote__more { display:inline; }
.testimonial-stage .testimonial-card__source { opacity:.15; transform:translateY(18px); transition:opacity .65s var(--ease), transform .75s var(--ease); }
.testimonial-stage .testimonial-card.is-active .testimonial-card__source { opacity:1; transform:none; transition-delay:.12s; }
.testimonial-controls { margin-top:14px; }
.testimonial-chapters { margin-top:12px; }

/* About: shorter desktop beats and a purpose-built swipe story below 880px. */
.sticky-story .ss-beat { min-height:50svh; }
.clients-band .client .nm { font-size:clamp(16px, 1.6vw, 20px); }

/* Services hub: landscape cards instead of nine tall portrait posters. */
.services-hub .svc-grid {
  grid-template-columns:repeat(3, minmax(0, 1fr));
  gap:14px;
  margin-top:28px;
}
.services-hub .svc-grid .svc-card-link:has(.svc-card-media) { aspect-ratio:16 / 10; }
.services-hub .svc-grid .svc-card-link:has(.svc-card-media)::before { opacity:.9; }
.services-hub .svc-grid .svc-card-link:has(.svc-card-media) .svc-card-body { opacity:1; padding:18px; }
.services-hub .svc-grid .svc-card-link:has(.svc-card-media) .svc-card-title { font-size:clamp(17px, 1.4vw, 21px); transform:none; }
.services-hub .svc-grid .svc-card-link:has(.svc-card-media) .svc-card-copy { -webkit-line-clamp:2; font-size:12px; transform:none; }
.services-hub .project-grid { grid-template-columns:repeat(3, minmax(0, 1fr)); gap:16px; }
.services-hub .project-card img { aspect-ratio:16 / 10; }
.services-hub .project-card h3 { margin-top:13px; font-size:var(--heading-sm); }
.services-hub .project-card > p:not(.svc-gallery-meta):not(.svc-gallery-link) {
  display:-webkit-box;
  -webkit-box-orient:vertical;
  -webkit-line-clamp:2;
  overflow:hidden;
  font-size:13px;
}
/* Shared service details: uniform work grids and compact disclosure bands. */
.service-template-page .service-band,
.service-template-page .dark-band { padding-block:var(--section-space-small); }
.service-template-page .svc-lead { font-size:var(--text-base); line-height:1.62; }
.service-template-page .svc-item summary { padding-block:15px; }
.service-template-page .mosaic {
  grid-template-columns:repeat(3, minmax(0, 1fr));
  gap:12px;
}
.service-template-page .mosaic > * {
  grid-column:span 1 !important;
  aspect-ratio:4 / 3 !important;
}
.service-template-page .proj-card-body { padding:16px; }
.service-template-page .proj-card h3 { font-size:18px; }
.service-template-page .proj-card p { font-size:12px; line-height:1.5; }
.cta-panel { padding:var(--section-space-small) var(--page-padding); }
.cta-panel h2 { font-size:clamp(28px, 3.5vw, 42px); }/* Full gallery: curated first six; remaining real work stays in disclosure. */
.gallery-item.gallery-item,
.gallery-item--lead.gallery-item--lead { grid-column:span 1; aspect-ratio:4 / 3; }
.gallery-grid--more { margin-top:10px; }

@media (max-width:900px) {
  .site-header .nav { height:62px; }
  .site-header .brand img { height:36px; }
  .nav-links {
    inset:62px 0 calc(48px + env(safe-area-inset-bottom, 0px));
    min-height:calc(100dvh - 110px - env(safe-area-inset-bottom, 0px));
    padding-top:14px;
  }
  .contact-dock a { min-height:48px; font-size:13px; }
  .site-footer { padding-bottom:calc(20px + 48px + env(safe-area-inset-bottom, 0px)); }
  /* Let the mobile hero end with its content. A viewport-height minimum left
     220–280px of empty photograph below the CTAs on common phone screens. */
  .page-home .hero {
    min-height:auto;
    padding-block:clamp(42px, 6vw, 54px) clamp(32px, 5vw, 42px);
  }
  .page-home .hero h1 { font-size:clamp(34px, 6.5vw, 46px); }
  .home-system__image { min-height:320px; }
  .sticky-story .ss-grid { gap:24px; }
  .sticky-story .ss-beats {
    display:flex;
    gap:14px;
    overflow-x:auto;
    scroll-snap-type:x mandatory;
    padding:0 var(--page-padding) 10px;
    margin-inline:calc(var(--page-padding) * -1);
    scrollbar-width:none;
  }
  .sticky-story .ss-beats::-webkit-scrollbar { display:none; }
  .sticky-story .ss-beat {
    flex:0 0 min(76vw, 330px);
    min-height:0;
    margin:0;
    padding:0 0 18px;
    border-bottom:1px solid var(--line);
    scroll-snap-align:start;
  }
  .sticky-story .ss-beat-img { aspect-ratio:16 / 10; margin-bottom:16px; }
  .sticky-story .ss-beat h3 { font-size:clamp(21px, 4vw, 28px); }
  .sticky-story .ss-beat p { margin-top:10px; font-size:14px; line-height:1.58; }
  .services-hub .svc-grid { grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .services-hub .project-grid,
  .service-template-page .mosaic {
    display:flex;
    gap:12px;
    overflow-x:auto;
    scroll-snap-type:x mandatory;
    padding-bottom:10px;
    scrollbar-width:none;
  }
  .services-hub .project-grid::-webkit-scrollbar,
  .service-template-page .mosaic::-webkit-scrollbar { display:none; }
  .services-hub .project-card,
  .service-template-page .mosaic > * {
    flex:0 0 min(72vw, 320px);
    scroll-snap-align:start;
  }
}

@media (max-width:640px) {
  :root { --page-padding:20px; --section-space:56px; --section-space-small:44px; }
  .section-title { font-size:clamp(26px, 8vw, 32px); }
  .page-hero { padding-block:42px 34px; }
  .page-hero h1 { font-size:clamp(32px, 10vw, 40px); }
  .page-hero p { margin-top:14px; font-size:14px; }
  .service-template-page .section { padding-block:56px; }
  .form-card { padding:22px 18px; }
  .field input,
  .field select { height:48px; min-height:48px; }
  .form-actions { gap:8px; }

  body .site-footer { padding-top:32px; padding-bottom:calc(20px + 48px + env(safe-area-inset-bottom, 0px)); }
  .footer-grid {
    grid-template-columns:repeat(2, minmax(0, 1fr));
    gap:0 18px;
    padding-bottom:20px;
  }
  .site-footer .footer-grid > * { padding-block:16px; border-top:0; }
  .footer-grid > :nth-child(1) { grid-column:1 / -1; grid-row:1; }
  .footer-grid > :nth-child(2) { grid-column:1; grid-row:2; }
  .footer-grid > :nth-child(3) { grid-column:1 / -1; grid-row:3; border-top:1px solid rgba(255,255,255,.1); }
  .footer-grid > :nth-child(4) { grid-column:2; grid-row:2; }
  .footer-brand img { height:50px; }
  .footer-brand p { margin-top:8px; font-size:12px; }
  .footer-col h3 { font-size:10px; }
  .footer-col a { min-height:36px; font-size:12px; line-height:1.35; }
  .footer-col span { font-size:11px; line-height:1.45; }
  .footer-grid > .footer-col:last-child a { margin-top:4px; padding-inline:8px; }
  .footer-services { grid-template-columns:repeat(2, minmax(0, 1fr)); column-gap:16px; }
  .footer-services a { font-size:11.5px; }
  .footer-social { flex-direction:row; flex-wrap:nowrap; align-items:center; gap:10px; padding-block:18px; }
  .footer-social-copy { flex:1 1 auto; min-width:0; }
  .footer-social-copy h3 { margin-bottom:4px; font-size:10px; letter-spacing:.17em; }
  .footer-social-copy p { display:block; margin-top:0; font-size:11px; line-height:1.35; }
  .footer-social .social-links { flex:0 0 auto; width:auto; margin-left:auto; gap:4px; }
  .footer-social .social-link { width:40px; height:40px; }
  .footer-bottom { padding-top:12px; }

  .page-home .hero { min-height:auto; padding-block:40px 34px; }
  .page-home .hero h1 { font-size:clamp(32px, 9.6vw, 38px); }
  .page-home .hero-lead { font-size:14px; line-height:1.55; }
  .page-home .hero-actions .btn { min-height:44px; font-size:11px; }
  .page-home .home-system__intro .section-title { font-size:clamp(29px, 8.5vw, 36px); }
  .home-system__image { min-height:280px; }
  .home-system__steps { margin-top:-50px; }
  .home-system__steps li { min-height:58px; }
  .hscroll[data-autoplay="true"] .hcard { flex-basis:72vw; }
  .service-showcase-grid { gap:8px; }
  .service-showcase-card--residential { min-height:220px; }
  .service-showcase-card--villa,
  .service-showcase-card--healthcare,
  .service-showcase-card--commercial { min-height:176px; }
  .page-home .home-work .mosaic { grid-template-columns:repeat(2, minmax(0, 1fr)); gap:8px; }
  .page-home .mosaic > * { grid-column:span 1 !important; aspect-ratio:4 / 5 !important; }
  .page-home .proj-card-body { padding:12px; }
  .page-home .proj-card h3 { font-size:14px; line-height:1.25; }
  .page-home .proj-card p { display:none; }

  .testimonial-section { padding-block:40px; }
  .testimonial-head { gap:12px; margin-bottom:22px; }
  .testimonial-head .section-title { font-size:clamp(26px, 8vw, 32px); }
  .testimonial-head__copy { display:none; }
  .testimonial-stage .testimonial-card { padding:0 22px 28px; }
  .testimonial-stage .testimonial-card__image {
    width:calc(100% + 44px);
    height:110px;
    margin-inline:-22px;
  }
  .testimonial-card__number { top:18px; right:18px; font-size:38px; }
  .testimonial-stage .testimonial-card__meta { margin-top:18px; padding-bottom:14px; }
  .testimonial-card__identity { margin-top:16px; }
  .testimonial-stage .testimonial-card__avatar { flex-basis:42px; width:42px; height:42px; }
  .testimonial-card__source { margin-top:12px; }
  .testimonial-stage .testimonial-card blockquote { padding-block:14px; font-size:clamp(17px, 5vw, 19px); line-height:1.42; }
  .testimonial-quote details { display:block; margin-top:10px; }
  .testimonial-quote details > summary {
    display:inline-flex;
    min-height:32px;
    align-items:center;
    color:#7c6338;
    cursor:pointer;
    font:700 9px/1 'Montserrat', sans-serif;
    letter-spacing:.11em;
    text-transform:uppercase;
  }
  .testimonial-quote details > .testimonial-quote__more { display:none; }
  .testimonial-quote details[open] > .testimonial-quote__more { display:inline; }
  .testimonial-stage .testimonial-card figcaption { font-size:8px; }
  .testimonial-controls { grid-template-columns:44px minmax(50px, 1fr) auto 44px; }
  .testimonial-chapters { display:none; }
  .clients-band .client .nm { font-size:14px; }
  .clients-band .client .ty { font-size:9px; white-space:normal; }

  .services-hub .svc-grid { grid-template-columns:1fr; gap:10px; }
  .services-hub .svc-grid .svc-card-link:has(.svc-card-media) {
    display:grid;
    grid-template-columns:112px minmax(0, 1fr);
    min-height:126px;
    aspect-ratio:auto;
    background:var(--white);
  }
  .services-hub .svc-grid .svc-card-media { position:relative; inset:auto; }
  .services-hub .svc-grid .svc-card-link:has(.svc-card-media)::before,
  .services-hub .svc-grid .svc-card-link:has(.svc-card-media)::after { display:none; }
  .services-hub .svc-grid .svc-card-link:has(.svc-card-media) .svc-card-body {
    position:relative;
    inset:auto;
    justify-content:center;
    padding:14px;
  }
  .services-hub .svc-grid .svc-card-link:has(.svc-card-media) .svc-card-title { margin:0; color:var(--ink); font-size:17px; }
  .services-hub .svc-grid .svc-card-link:has(.svc-card-media) .svc-card-copy { margin-top:6px; color:var(--ink-soft); font-size:11.5px; }
  .services-hub .svc-card-cta { padding-top:8px; margin-top:0; color:var(--clay); font-size:9px; }
  .services-hub .project-card,
  .service-template-page .mosaic > * { flex-basis:82vw; }
  .service-template-page .proj-card p { display:none; }
  .cta-panel h2 { font-size:clamp(26px, 8vw, 32px); }
  .gallery-item.gallery-item,
  .gallery-item--lead.gallery-item--lead { grid-column:span 1; aspect-ratio:4 / 3; }
}

@media (prefers-reduced-motion:reduce) {
  .testimonial-stage .testimonial-card__source,
  .gallery-more > summary span { transition:none; }
}

/* ========================================================================== 
   Mobile interaction polish

   This final layer is intentionally small and shared. It adds tactile behavior
   to the existing layouts without introducing a second animation system or
   taking control of native scrolling.
   ========================================================================== */

/* The hero accepts horizontal project swipes while the browser retains the
   vertical page gesture. Active slides alone receive compositor promotion. */
.hero,
.hero-cine {
  touch-action:pan-y;
}
.hero-cine {
  user-select:none;
  -webkit-user-select:none;
}
.hero-slide { backface-visibility:hidden; }
.hero-slide.is-active { will-change:opacity; }

@media (max-width:900px) {
  /* The drawer arrives as one surface, then its choices settle in quickly.
     Delays stay below 180ms so the menu feels responsive, not theatrical. */
  .nav-links > .mobile-menu-intro,
  .nav-links > a,
  .nav-links > .nav-services {
    opacity:0;
    transform:translateY(12px);
    transition:opacity .3s ease, transform .42s var(--ease-soft);
  }
  .nav-links.open > .mobile-menu-intro,
  .nav-links.open > a,
  .nav-links.open > .nav-services { opacity:1; transform:none; }
  .nav-links.open > :nth-child(1) { transition-delay:.04s; }
  .nav-links.open > :nth-child(2) { transition-delay:.07s; }
  .nav-links.open > :nth-child(3) { transition-delay:.10s; }
  .nav-links.open > :nth-child(4) { transition-delay:.13s; }
  .nav-links.open > :nth-child(5) { transition-delay:.16s; }
  .nav-links.open > :nth-child(n+6) { transition-delay:.18s; }

  /* Native, momentum-driven rails on touch screens. */
  .sticky-story .ss-beats,
  .services-hub .project-grid,
  .service-template-page .mosaic,
  .hscroll-viewport {
    -webkit-overflow-scrolling:touch;
    scroll-behavior:smooth;
    scroll-padding-inline:var(--page-padding);
  }
}

@media (hover:none), (pointer:coarse) {
  .btn,
  .hero-arrow,
  .menu-toggle,
  .service-showcase-card,
  .industry-card,
  .proj-card { -webkit-tap-highlight-color:transparent; }

  .btn:active,
  .hero-arrow:active,
  .menu-toggle:active { transform:scale(.975); }
}

/* 320–390px devices need controls to use the full measure; two half-width hero
   actions become difficult to scan and leave too little room for their labels. */
@media (max-width:390px) {
  :root { --page-padding:16px; }
  .page-home .hero { min-height:auto; padding-block:34px 30px; }
  .page-home .hero-actions { grid-template-columns:1fr; }
  .page-home .hero-actions .btn { width:100%; }
  .page-home .hero-controls { grid-template-columns:40px minmax(0, 1fr) 40px; }
  .page-home .hero-arrow { width:40px; height:40px; }
  .page-home .hero-dot { min-width:14px; }
  .footer-services { grid-template-columns:1fr; }
}

/* ---------- Homepage process: visual-first five-stage story ---------- */
.page-home .home-system {
  padding-block:clamp(46px, 5vw, 68px);
  overflow:clip;
}
.page-home .home-system__grid {
  display:grid;
  grid-template-columns:1fr;
  gap:clamp(18px, 2.4vw, 28px);
}
.page-home .home-system__intro {
  position:relative;
  top:auto;
  max-width:900px;
  padding:0;
}
.page-home .home-system__intro .eyebrow { margin-bottom:10px; }
.page-home .home-system__intro .section-title {
  max-width:18ch;
  font-size:clamp(34px, 3.8vw, 52px);
  line-height:1.04;
  text-wrap:balance;
}
.page-home .home-system__lede {
  margin-top:9px;
  color:var(--ink-soft);
  font-size:13px;
  font-weight:600;
  letter-spacing:.08em;
  line-height:1.5;
  text-transform:uppercase;
}

.home-process-scroll {
  position:relative;
  height:clamp(1500px, 200svh, 1950px);
}
.home-process {
  --process-progress:.2;
  position:sticky;
  top:clamp(76px, 10vh, 96px);
  display:grid;
  grid-template-columns:minmax(0, 1fr) minmax(230px, 30%);
  height:min(660px, calc(100svh - 116px));
  min-width:0;
  overflow:hidden;
  border-radius:4px;
  background:var(--ink);
  box-shadow:0 28px 72px rgba(20,19,42,.16);
}
.home-process__media {
  position:relative;
  min-width:0;
  height:100%;
  overflow:hidden;
  background:#d8d1c5;
  touch-action:pan-y;
}
.home-process__slide {
  position:absolute;
  inset:0;
  margin:0;
  opacity:0;
  visibility:hidden;
  transform:scale(1.025);
  transition:opacity .72s var(--ease-soft), transform 1.15s var(--ease-soft), visibility .72s;
}
.home-process__slide::after {
  content:'';
  position:absolute;
  inset:0;
  background:linear-gradient(180deg, rgba(9,8,30,.03) 45%, rgba(9,8,30,.38) 100%);
  pointer-events:none;
}
.home-process__slide.is-active {
  z-index:1;
  opacity:1;
  visibility:visible;
  transform:scale(1);
}
.home-process__slide picture,
.home-process__slide img { display:block; width:100%; height:100%; }
.home-process__slide img { object-fit:cover; object-position:center; }
.home-process__count {
  position:absolute;
  top:18px;
  left:18px;
  z-index:3;
  display:grid;
  grid-template-columns:auto 34px auto;
  align-items:center;
  gap:8px;
  min-width:102px;
  padding:9px 11px;
  border:1px solid rgba(255,255,255,.24);
  border-radius:999px;
  background:rgba(8,7,34,.54);
  backdrop-filter:blur(10px);
  color:var(--white);
  font-size:9px;
  font-weight:700;
  letter-spacing:.14em;
}
.home-process__count i { height:1px; background:rgba(255,255,255,.42); }
.home-process__count { display:none; }

.home-process__nav {
  position:relative;
  z-index:2;
  display:grid;
  grid-template-rows:repeat(5, minmax(0, 1fr));
  margin:0;
  padding:0;
  color:var(--white);
  list-style:none;
}
.home-process__nav::before {
  content:'';
  position:absolute;
  top:0;
  bottom:0;
  left:0;
  width:2px;
  background:linear-gradient(to bottom, var(--gold) calc(var(--process-progress) * 100%), rgba(255,255,255,.12) 0);
  transition:background .45s var(--ease);
}
.home-process__nav li { min-height:0; opacity:.42; transition:opacity .38s var(--ease), background-color .38s var(--ease); }
.home-process__nav li + li { border-top:1px solid rgba(255,255,255,.1); }
.home-process__nav li.is-active { opacity:1; background:rgba(255,255,255,.075); }
@media (hover:hover) { .home-process__nav li:hover { opacity:.82; background:rgba(255,255,255,.045); } }
.home-process__nav button {
  display:grid;
  grid-template-columns:38px minmax(0, 1fr);
  align-items:center;
  width:100%;
  height:100%;
  min-height:82px;
  padding:14px clamp(15px, 2vw, 24px);
  border:0;
  background:transparent;
  color:inherit;
  cursor:pointer;
  text-align:left;
}
.home-process__nav button > span:first-child {
  color:var(--gold-lit);
  font-size:9px;
  font-weight:700;
  letter-spacing:.14em;
}
.home-process__step-copy { display:grid; gap:5px; }
.home-process__step-copy strong {
  color:var(--white);
  font:400 clamp(20px, 2vw, 28px)/1 'Fraunces', Georgia, serif;
  letter-spacing:-.025em;
}
.home-process__step-copy small { color:rgba(255,255,255,.68); font-size:10px; line-height:1.35; }
.home-process__nav button:focus-visible { outline:2px solid var(--gold); outline-offset:-4px; }
.home-process__mobile-controls { display:none; }

@media (max-width:900px) and (min-width:761px) {
  .home-process { grid-template-columns:minmax(0, 1fr) 250px; }
  .home-process__media { height:100%; }
  .home-process__nav button { min-height:72px; padding-inline:14px; }
  .home-process__step-copy strong { font-size:20px; }
}

@media (max-width:760px) {
  .page-home .home-system { padding-block:34px 40px; }
  .page-home .home-system::before {
    top:8px;
    font-size:clamp(34px, 10vw, 72px);
    opacity:.65;
  }
  .page-home .home-system__grid { gap:16px; }
  .page-home .home-system__intro .eyebrow { margin-bottom:9px; }
  .page-home .home-system__intro .section-title {
    max-width:19ch;
    font-size:clamp(28px, 7.3vw, 34px);
    line-height:1.06;
  }
  .page-home .home-system__lede { margin-top:8px; font-size:9px; }

  .home-process-scroll { height:auto; min-height:0; }
  .home-process {
    position:relative;
    top:auto;
    display:block;
    height:auto;
    overflow:visible;
    border-radius:3px;
    background:transparent;
    box-shadow:0 20px 52px rgba(20,19,42,.15);
  }
  .home-process__media { height:auto; aspect-ratio:4 / 3; border-radius:3px; }
  .home-process__slide { transition-duration:.58s, .9s, .58s; }
  .home-process__slide::after {
    background:linear-gradient(180deg, rgba(9,8,30,.02) 35%, rgba(9,8,30,.64) 100%);
  }
  .home-process__count { top:12px; left:12px; }

  .home-process__nav {
    position:absolute;
    right:12px;
    bottom:12px;
    left:12px;
    z-index:4;
    display:block;
    height:74px;
    overflow:hidden;
    border:1px solid rgba(255,255,255,.18);
    border-radius:3px;
    background:rgba(8,7,34,.88);
    backdrop-filter:blur(12px);
  }
  .home-process__nav::before { display:none; }
  .home-process__nav li {
    position:absolute;
    inset:0;
    border:0 !important;
    opacity:0;
    visibility:hidden;
    transform:translateY(8px);
    transition:opacity .35s var(--ease), transform .42s var(--ease), visibility .35s;
  }
  .home-process__nav li.is-active {
    opacity:1;
    visibility:visible;
    transform:none;
    background:transparent;
  }
  .home-process__nav button {
    grid-template-columns:34px minmax(0, 1fr);
    min-height:74px;
    padding:10px 112px 10px 14px;
    pointer-events:none;
  }
  .home-process__step-copy { gap:3px; }
  .home-process__step-copy strong { font-size:22px; }
  .home-process__step-copy small { font-size:9px; }

  .home-process__mobile-controls {
    position:absolute;
    right:23px;
    bottom:29px;
    z-index:6;
    display:grid;
    grid-template-columns:32px auto 32px;
    align-items:center;
    gap:5px;
  }
  .home-process__mobile-controls > button {
    display:grid;
    place-items:center;
    width:32px;
    height:32px;
    border:1px solid rgba(255,255,255,.25);
    border-radius:50%;
    background:rgba(255,255,255,.06);
    color:var(--white);
    cursor:pointer;
  }
  .home-process__dots { display:flex; gap:4px; }
  .home-process__dots button {
    position:relative;
    width:12px;
    height:32px;
    padding:0;
    border:0;
    background:transparent;
    cursor:pointer;
  }
  .home-process__dots button::before,
  .home-process__dots button::after {
    content:'';
    position:absolute;
    top:15px;
    left:2px;
    width:8px;
    height:2px;
    background:rgba(255,255,255,.3);
  }
  .home-process__dots button::after {
    background:var(--gold-lit);
    transform:scaleX(0);
    transform-origin:left;
  }
  .home-process__dots button.is-active::before { background:rgba(255,255,255,.55); }
  .home-process.is-playing .home-process__dots button.is-active::after {
    animation:home-process-dot 4.3s linear forwards;
  }
  @keyframes home-process-dot { to { transform:scaleX(1); } }
}

@media (max-width:390px) {
  .page-home .home-system { padding-block:30px 36px; }
  .page-home .home-system__intro .section-title { font-size:clamp(27px, 8.7vw, 32px); }
  .home-process__media { aspect-ratio:1 / 1; }
  .home-process__nav button { padding-right:96px; }
  .home-process__mobile-controls { right:18px; }
  .home-process__dots { display:none; }
}

/* ---------- Minimal heading and spacing calibration ---------- */
.eyebrow { margin-bottom:10px; font-size:10px; }
.section-title {
  max-width:22ch;
  font-size:clamp(27px, 3vw, 40px);
  line-height:1.07;
  text-wrap:balance;
}
.section > .wrap > .section-title { margin-bottom:clamp(18px, 2.2vw, 28px); }

.page-hero {
  padding-block:clamp(42px, 4.6vw, 60px) clamp(30px, 3.4vw, 44px);
}
.page-hero h1,
.gallery-hero h1 {
  max-width:20ch;
  font-size:clamp(32px, 3.8vw, 50px);
  line-height:1.05;
}
.page-home .hero h1 { font-size:clamp(36px, 4vw, 56px); }
.cta h2,
.cta-panel h2,
.testimonial-head .section-title,
.page-faq-intro .section-title {
  font-size:clamp(26px, 2.8vw, 38px);
  line-height:1.08;
}
.services-hub .section,
.service-template-page .section { padding-block:var(--section-space); }

@media (max-width:640px) {
  :root {
    --section-space:46px;
    --section-space-small:38px;
  }
  .section-title { font-size:clamp(24px, 6.8vw, 29px); line-height:1.1; }
  .eyebrow { margin-bottom:8px; font-size:9px; }
  .page-hero { padding-block:34px 28px; }
  .page-hero h1,
  .gallery-hero h1 { font-size:clamp(29px, 8.6vw, 36px); }
  .page-home .hero h1 { font-size:clamp(30px, 8.8vw, 36px); }
  .cta h2,
  .cta-panel h2,
  .testimonial-head .section-title,
  .page-faq-intro .section-title { font-size:clamp(24px, 6.8vw, 29px); }
  .services-hub .section,
  .service-template-page .section { padding-block:46px; }
}

/* ---------- Process film: distinctive editorial treatment ---------- */
.page-home .home-system::after {
  content:'';
  position:absolute;
  top:18%;
  right:-12%;
  width:clamp(260px, 40vw, 620px);
  aspect-ratio:1;
  border-radius:50%;
  background:radial-gradient(circle, rgba(217,195,154,.2), transparent 68%);
  pointer-events:none;
  animation:process-aura 9s ease-in-out infinite alternate;
}
@keyframes process-aura {
  from { opacity:.45; transform:translate3d(0, 0, 0) scale(.92); }
  to { opacity:.8; transform:translate3d(-4%, 5%, 0) scale(1.08); }
}

.home-process {
  grid-template-columns:minmax(250px, 28%) minmax(0, 1fr);
  overflow:visible;
  gap:0;
  border-radius:0;
  background:transparent;
  box-shadow:none;
}
.home-process__media {
  grid-column:2;
  grid-row:1;
  border-radius:10px;
  box-shadow:0 30px 80px rgba(20,19,42,.22);
}
.home-process__media::before,
.home-process__media::after {
  content:'';
  position:absolute;
  z-index:4;
  width:46px;
  height:46px;
  border-color:rgba(244,209,157,.88);
  pointer-events:none;
}
.home-process__media::before {
  top:14px;
  right:14px;
  border-top:1px solid;
  border-right:1px solid;
}
.home-process__media::after {
  bottom:14px;
  left:14px;
  border-bottom:1px solid;
  border-left:1px solid;
}
.home-process__slide {
  clip-path:inset(0 7% 0 0);
  filter:saturate(.88) contrast(.98);
  transform:scale(1.045);
  transition:opacity .5s var(--ease-soft), transform .8s var(--ease-soft), clip-path .68s var(--ease-soft), filter .6s ease, visibility .5s;
}
.home-process__slide.is-active {
  clip-path:inset(0);
  filter:saturate(1) contrast(1);
  transform:scale(1);
}
.home-process.is-changing .home-process__slide.is-active img {
  animation:process-image-drift 3.4s ease-out both;
}
@keyframes process-image-drift {
  from { transform:scale(1.035) translate3d(1%, 0, 0); }
  to { transform:scale(1.005) translate3d(0, 0, 0); }
}

.home-process__nav {
  grid-column:1;
  grid-row:1;
  z-index:5;
  margin-block:clamp(28px, 5vh, 54px);
  margin-right:-42px;
  overflow:hidden;
  border:1px solid rgba(255,255,255,.11);
  border-radius:8px 0 0 8px;
  background:linear-gradient(145deg, #11102e, #090823);
  box-shadow:-18px 24px 58px rgba(20,19,42,.22);
}
.home-process__nav::before { left:auto; right:0; width:3px; }
.home-process__nav li {
  position:relative;
  transform:translateX(0);
  transition:opacity .38s var(--ease), background-color .38s var(--ease), transform .45s var(--ease);
}
.home-process__nav li::after {
  content:'';
  position:absolute;
  top:50%;
  right:18px;
  width:18px;
  height:1px;
  background:var(--gold-lit);
  opacity:0;
  transform:scaleX(0);
  transform-origin:right;
  transition:opacity .3s ease, transform .45s var(--ease);
}
.home-process__nav li.is-active { transform:translateX(8px); }
.home-process__nav li.is-active::after { opacity:1; transform:scaleX(1); }
.home-process__nav button { padding-right:44px; }

.home-process__count {
  top:22px;
  right:22px;
  left:auto;
  background:rgba(8,7,34,.7);
}

@media (max-width:760px) {
  .page-home .home-system::after { top:28%; right:-42%; }
  .home-process { display:block; }
  .home-process__media {
    border-radius:11px;
    box-shadow:0 24px 62px rgba(20,19,42,.22);
  }
  .home-process__media::before,
  .home-process__media::after { width:34px; height:34px; }
  .home-process__media::before { top:10px; right:74px; }
  .home-process__media::after { bottom:10px; left:10px; }
  .home-process__slide { clip-path:inset(0 10% 0 0); }
  .home-process__slide.is-active { clip-path:inset(0); }
  .home-process__count {
    top:12px;
    right:auto;
    left:12px;
    min-width:88px;
    grid-template-columns:auto 24px auto;
    padding:7px 9px;
  }

  .home-process__nav {
    right:80px;
    bottom:12px;
    left:12px;
    height:76px;
    margin:0;
    border-radius:6px;
    background:linear-gradient(120deg, rgba(10,9,39,.96), rgba(19,17,54,.9));
    box-shadow:0 14px 38px rgba(8,7,34,.34);
  }
  .home-process__nav::after {
    content:'';
    position:absolute;
    top:0;
    left:0;
    width:calc(var(--process-progress) * 100%);
    height:2px;
    background:linear-gradient(90deg, var(--gold), var(--gold-lit));
    transition:width .55s var(--ease);
  }
  .home-process__nav li.is-active { transform:none; }
  .home-process__nav li::after { display:none; }
  .home-process__nav button {
    min-height:76px;
    padding:10px 14px;
  }
  .home-process__step-copy strong { font-size:clamp(20px, 4.2vw, 25px); }

  .home-process__mobile-controls {
    top:50%;
    right:12px;
    bottom:auto;
    display:grid;
    grid-template-columns:52px;
    grid-template-rows:28px auto 28px;
    justify-items:center;
    gap:5px;
    transform:translateY(-50%);
  }
  .home-process__mobile-controls > button {
    width:28px;
    height:28px;
    border-color:rgba(255,255,255,.42);
    background:rgba(8,7,34,.5);
    backdrop-filter:blur(8px);
    font-size:12px;
    transition:background-color .25s ease, transform .25s var(--ease);
  }
  .home-process__mobile-controls > button:active { transform:scale(.9); }
  .home-process__dots {
    display:flex;
    flex-direction:column;
    gap:5px;
  }
  .home-process__dots button {
    position:relative;
    width:50px;
    height:38px;
    overflow:hidden;
    padding:0;
    border:1px solid rgba(255,255,255,.3);
    border-radius:5px;
    background:#11102e;
    opacity:.58;
    transform:translateX(0) scale(.94);
    transition:opacity .3s ease, transform .4s var(--ease), border-color .3s ease, box-shadow .3s ease;
  }
  .home-process__dots button::before { display:none; }
  .home-process__dots button::after {
    top:auto;
    right:0;
    bottom:0;
    left:0;
    width:100%;
    height:2px;
    background:var(--gold-lit);
    transform:scaleX(0);
    transform-origin:left;
  }
  .home-process__dots button img {
    display:block;
    width:100%;
    height:100%;
    object-fit:cover;
    filter:saturate(.7) brightness(.78);
    transition:filter .35s ease, transform .55s var(--ease-soft);
  }
  .home-process__dots button span { display:none; }
  .home-process__dots button.is-active {
    border-color:var(--gold-lit);
    box-shadow:0 8px 22px rgba(8,7,34,.42);
    opacity:1;
    transform:translateX(-7px) scale(1);
  }
  .home-process__dots button.is-active img {
    filter:saturate(1) brightness(1);
    transform:scale(1.08);
  }
  .home-process.is-playing .home-process__dots button.is-active::after {
    animation:home-process-dot 3.4s linear forwards;
  }
}

/* One stage label at a time. The remaining labels stay in the document for
   keyboard and screen-reader access, but do not compete with the active image. */
@media (min-width:761px) {
  .home-process { display:block; }
  .home-process__media { width:100%; height:100%; }
  .home-process__nav {
    position:absolute;
    right:auto;
    bottom:22px;
    left:22px;
    z-index:6;
    display:block;
    width:min(430px, 42%);
    height:96px;
    margin:0;
    overflow:hidden;
    border-radius:7px;
    background:linear-gradient(120deg, rgba(10,9,39,.96), rgba(19,17,54,.9));
    box-shadow:0 18px 50px rgba(8,7,34,.34);
    backdrop-filter:blur(12px);
  }
  .home-process__nav::before {
    top:0;
    right:auto;
    bottom:auto;
    left:0;
    width:calc(var(--process-progress) * 100%);
    height:2px;
    background:linear-gradient(90deg, var(--gold), var(--gold-lit));
    transition:width .55s var(--ease);
  }
  .home-process__nav li {
    position:absolute;
    inset:0;
    border:0 !important;
    opacity:0;
    visibility:hidden;
    transform:translateY(10px);
    pointer-events:none;
  }
  .home-process__nav li.is-active {
    opacity:1;
    visibility:visible;
    transform:none;
  }
  .home-process__nav li::after { display:none; }
  .home-process__nav button {
    grid-template-columns:42px minmax(0, 1fr);
    min-height:96px;
    padding:14px 20px;
    pointer-events:none;
  }
  .home-process__step-copy { opacity:1; visibility:visible; }
}

@media (max-width:760px) {
  .home-process__nav li.is-active,
  .home-process__nav li.is-active button,
  .home-process__nav li.is-active .home-process__step-copy {
    color:var(--white);
    opacity:1;
    visibility:visible;
  }
}

@media (max-width:390px) {
  .home-process__mobile-controls { right:8px; grid-template-columns:44px; }
  .home-process__dots { display:flex; gap:4px; }
  .home-process__dots button { width:42px; height:32px; }
  .home-process__nav { right:62px; }
}

/* One caption, one active story. Keeping the changing copy in a dedicated
   element prevents inactive stages from stacking or sliding outside the card. */
.home-process__caption {
  position:absolute;
  right:auto;
  bottom:22px;
  left:22px;
  z-index:7;
  display:grid;
  grid-template-columns:42px minmax(0, 1fr);
  align-items:center;
  width:clamp(320px, 42%, 470px);
  min-height:96px;
  padding:14px 20px;
  overflow:hidden;
  border:1px solid rgba(255,255,255,.16);
  border-radius:8px;
  background:linear-gradient(120deg, rgba(9,8,38,.97), rgba(24,21,61,.92));
  box-shadow:0 18px 52px rgba(8,7,34,.38);
  backdrop-filter:blur(14px);
  color:var(--white);
}
.home-process__caption::before {
  content:'';
  position:absolute;
  top:0;
  left:0;
  width:calc(var(--process-progress) * 100%);
  height:2px;
  background:linear-gradient(90deg, var(--gold), var(--gold-lit));
  box-shadow:0 0 18px rgba(244,209,157,.45);
  transition:width .46s var(--ease);
}
.home-process__caption-number {
  color:var(--gold-lit);
  font-size:9px;
  font-weight:700;
  letter-spacing:.14em;
}
.home-process__caption-copy {
  display:grid;
  min-width:0;
  gap:5px;
  color:var(--white);
}
.home-process__caption-copy strong {
  color:var(--white);
  font:400 clamp(22px, 2vw, 29px)/1 'Fraunces', Georgia, serif;
  letter-spacing:-.025em;
}
.home-process__caption-copy small {
  overflow:hidden;
  color:rgba(255,255,255,.72);
  font-size:10px;
  line-height:1.35;
  text-overflow:ellipsis;
  white-space:nowrap;
}
.home-process.is-changing .home-process__caption-copy {
  animation:process-caption-in .42s var(--ease-out) both;
}
@keyframes process-caption-in {
  from { opacity:0; transform:translateY(8px); }
  to { opacity:1; transform:none; }
}

@media (max-width:760px) {
  .home-process__caption {
    right:76px;
    bottom:12px;
    left:12px;
    grid-template-columns:30px minmax(0, 1fr);
    width:auto;
    min-height:76px;
    padding:10px 12px;
    border-radius:7px;
    box-shadow:0 14px 38px rgba(8,7,34,.38);
  }
  .home-process__caption-copy { gap:3px; }
  .home-process__caption-copy strong { font-size:clamp(19px, 5.4vw, 24px); }
  .home-process__caption-copy small { font-size:9px; }
}

@media (max-width:390px) {
  .home-process__caption {
    right:58px;
    grid-template-columns:26px minmax(0, 1fr);
    padding-inline:10px;
  }
  .home-process__caption-copy strong { font-size:19px; }
}

@media (prefers-reduced-motion:reduce) {
  .nav-links > .mobile-menu-intro,
  .nav-links > a,
  .nav-links > .nav-services { transition:none; }
  .sticky-story .ss-beats,
  .services-hub .project-grid,
  .service-template-page .mosaic,
  .hscroll-viewport { scroll-behavior:auto; }
  .hero-slide.is-active { will-change:auto; }
  .home-process__slide,
  .home-process__nav li,
  .home-process__nav::before,
  .home-process__dots button,
  .home-process__dots button img { transition:none; }
  .home-process__caption::before { transition:none; }
  .page-home .home-system::after,
  .home-process.is-changing .home-process__slide.is-active img,
  .home-process.is-changing .home-process__caption-copy { animation:none; }
  .home-process.is-playing .home-process__dots button.is-active::after { animation:none; transform:scaleX(1); }
}

/* ==========================================================================
   RESPONSIVE CORRECTIONS
   Appended last so these win on source order over the earlier mobile blocks
   they deliberately override. Every rule here answers a measurement taken at
   320 / 360 / 390 / 768 / 1024 / 1280 — nothing is speculative.
   ========================================================================== */

/* ---------- Full-bleed safety net ----------
   .bleed, .rail and .marquee are built on 100vw minus --sbw, and --sbw is only
   correct once main.js has measured the scrollbar. Between first paint and that
   measurement — and permanently if scripting fails — 100vw overshoots the layout
   viewport by the scrollbar width on classic-scrollbar desktops, which gives the
   whole page a horizontal scrollbar and shifts every band ~8px left.
   `clip` rather than `hidden`: hidden on the root makes the viewport a scroll
   container and kills position:sticky, which the process film and the sticky
   story column both rely on. clip discards the overflow without doing that. */
html { overflow-x: clip; }


/* ---------- Nav panel geometry leaking past the mobile breakpoint ----------
   The mobile menu becomes a fixed slide-in panel at max-width:880px, but the
   panel's box — `inset:62px 0 …` and `min-height:calc(100dvh - 110px)` — is
   declared in a max-width:900px block. Between 881 and 900px the panel sizing
   therefore applied while the nav was still the STATIC desktop row and the
   hamburger was display:none, leaving a transparent ~790px-tall box hanging
   over the hero. It has pointer-events:auto and no background, so it was
   invisible but swallowed every click in that band — elementFromPoint over the
   hero CTAs returned nav.nav-links, not the buttons.

   SECOND LEAK, same cause, found 10 August 2026. The drawer's entrance stagger
   is declared in the same max-width:900px block:

       .nav-links > .mobile-menu-intro, .nav-links > a, .nav-links > .nav-services
         { opacity:0; transform:translateY(12px); }

   with opacity restored only under `.nav-links.open`. On the desktop row there
   is no `.open` — the class only ever lands on the drawer. So between 881 and
   900px, Home / About / Services / Contact and the "Start a Project" CTA all
   rendered at **opacity 0**. Only `.nav-social` survived, because it is not in
   that selector list, which is why the icons appeared to float 12px out of line
   with nothing beside them: they were the only thing left.

   In that band the header had no usable navigation and no hamburger to fall
   back to. Measured at 885px before the fix: five of six nav children at
   opacity 0, transform translateY(12px).

   Reset both leaks to the desktop base (line 429 sets no inset, height or
   padding; the row is opaque and untransformed) for every width at which the
   mobile panel does not exist. `transition` is deliberately NOT reset — the
   drawer's timing is harmless on a row that never animates opacity, and
   clearing it would flatten the .nav-cta hover lift. */
@media (min-width: 881px) {
  .nav-links { inset: auto; min-height: 0; padding-top: 0; }
  .nav-links > .mobile-menu-intro,
  .nav-links > a,
  .nav-links > .nav-services { opacity: 1; transform: none; }
}

/* ---------- Mobile menu: one uninterrupted full-screen surface ----------
   The header can compact while a visitor scrolls, but the old drawer kept a
   fixed 62px top offset. On some phones that left a thin slice of the page
   visible between the compact header and the menu. Opening the drawer now
   owns the entire viewport; the brand and close control deliberately sit above
   it so the opening edge is always intentional. */
@media (max-width: 900px) {
  body.menu-open .nav-links {
    inset:0;
    min-height:100dvh;
    padding:calc(76px + env(safe-area-inset-top, 0px)) 30px calc(28px + env(safe-area-inset-bottom, 0px));
    border:0;
    background:var(--paper);
  }
  body.menu-open .site-header { border-bottom-color:transparent; box-shadow:none; }
  body.menu-open .brand {
    position:fixed;
    top:calc(12px + env(safe-area-inset-top, 0px));
    left:20px;
    z-index:103;
  }
  body.menu-open .menu-toggle {
    position:fixed;
    top:calc(10px + env(safe-area-inset-top, 0px));
    right:20px;
    z-index:103;
  }
}

/* ---------- Service showcase: overlapping cards on tablet and phone ----------
   The mosaic sets `grid-auto-rows` three times: the 12-column desktop value,
   a taller one at 900px, and `auto` at 560px. A later GLOBAL calibration rule
   (`.service-showcase-grid { grid-auto-rows:clamp(96px, 8.5vw, 126px) }`) then
   re-declared it at the same specificity — and media queries add none, so the
   96px desktop row won at EVERY width. Against cards carrying min-height
   176-220px that placed each row 104px apart under a 220px card: the tiles
   overlapped by up to 116px and spilled 96px out of the grid box.

   Restated here, after that rule, so the responsive values apply again.
   `minmax(…, auto)` rather than a fixed track: the row now grows to whatever
   the card's min-height actually is, so the two can never disagree again. */
@media (max-width: 900px) {
  .service-showcase-grid { grid-auto-rows: minmax(clamp(180px, 28vw, 260px), auto); }
}
@media (max-width: 560px) {
  .service-showcase-grid { grid-auto-rows: auto; }
}

/* ---------- Touch targets ----------
   The prev/next circles are 28px, which is a deliberate visual size against a
   photograph — so the hit area is grown with a transparent pseudo-element to
   44px instead of inflating the button and unbalancing the overlay.
   Bounded at 900px, the site's own tablet breakpoint: 768 (iPad portrait) is a
   touch device and was falling through to the desktop sizes. */
@media (max-width: 900px) {
  .home-process__mobile-controls > button { position: relative; }
  .home-process__mobile-controls > button::after {
    content: '';
    position: absolute;
    inset: -8px;
  }
  /* The only control that opens the rest of a review, at 32px. */
  .testimonial-quote details > summary { min-height: 44px; }
  /* Was reduced to 38px at 560px for no reason the layout needed. */
  .service-showcase-link { min-height: 44px; }
}

/* ---------- Mobile legibility floor ----------
   The label tier — eyebrows, card meta, kickers, captions — is uppercase, 600-
   700 weight and letter-spaced .12-.2em, and the earlier phone blocks step it
   DOWN to 8-10px. At 390px that is below the point where letterspaced uppercase
   stays readable; measured across the homepage it affected sixteen components.
   The floor is 11px for the label tier and 13px for anything that is read as a
   sentence. Letter-spacing is eased back where the size goes up so the labels
   occupy roughly the same width and no card re-wraps.

   Bounded at 900px — the site's own tablet breakpoint — not 760px. Media
   queries measure the viewport INCLUDING the classic scrollbar, so a 768px
   iPad reports 768 and a 760px ceiling missed the single most common tablet
   width entirely. True desktop (901px and up) keeps its existing label tier. */
@media (max-width: 900px) {
  .eyebrow { font-size: 11px; letter-spacing: .16em; }
  .hscroll-intro .eyebrow { font-size: 11px; letter-spacing: .14em; }
  .service-showcase-kicker { font-size: 11px; letter-spacing: .14em; }
  .page-home .hero-tag { font-size: 11px; letter-spacing: .14em; }

  .hcard-idx,
  .industry-card .idx,
  .proj-card .meta,
  .service-showcase-copy small { font-size: 11px; letter-spacing: .14em; }

  .home-process__caption-copy small,
  .home-process__step-copy small { font-size: 11px; }
  .home-process__caption-number { font-size: 11px; }

  .testimonial-card__meta { font-size: 11px; letter-spacing: .12em; }
  .testimonial-stage .testimonial-card .ro,
  .testimonial-card__source,
  .testimonial-card__source small { font-size: 11px; }
  .testimonial-stage .testimonial-card figcaption { font-size: 11px; }
  .testimonial-quote details > summary { font-size: 11px; }
  /* Chapter numerals — hidden below 760px, visible and 9px on tablets. */
  .testimonial-chapters button span { font-size: 11px; }

  .hscroll-intro a,
  .service-showcase-link { font-size: 11px; letter-spacing: .1em; }

  /* Nav panel and footer column headings. */
  .services-col-title { font-size: 11px; letter-spacing: .14em; }
  .footer-col h3 { font-size: 11px; letter-spacing: .16em; }

  /* Read as sentences, not labels — these get the 13px floor. */
  .page-home .home-system__lede { font-size: 14px; line-height: 1.6; }
  .page-home .hero-actions .btn { font-size: 13px; }
  .footer-bottom { font-size: 13px; }
}

/* ==========================================================================
   VISUAL POLISH — service showcase and its neighbours
   Scope: the three consecutive card grids on the homepage — .hscroll
   ("Selected spaces"), .service-showcase, and .home-work ("Recent Work").
   CSS only: no markup, no copy, no layout or grid change, nothing that alters
   what a crawler reads.

   The premise is not that anything was broken — it was not. Accessibility is
   already handled (global :focus-visible outline, a hover:none fallback for
   the showcase descriptor, a documented tap-to-reveal caption on the reel).
   The three sections were simply authored at different times and had drifted
   into three separate card systems sitting back to back, which is what makes a
   page read as assembled rather than designed.
   ========================================================================== */

/* ---------- One card system ----------
   Measured across the three adjacent grids: corner radii of 4px / 9px / 12px,
   and the SAME category-label role ("Residential", "01 · Interiors",
   "Healthcare · Akshay Nagar") set at three different weights — 700 / 600 /
   500 — in two different golds.

   Radius settles at 10px. The homepage mosaic keeps its own 12px
   (`.page-home .home-work .mosaic > .proj-card`, higher specificity, left
   alone deliberately): those tiles are markedly larger, and a radius that
   scales a little with the card is correct rather than inconsistent. The
   4-to-9 spread was the actual drift.

   Weight settles at 500 — NOT a middle value. This file already normalises the
   label tier sitewide with `.eyebrow, .meta, .idx { font-weight:500!important }`,
   so 500 is the system's own answer; .hcard-idx (700) and the showcase small
   (600) had simply escaped it by not carrying one of those three class names.
   Matching the rule is right, and it avoids an !important arms race. */
.hcard,
.service-showcase-card,
.proj-card { border-radius: 10px; }

.hcard-idx,
.service-showcase-copy small,
.proj-card .meta { color: var(--gold-lit); font-weight: 500; }

/* ---------- Press feedback ----------
   None of the three card types had an :active state, so on a phone — where
   there is no hover to preview the link — tapping a card produced no response
   at all until the next page painted. `scale` rather than `transform`: the
   cards are .reveal elements whose transform is owned by the reveal
   transition, and the two would fight. */
.hcard,
.service-showcase-card,
.proj-card { transition: scale .18s var(--ease); }
.hcard:active,
.service-showcase-card:active,
.proj-card:active { scale: .985; }

/* ---------- Showcase scrim ----------
   The original is a straight two-stop ramp (.04 at 18% to .76 at 100%). It
   greys down the top half of the photograph more than it needs to, and a linear
   alpha ramp leaves a faint visible band where it begins.

   These stops hold the top of the card CLEARER than before, then fall away
   faster into the caption. The constraint the curve is built around: from the
   50% mark down — everywhere the caption block actually sits — it is never
   lighter than the ramp it replaces. Measured against the gold label
   (#e8d5a8) over a bright (220) photo pixel, contrast improves the whole way
   down rather than being traded away:

       52%  2.10 -> 2.22      80%  4.38 -> 4.92
       60%  2.55 -> 2.74      91%  6.03 -> 7.14
       70%  3.31 -> 3.64

   Worth recording what this does NOT fix: that gold label over the brightest
   images still lands under 4.5:1 near the top of its block, in the new curve
   and the old one alike. It is a pre-existing weakness of a light accent on
   photography, sitewide, and darkening the scrim far enough to solve it would
   bury the image. It needs a colour decision, not a gradient. */
.service-showcase-shade {
  background: linear-gradient(180deg,
    rgba(5,5,31,0)    0%,
    rgba(5,5,31,.04) 30%,
    rgba(5,5,31,.34) 50%,
    rgba(5,5,31,.48) 65%,
    rgba(5,5,31,.62) 80%,
    rgba(5,5,31,.72) 90%,
    rgba(5,5,31,.84) 100%);
}
@media (hover:hover) {
  .service-showcase-card:hover .service-showcase-shade,
  .service-showcase-card:focus-visible .service-showcase-shade {
    background: linear-gradient(180deg,
      rgba(5,5,31,.06)  0%,
      rgba(5,5,31,.18) 30%,
      rgba(5,5,31,.50) 50%,
      rgba(5,5,31,.62) 65%,
      rgba(5,5,31,.76) 80%,
      rgba(5,5,31,.86) 90%,
      rgba(5,5,31,.96) 100%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hcard, .service-showcase-card, .proj-card { transition: none; }
  .hcard:active, .service-showcase-card:active, .proj-card:active { scale: 1; }
}

/* ============================================================
   HIGH-REFRESH HOMEPAGE MOTION
   The home page has several visual stories. Keep their active layers on the
   compositor, and avoid the paint-heavy effects that are most noticeable on a
   120/144Hz display. Motion remains purposeful: image travel, controls and
   progress all use transforms or opacity instead of animated filters/shadows.
   ============================================================ */
@media (prefers-reduced-motion:no-preference) {
  .page-home .hero-slide.is-active .hero-bg,
  .page-home .home-process__slide.is-active,
  .page-home .testimonial-stage .testimonial-card.is-active .testimonial-card__image img {
    backface-visibility:hidden;
    will-change:transform, opacity;
  }

  /* A moving radial-gradient has to repaint the complete hero for every pointer
     sample. The scene itself still responds through transform-based depth. */
  .page-home .hero-bloom {
    background:radial-gradient(30% 40% at 62% 48%, rgba(232,213,168,.20), transparent 70%);
    transition:opacity .5s linear;
  }

  /* The CTA remains tactile on hover without an always-running box-shadow paint. */
  .page-home .hero-actions .btn-dark { animation:none; }
  @media (hover:hover) {
    .page-home .hero-actions .btn-dark:hover,
    .page-home .hero-actions .btn-dark:focus-visible {
      transform:translate3d(0, -2px, 0);
      box-shadow:0 16px 34px rgba(16,12,36,.3), inset 0 1px rgba(255,255,255,.5);
    }
  }

  /* Filter interpolation re-rasterises photographs. Preserve the visual depth
     cue with a scale/overlay transition, which stays consistently smooth. */
  .page-home .service-showcase-card img,
  .page-home .testimonial-card__image img,
  .page-home .home-process__slide,
  .page-home .home-process__dots button img { transition-property:transform, opacity, visibility, clip-path; }
  .page-home .home-process__slide { filter:none; }
}

@media (hover:none), (pointer:coarse) {
  /* Mobile keeps the image stories but drops background-only motion, saving
     battery and leaving every frame available to scrolling and touch input. */
  .page-home .hero-bloom,
  .page-home .hero-vignette,
  .page-home .home-system::after { animation:none; }
}

/* ============================================================
   FOOTER — LOGO-LED CLOSING MOMENT
   The mark is the brand signature, so it stands alone without a duplicate name.
   Motion starts only after the footer enters view (main.js adds .is-footer-live),
   keeping the rest of the site calm and efficient.
   ============================================================ */
.site-footer[data-footer-motion]::before { animation:none; }
.footer-grid { position:relative; }
.footer-grid::before {
  content:'';
  position:absolute;
  top:-13px;
  left:0;
  width:min(180px, 28%);
  height:1px;
  background:linear-gradient(90deg, var(--gold-lit), rgba(244,209,157,0));
  opacity:0;
  pointer-events:none;
  transform:scaleX(0);
  transform-origin:left center;
}
.footer-brand a {
  position:relative;
  isolation:isolate;
  transition:transform .45s var(--ease-soft);
}
.footer-brand a::before {
  content:'';
  position:absolute;
  inset:-18px -22px;
  z-index:-1;
  border-radius:50%;
  background:radial-gradient(circle, rgba(244,209,157,.22), rgba(244,209,157,0) 68%);
  opacity:0;
  pointer-events:none;
  transform:scale(.82);
}
.footer-brand img { display:block; transition:transform .55s var(--ease-soft), filter .55s var(--ease); }

@media (prefers-reduced-motion:no-preference) {
  .site-footer[data-footer-motion].is-footer-live::before { animation:footer-aurora 18s ease-in-out infinite alternate; }
  .site-footer.is-footer-live .footer-grid::before { animation:footer-rule-in .85s var(--ease-out) .1s both; }
  .site-footer.is-footer-live .footer-brand a::before { animation:footer-logo-halo 5.6s ease-in-out .4s infinite; }
  .site-footer.is-footer-live .footer-brand img { animation:footer-logo-arrive .72s var(--ease-out) both; }
}
@keyframes footer-rule-in { to { opacity:1; transform:scaleX(1); } }
@keyframes footer-logo-arrive {
  from { opacity:0; transform:translate3d(-10px, 0, 0) scale(.94); }
  to { opacity:1; transform:translate3d(0, 0, 0) scale(1); }
}
@keyframes footer-logo-halo {
  0%, 100% { opacity:.22; transform:scale(.86); }
  50% { opacity:.62; transform:scale(1.1); }
}
@media (hover:hover) {
  .footer-brand a:hover,
  .footer-brand a:focus-visible { transform:translate3d(0, -3px, 0); }
  .footer-brand a:hover img,
  .footer-brand a:focus-visible img { filter:drop-shadow(0 10px 16px rgba(0,0,0,.24)); transform:scale(1.035); }
}
@media (max-width:640px) {
  .footer-grid::before { top:-8px; width:124px; }
  .footer-brand a::before { inset:-14px -18px; }
}
@media (prefers-reduced-motion:reduce) {
  .footer-grid::before { opacity:1; transform:scaleX(1); }
}

/* ============================================================
   HEADER LOGO — SINGLE RESPONSIVE SIZE SYSTEM
   Earlier rules alternated between explicit width and height, which could
   squeeze the logo on narrow screens. The mark now preserves its natural ratio
   in the normal, compact and open-menu header states.
   ============================================================ */
.site-header .brand {
  display:inline-flex;
  /* The image is 139:92. Keeping it below the bar height leaves a deliberate
     inset above and below instead of letting the mark touch the header edges. */
  width:clamp(96px, 7.5vw, 104px);
  min-height:0;
  transform-origin:left center;
}
.site-header .brand img,
.page-home .site-header .brand img {
  display:block;
  width:100%;
  height:auto;
  max-width:100%;
}
.site-header .nav { min-height:72px; height:72px; }
.site-header.is-stuck .nav { min-height:72px; height:72px; }
.site-header.is-stuck .brand { width:clamp(96px, 7.5vw, 104px); }

/* Simple fixed header: full width, no floating-card spacing or rounded edges. */
.site-header {
  top:0;
  width:100%;
  margin:0;
  border:0;
  border-bottom:1px solid var(--line);
  border-radius:0;
}

@media (max-width:900px) {
  .site-header .nav,
  .site-header.is-stuck .nav { min-height:66px; height:66px; }
  .site-header .brand,
  .site-header.is-stuck .brand { width:92px; }
  .site-header { top:0; margin:0; }
}
@media (max-width:420px) {
  .site-header .brand,
  .site-header.is-stuck .brand { width:84px; }
}

/* ============================================================
   SERVICE SHOWCASE — IMAGE-FIRST LAZY REVEAL
   The card image must never be hidden behind the generic navy loading state.
   This keeps a warm neutral fallback while the native lazy image arrives, then
   resolves the real photograph from a gentle blur in one concise entrance.
   ============================================================ */
.service-showcase-card { background:#d8d1c5; }
.service-showcase-card .service-showcase-image {
  opacity:1;
  filter:blur(15px) saturate(.88);
  transform:scale(1.065);
  transition:filter .62s var(--ease-soft), transform .82s var(--ease-soft);
}
.service-showcase-card .service-showcase-shade {
  background:linear-gradient(180deg,
    rgba(28,24,20,.02) 0%,
    rgba(28,24,20,.10) 34%,
    rgba(28,24,20,.48) 66%,
    rgba(28,24,20,.78) 100%);
}
.js .service-showcase-card.is-media-ready .service-showcase-image {
  filter:blur(0) saturate(1);
  transform:scale(1.01);
}
.service-showcase-card.is-media-error .service-showcase-image { display:none; }
@media (hover:hover) {
  .js .service-showcase-card.is-media-ready:hover .service-showcase-image,
  .js .service-showcase-card.is-media-ready:focus-visible .service-showcase-image {
    filter:brightness(.94) saturate(1);
    transform:scale(1.065);
  }
}
@media (prefers-reduced-motion:reduce) {
  .service-showcase-card .service-showcase-image,
  .js .service-showcase-card.is-media-ready .service-showcase-image { filter:none; transform:scale(1.01); transition:none; }
}

/* ============================================================
   HOMEPAGE MEDIA — BLUR ONLY, NO BLUE LOADING SURFACE
   All image-led homepage components use the same warm fallback. Their finished
   caption gradients appear only after the real bitmap has decoded.
   ============================================================ */
.js .page-home .home-process__slide:not(.is-media-ready),
.js .page-home .hcard:not(.is-media-ready),
.js .page-home .home-work .proj-card:not(.is-media-ready),
.js .page-home .industry-card:not(.is-media-ready),
.js .page-home .testimonial-card:not(.is-media-ready) .testimonial-card__image {
  background:#d8d1c5;
}
.js .page-home .home-process__slide:not(.is-media-ready)::after,
.js .page-home .hcard:not(.is-media-ready)::after,
.js .page-home .home-work .proj-card:not(.is-media-ready)::before,
.js .page-home .industry-card:not(.is-media-ready)::before,
.js .page-home .testimonial-card:not(.is-media-ready) .testimonial-card__image::after {
  opacity:0 !important;
}

/* Finished overlays are neutral charcoal rather than navy, so the photographs
   retain their real colour while captions remain readable. */
.page-home .home-work .proj-card::before,
.page-home .industry-card::before {
  background:linear-gradient(180deg,
    rgba(17,15,14,.01) 20%,
    rgba(17,15,14,.22) 48%,
    rgba(17,15,14,.64) 74%,
    rgba(17,15,14,.92) 100%);
}
.page-home .hcard::after {
  background:linear-gradient(180deg, rgba(17,15,14,0) 40%, rgba(17,15,14,.52) 68%, rgba(17,15,14,.92) 100%);
}
.page-home .home-process__slide::after {
  background:linear-gradient(180deg, rgba(17,15,14,.02) 42%, rgba(17,15,14,.38) 100%);
}

/* Recent Work receives a longer warm-up window in main.js and owns its blur
   reveal, so it never enters the generic hold state. */
.page-home .home-work .proj-card,
.page-home .home-work .proj-card-media { background:#d8d1c5; }
.js .page-home .home-work .proj-card-media img {
  opacity:1;
  filter:blur(16px) saturate(.9);
  transform:scale(1.065);
  transition:filter .64s var(--ease-soft), transform .84s var(--ease-soft);
}
.js .page-home .home-work .proj-card.is-media-ready .proj-card-media img {
  filter:blur(0) saturate(1);
  transform:scale(1.01);
}
.page-home .home-work .proj-card.is-media-error { background:#26221e; }
@media (hover:hover) {
  .js .page-home .home-work .proj-card.is-media-ready:hover .proj-card-media img,
  .js .page-home .home-work .proj-card.is-media-ready:focus-visible .proj-card-media img {
    filter:brightness(.94) saturate(1);
    transform:scale(1.065);
  }
}
@media (hover:none), (pointer:coarse) {
  .page-home .home-work .proj-card.is-media-ready::before,
  .page-home .industry-card.is-media-ready::before { opacity:.78; }
}
@media (prefers-reduced-motion:reduce) {
  .js .page-home .home-work .proj-card-media img,
  .js .page-home .home-work .proj-card.is-media-ready .proj-card-media img { filter:none; transform:scale(1.01); transition:none; }
}

/* ============================================================
   FOOTER BRAND — FIXED LOGO / DESCRIPTION RHYTHM
   An explicit two-row grid prevents the tagline from wrapping beside the logo
   at any viewport width. Both elements share one clean left edge.
   ============================================================ */
.site-footer .footer-brand {
  display:grid;
  grid-template-columns:minmax(0, 1fr);
  align-items:start;
  justify-items:start;
  gap:14px;
  width:min(100%, 360px);
  max-width:360px;
  margin:0 0 12px;
}
.site-footer .footer-brand > a {
  grid-column:1;
  grid-row:1;
  width:auto;
}
.site-footer .footer-brand img {
  width:auto;
  height:clamp(58px, 5.6vw, 76px);
  max-width:min(100%, 170px);
  object-fit:contain;
}
.site-footer .footer-brand > p {
  grid-column:1;
  grid-row:2;
  width:100%;
  max-width:32ch;
  margin:0;
  color:#c5bfb1;
  font-size:clamp(13px, 1.05vw, 15px);
  line-height:1.55;
}
@media (max-width:640px) {
  .site-footer .footer-brand { gap:11px; margin-bottom:6px; }
  .site-footer .footer-brand img { height:54px; max-width:150px; }
  .site-footer .footer-brand > p { font-size:13px; line-height:1.5; }
}

/* ============================================================
   TESTIMONIAL CONTROLS — ONE RESPONSIVE ROW
   The duplicate numbered chapter rail has been removed. Navigation, timing and
   position now live in one compact control bar beneath the review.
   ============================================================ */
.testimonial-stage .testimonial-controls {
  display:grid;
  grid-template-columns:52px minmax(120px, 1fr) auto 52px;
  align-items:center;
  gap:clamp(10px, 1.4vw, 18px);
  margin-top:clamp(14px, 1.6vw, 20px);
}
.testimonial-stage .testimonial-controls button {
  width:52px;
  height:52px;
  flex:none;
}
.testimonial-stage .testimonial-progress { min-width:0; }
.testimonial-stage .testimonial-count {
  min-width:max-content;
  justify-content:center;
  font-variant-numeric:tabular-nums;
}
@media (max-width:760px) {
  .testimonial-stage .testimonial-controls {
    grid-template-columns:44px minmax(44px, 1fr) auto 44px;
    gap:8px;
    margin-top:12px;
  }
  .testimonial-stage .testimonial-controls button { width:44px; height:44px; }
  .testimonial-stage .testimonial-count { gap:4px; font-size:11px; letter-spacing:.08em; }
}
@media (max-width:380px) {
  .testimonial-stage .testimonial-controls { grid-template-columns:40px minmax(32px, 1fr) auto 40px; gap:6px; }
  .testimonial-stage .testimonial-controls button { width:40px; height:40px; }
}

/* ============================================================
   SITEWIDE HEADER ENTRANCE
   The logo and navigation arrive as one short architectural sequence. The
   ready class is JavaScript-owned, so navigation remains visible if scripting
   is unavailable. Transform and opacity keep the sequence compositor-only.
   ============================================================ */
.js .site-header.header-enter-ready::after {
  content:'';
  position:absolute;
  right:0;
  bottom:-1px;
  left:0;
  height:1px;
  z-index:2;
  pointer-events:none;
  background:linear-gradient(90deg, transparent 0, var(--gold) 22%, rgba(10,9,47,.2) 72%, transparent 100%);
  opacity:0;
  transform:scaleX(.08);
  transform-origin:left center;
  transition:transform .75s var(--ease-soft) .08s, opacity .35s ease .08s;
}
.js .site-header.header-enter-ready.header-entered::after {
  opacity:1;
  transform:scaleX(1);
}
.js .site-header.header-enter-ready .brand,
.js .site-header.header-enter-ready .menu-toggle {
  opacity:0;
  transform:translate3d(0,-12px,0);
  transition:opacity .5s ease, transform .62s var(--ease-out);
}
.js .site-header.header-enter-ready.header-entered .brand,
.js .site-header.header-enter-ready.header-entered .menu-toggle {
  opacity:1;
  transform:translate3d(0,0,0);
}
.js .site-header.header-enter-ready .brand { transition-delay:.04s; }
.js .site-header.header-enter-ready .menu-toggle { transition-delay:.18s; }

@media (min-width:881px) {
  .js .site-header.header-enter-ready .nav-links > a,
  .js .site-header.header-enter-ready .nav-services,
  .js .site-header.header-enter-ready .nav-social {
    opacity:0;
    transform:translate3d(0,-10px,0);
    transition:opacity .42s ease, transform .58s var(--ease-out);
  }
  .js .site-header.header-enter-ready.header-entered .nav-links > a,
  .js .site-header.header-enter-ready.header-entered .nav-services,
  .js .site-header.header-enter-ready.header-entered .nav-social {
    opacity:1;
    transform:translate3d(0,0,0);
  }
  .js .site-header.header-enter-ready .nav-links > a:nth-of-type(1) { transition-delay:.10s; }
  .js .site-header.header-enter-ready .nav-links > a:nth-of-type(2) { transition-delay:.15s; }
  .js .site-header.header-enter-ready .nav-services { transition-delay:.20s; }
  .js .site-header.header-enter-ready .nav-links > a:nth-of-type(3) { transition-delay:.25s; }
  .js .site-header.header-enter-ready .nav-links > a:nth-of-type(4) { transition-delay:.30s; }
  .js .site-header.header-enter-ready .nav-social { transition-delay:.35s; }
}

@media (prefers-reduced-motion:reduce) {
  .js .site-header.header-enter-ready::after { display:none; }
  .js .site-header.header-enter-ready .brand,
  .js .site-header.header-enter-ready .menu-toggle,
  .js .site-header.header-enter-ready .nav-links > a,
  .js .site-header.header-enter-ready .nav-services,
  .js .site-header.header-enter-ready .nav-social {
    opacity:1;
    transform:none;
    transition:none;
  }
}

/* ---------- Service image grid: larger, clearer responsive cards ---------- */
.page-home .service-showcase-grid {
  grid-auto-rows:clamp(124px, 11.5vw, 172px);
}
@media (max-width:900px) {
  /* minmax(…, auto), never a fixed track. This rule is scoped to .page-home and
     sits after the "overlapping cards on tablet and phone" fix further up, so it
     out-specifies AND outranks it — a fixed 210px row here reinstated exactly the
     bug that block describes. The cards below carry min-heights of 240-380px on a
     phone; against a 210px track each card overlapped the one under it by up to
     118px, which is what the second card's corner sitting on the first card's
     photograph was. The row has to be free to grow to whatever the card's own
     min-height resolves to, so the two can never disagree. */
  .page-home .service-showcase-grid {
    grid-auto-rows:minmax(clamp(210px, 31vw, 300px), auto);
  }
}
@media (max-width:640px) {
  /* One column below 640: the row is simply the card. */
  .page-home .service-showcase-grid { gap:12px; grid-auto-rows:auto; }
  .page-home .service-showcase-card--residential { min-height:clamp(300px, 84vw, 380px); }
  .page-home .service-showcase-card--villa,
  .page-home .service-showcase-card--healthcare,
  .page-home .service-showcase-card--commercial,
  .page-home .service-showcase-card--government,
  .page-home .service-showcase-card--luxury,
  .page-home .service-showcase-card--residential-build,
  .page-home .service-showcase-card--commercial-build,
  .page-home .service-showcase-card--office {
    min-height:clamp(240px, 70vw, 310px);
  }
}

/* ============================================================
   HOME ENQUIRY — MATERIAL LEDGER
   A conversion form should feel like the beginning of a design consultation,
   not the end of a template. These rules stay scoped to the homepage so the
   contact page keeps its established, task-focused form.
   ============================================================ */
.page-home .home-enquiry-section {
  position:relative;
  isolation:isolate;
  overflow:hidden;
  background:
    linear-gradient(118deg, rgba(247,244,236,.98), rgba(236,229,215,.98)),
    var(--paper-warm);
}
.page-home .home-enquiry-section::before {
  content:'';
  position:absolute;
  inset:0;
  z-index:-1;
  pointer-events:none;
  opacity:.7;
  background:
    linear-gradient(90deg, transparent 0 12.5%, rgba(13,12,46,.045) 12.5% calc(12.5% + 1px), transparent calc(12.5% + 1px) 87.5%, rgba(13,12,46,.045) 87.5% calc(87.5% + 1px), transparent calc(87.5% + 1px)),
    radial-gradient(circle at 76% 36%, rgba(205,165,98,.18), transparent 20%),
    radial-gradient(circle at 20% 88%, rgba(13,12,46,.06), transparent 27%);
}
.page-home .home-enquiry-luxury {
  display:grid;
  grid-template-columns:minmax(0, .83fr) minmax(480px, 1.17fr);
  align-items:stretch;
  gap:clamp(38px, 7vw, 110px);
  max-width:1180px;
  margin-inline:auto;
}
.page-home .home-enquiry-aside {
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  justify-content:center;
  padding:clamp(16px, 3vw, 34px) 0;
}
.page-home .home-enquiry-aside .eyebrow {
  color:var(--ink);
  margin-bottom:clamp(18px, 2vw, 28px);
}
.page-home .home-enquiry-aside .eyebrow::before { background:#bd9255; }
.page-home .home-enquiry-aside .section-title {
  max-width:9ch;
  margin:0;
  color:var(--ink);
  font-size:clamp(43px, 4.55vw, 70px);
  line-height:.98;
  letter-spacing:-.055em;
}
.page-home .home-enquiry-aside .section-title::after {
  content:'';
  display:block;
  width:70px;
  height:1px;
  margin-top:clamp(24px, 3vw, 38px);
  background:linear-gradient(90deg, #b98c50, rgba(185,140,80,0));
}
.page-home .home-enquiry-aside .home-contact-intro {
  max-width:35ch;
  margin:clamp(28px, 3.2vw, 44px) 0 0;
  color:#5d5a6d;
  font-size:clamp(15px, 1.25vw, 17px);
  line-height:1.65;
}
.page-home .home-contact-card {
  position:relative;
  overflow:hidden;
  align-self:center;
  padding:clamp(28px, 3.5vw, 54px);
  border:1px solid rgba(13,12,46,.16);
  border-radius:clamp(16px, 1.5vw, 24px) !important;
  background-clip:padding-box;
  background:rgba(255,254,250,.88);
  box-shadow:22px 24px 0 rgba(13,12,46,.055), 0 24px 50px rgba(28,24,38,.10);
}
.page-home .home-contact-card::before {
  content:'';
  position:absolute;
  top:0;
  right:0;
  width:clamp(96px, 16%, 140px);
  height:3px;
  background:linear-gradient(90deg, #bc9054, #e4c88e);
}
.page-home .home-contact-card__heading {
  display:grid;
  grid-template-columns:auto 1fr auto;
  align-items:center;
  gap:12px;
  margin-bottom:clamp(26px, 3vw, 38px);
  color:var(--ink);
  font-size:10px;
  font-weight:700;
  letter-spacing:.16em;
  text-transform:uppercase;
}
.page-home .home-contact-card__heading i {
  display:block;
  height:1px;
  background:linear-gradient(90deg, rgba(13,12,46,.2), rgba(13,12,46,.03));
}
.page-home .home-contact-card__heading small {
  color:#897554;
  font-size:9px;
  font-weight:650;
  letter-spacing:.09em;
}
.page-home .home-contact-form .field { margin-bottom:20px; }
.page-home .home-contact-form .field input,
.page-home .home-contact-form .field select {
  min-height:58px;
  border-color:rgba(13,12,46,.18);
  border-radius:0;
  background:#f8f6f0;
  color:var(--ink);
  transition:border-color .25s var(--ease), background-color .25s var(--ease), box-shadow .25s var(--ease), transform .25s var(--ease);
}
.page-home .home-contact-form .field:focus-within input,
.page-home .home-contact-form .field:focus-within select {
  border-color:#a9793d;
  background:#fffefb;
  box-shadow:0 0 0 3px rgba(185,140,80,.15);
}
.page-home .home-contact-form .field:focus-within label { color:#9b6d35; }
.page-home .home-contact-form .req { color:#a64737; }
.page-home .home-enquiry-submit {
  position:relative;
  isolation:isolate;
  width:100%;
  min-height:60px;
  justify-content:center;
  gap:12px;
  padding:7px 28px;
  overflow:hidden;
  border:1px solid #0d0c2e;
  border-radius:999px !important;
  background:#0d0c2e;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.09), 0 10px 20px rgba(13,12,46,.18);
  color:#fffdf8;
  font-size:12px;
  font-weight:700;
  letter-spacing:.13em;
  text-transform:uppercase;
}
.page-home .home-enquiry-submit::before {
  content:'';
  position:absolute;
  inset:1px;
  z-index:-1;
  background:linear-gradient(104deg, rgba(202,160,96,.42), transparent 31% 68%, rgba(202,160,96,.26));
  opacity:.65;
  transition:opacity .3s ease;
}
.page-home .home-enquiry-submit::after {
  content:'';
  position:absolute;
  inset:0;
  z-index:-1;
  background:linear-gradient(105deg, transparent 25%, rgba(255,243,211,.26) 50%, transparent 75%);
  transform:translateX(-125%);
  transition:transform .65s var(--ease);
}
.page-home .home-enquiry-submit .arr { margin-left:4px; font-size:18px; }
.page-home .home-contact-form .form-note {
  margin-top:18px;
  color:#726d77;
  font-size:11px;
  letter-spacing:.01em;
}
@media (hover:hover) {
  .page-home .home-enquiry-submit:hover,
  .page-home .home-enquiry-submit:focus-visible {
    background:#1b173d;
    box-shadow:inset 0 0 0 1px rgba(255,255,255,.16), 0 16px 26px rgba(13,12,46,.24);
    transform:translate3d(0, -3px, 0);
  }
  .page-home .home-enquiry-submit:hover::before,
  .page-home .home-enquiry-submit:focus-visible::before { opacity:1; }
  .page-home .home-enquiry-submit:hover::after,
  .page-home .home-enquiry-submit:focus-visible::after { transform:translateX(125%); }
  .page-home .home-enquiry-submit:hover .arr,
  .page-home .home-enquiry-submit:focus-visible .arr { transform:translateX(6px); }
}
.page-home .home-enquiry-submit:focus-visible { outline:3px solid rgba(185,140,80,.6); outline-offset:3px; }
.page-home .home-enquiry-submit.is-sending { transform:none; background:#28244c; }
@media (max-width:900px) {
  .page-home .home-enquiry-luxury { grid-template-columns:minmax(0, 1fr); gap:32px; max-width:700px; }
  .page-home .home-enquiry-aside { padding:0; }
  .page-home .home-enquiry-aside .section-title { max-width:13ch; }
}
@media (max-width:560px) {
  .page-home .home-enquiry-section::before { opacity:.48; background:radial-gradient(circle at 90% 5%, rgba(205,165,98,.18), transparent 28%); }
  .page-home .home-enquiry-aside .section-title { font-size:clamp(39px, 11vw, 52px); }
  .page-home .home-contact-card { padding:26px 18px 22px; box-shadow:10px 12px 0 rgba(13,12,46,.05), 0 18px 32px rgba(28,24,38,.10); }
  .page-home .home-contact-card__heading { grid-template-columns:auto 1fr; margin-bottom:26px; }
  .page-home .home-contact-card__heading small { grid-column:1 / -1; margin-top:-5px; }
  .page-home .home-contact-form .field { margin-bottom:16px; }
  .page-home .home-contact-form .field input,
  .page-home .home-contact-form .field select { min-height:56px; }
  .page-home .home-enquiry-submit { min-height:58px; }
}
@media (prefers-reduced-motion:reduce) {
  .page-home .home-enquiry-submit,
  .page-home .home-enquiry-submit::before,
  .page-home .home-enquiry-submit::after,
  .page-home .home-contact-form .field input,
  .page-home .home-contact-form .field select { transition:none; }
  .page-home .home-enquiry-submit.is-sending .arr { animation:none; }
}

/* ============================================================
   CONTACT STUDIO — A PROJECT BRIEF, NOT A GENERIC CONTACT FORM
   ============================================================ */
.page-contact .contact-studio { background:#f2eee5; }
.page-contact .contact-studio__stage {
  position:relative;
  isolation:isolate;
  overflow:hidden;
  /* Brief asks for clamp(65px, 7vw, 110px); 7vw is ~101px at 1440, which is
     close to the 132px that was flagged as too much dead space. This sits at
     the brief's lower bound (~66px at 1440) — controlled, not cavernous. */
  padding:clamp(44px, 4.6vw, 72px) 0 clamp(44px, 4.8vw, 76px);
  background:
    linear-gradient(90deg, transparent 0 8.5%, rgba(12,12,43,.075) 8.5% calc(8.5% + 1px), transparent calc(8.5% + 1px) 91.5%, rgba(12,12,43,.075) 91.5% calc(91.5% + 1px), transparent calc(91.5% + 1px)),
    radial-gradient(circle at 80% 22%, rgba(213,186,136,.22), transparent 19%),
    #f2eee5;
}
/* Three areas, not two. The left column stacks intro over the direct-contact
   rail; the brief spans both rows beside them. Named areas rather than source
   order, so the narrow layout can put the rail AFTER the form without moving
   anything in the markup. */
.page-contact .contact-studio__grid {
  display:grid;
  grid-template-columns:minmax(0, .85fr) minmax(min(100%, 540px), 1.15fr);
  grid-template-areas:
    'intro   brief'
    'details brief';
  grid-template-rows:auto 1fr;
  align-items:stretch;
  /* 7vw capped at 92px rather than 110px: at 1190px of container the wider gap
     costs the left column ~20px, which is what starts wrapping the phone
     number onto a second line. */
  column-gap:clamp(50px, 6vw, 92px);
  row-gap:clamp(24px, 2.6vw, 34px);
  max-width:1190px;
  margin-inline:auto;
}
.page-contact .contact-studio__intro  { grid-area:intro; }
/* Stretched to the full height of the left column, with its contents centred.
   That is what makes the last contact card's bottom edge land exactly on the
   card's bottom edge at every viewport — the two columns are the same height
   by construction, rather than by hand-tuned spacing that drifts the moment a
   line of copy wraps differently. */
.page-contact .contact-brief          { grid-area:brief; align-self:stretch; display:flex; flex-direction:column; justify-content:center; }
.page-contact .contact-studio__details { grid-area:details; }
.page-contact .contact-studio__intro { padding:0; }
.page-contact .contact-studio__intro .eyebrow { margin-bottom:24px; color:var(--ink); }
.page-contact .contact-studio__intro .eyebrow::before { background:#b48547; }
.page-contact .contact-studio__intro h1 {
  max-width:9ch;
  margin:0;
  color:var(--ink);
  /* See note in the handover: the brief's clamp(54px, 4.5vw, 76px) computes to
     ~65px at 1440 — the size that was flagged as too large. This lands at 56px
     there: clearly smaller, still large enough to hold the column. */
  font:400 clamp(40px, 3.9vw, 60px)/.98 'Montserrat', sans-serif;
  letter-spacing:-.03em;
}
.page-contact .contact-studio__intro h1::after {
  content:'';
  display:block;
  width:70px;
  height:1px;
  margin-top:clamp(16px, 1.8vw, 24px);
  background:linear-gradient(90deg, #b98c50, rgba(185,140,80,0));
}
.page-contact .contact-studio__lead {
  max-width:37ch;
  margin:clamp(16px, 1.8vw, 24px) 0 0;
  color:#5b5968;
  font-size:clamp(15px, 1.25vw, 17px);
  line-height:1.72;
}
.page-contact .contact-brief {
  position:relative;
  isolation:isolate;
  padding:clamp(30px, 4vw, 56px);
  border:1px solid rgba(12,12,43,.13);
  /* 16px, matching the contact cards. A hard-square form card beside three
     16px-radius cards was the page reading in two different design languages. */
  border-radius:16px;
  background:#fbfaf6;
  /* The offset block is kept — it is the signature of this card — but softened
     from 18px/.055 so it reads as paper lifting, not as a pasted-on sticker. */
  box-shadow:12px 12px 0 rgba(12,12,43,.035), 0 26px 52px -22px rgba(35,30,40,.26);
}
/* Inset from the corner now that the card is rounded — a 3px bar running into a
   16px radius clips into a wedge. */
.page-contact .contact-brief::before {
  content:'';
  position:absolute;
  top:0;
  right:36px;
  width:clamp(90px, 16%, 128px);
  height:3px;
  border-radius:0 0 2px 2px;
  background:linear-gradient(90deg, rgba(173,124,60,0), #c69a58);
}
.page-contact .contact-brief::after {
  content:'';
  position:absolute;
  right:18px;
  bottom:18px;
  z-index:-1;
  width:46%;
  height:40%;
  border-right:1px solid rgba(12,12,43,.08);
  border-bottom:1px solid rgba(12,12,43,.08);
  transform:translate(18px, 18px);
}
.page-contact .contact-brief h2 {
  margin:0;
  color:var(--ink);
  font:700 10px/1 'Montserrat', sans-serif;
  letter-spacing:.16em;
  text-transform:uppercase;
}
.page-contact .contact-brief__heading {
  display:grid;
  grid-template-columns:auto 1fr auto;
  align-items:center;
  gap:12px;
  margin-bottom:clamp(30px, 3.6vw, 46px);
}
.page-contact .contact-brief__heading i {
  display:block;
  height:1px;
  background:linear-gradient(90deg, rgba(13,12,46,.2), rgba(13,12,46,.03));
}
.page-contact .contact-brief__heading small {
  color:#897554;
  font-size:9px;
  font-weight:650;
  letter-spacing:.09em;
  text-transform:uppercase;
}
.page-contact .contact-brief__row { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:clamp(20px, 3vw, 30px); }
.page-contact .contact-brief .field { margin-bottom:28px; }
.page-contact .contact-brief .field > label {
  position:absolute;
  left:23px;
  top:23px;
  z-index:1;
  margin:0;
  pointer-events:none;
  transform-origin:left top;
  color:#625e6d;
  font-size:16px;
  font-weight:500;
  letter-spacing:0;
  text-transform:none;
  white-space:nowrap;
  transition:transform .3s var(--ease-soft), color .3s ease;
}
.page-contact .contact-brief .field > input {
  width:100%;
  /* 66px, not 58. The card is stretched to the left column's height, and at 58
     the form filled only ~70% of it — the balance was being paid for with a
     hollow box. Taller fields spend that space on the form instead. */
  min-height:74px;
  padding:30px 22px 10px;
  border:1px solid rgba(13,12,46,.18);
  border-radius:10px;
  background:#f8f6f0;
  color:var(--ink);
  font:400 16px/1.45 'Montserrat', sans-serif;
  box-shadow:none;
  transition:border-color .25s var(--ease), background-color .25s var(--ease), box-shadow .25s var(--ease);
}
.page-contact .contact-brief .field > input::placeholder { color:#98929c; }
.page-contact .contact-brief .field:focus-within > input {
  outline:0;
  border-color:#a9793d;
  background:#fffefb;
  box-shadow:0 0 0 3px rgba(185,140,80,.15);
}
.page-contact .contact-brief .field:focus-within > label { color:#956d38; }
.page-contact .contact-brief .field:has(> input:not(:placeholder-shown)) > label,
.page-contact .contact-brief .field:focus-within > label { transform:translate3d(0, -10px, 0) scale(.74); }
.page-contact .contact-brief .field[aria-invalid="true"] > input,
.page-contact .contact-brief input[aria-invalid="true"] { border-color:#a0443e; box-shadow:0 0 0 3px rgba(160,68,62,.12); }
.page-contact .contact-brief .req { color:#a0443e; }
.page-contact .contact-brief .field-error { margin:7px 0 0; color:#9c463f; font-size:11px; line-height:1.4; }
.page-contact .contact-brief .form-status { margin:-10px 0 25px; }
.page-contact .contact-brief__submit {
  display:flex;
  align-items:center;
  width:100%;
  min-height:60px;
  justify-content:center;
  gap:12px;
  margin-top:3px;
  padding:7px 28px;
  overflow:hidden;
  border:1px solid #0d0c2e;
  border-radius:999px;
  background:#0d0c2e;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.09), 0 10px 20px rgba(13,12,46,.18);
  color:#fffdf8;
  cursor:pointer;
  font:700 11px/1 'Montserrat', sans-serif;
  letter-spacing:.15em;
  text-transform:uppercase;
  transition:transform .35s var(--ease), background-color .35s var(--ease), box-shadow .35s var(--ease);
}
.page-contact .contact-brief__submit-icon { font-size:18px; transition:transform .4s var(--ease-soft); }
.page-contact .contact-brief__submit:focus-visible { outline:3px solid rgba(168,120,60,.62); outline-offset:3px; }
@media (hover:hover) and (pointer:fine) {
  .page-contact .contact-brief__submit:hover { background:#1b173d; box-shadow:inset 0 0 0 1px rgba(255,255,255,.16), 0 16px 26px rgba(13,12,46,.24); transform:translate3d(0, -3px, 0); }
  .page-contact .contact-brief__submit:hover .contact-brief__submit-icon { transform:translateX(6px); }
}
.page-contact .contact-brief__submit:active { transform:translateY(0); }
.page-contact .contact-brief__submit.is-sending { opacity:.75; pointer-events:none; }
.page-contact .contact-brief__submit.is-sending .contact-brief__submit-icon { animation:contact-send-arrow .7s var(--ease-soft) infinite; }
@keyframes contact-send-arrow { 50% { transform:translateX(5px); } }
.page-contact .contact-brief__privacy { margin:15px 0 0; color:#77717c; font-size:11px; line-height:1.5; text-align:center; }
/* A stacked rail now, not a four-across footer row. The border-top and the
   ~100px of margin that separated it from the composition are gone with it —
   it is part of the left column, not a band under everything. */
.page-contact .contact-studio__details {
  display:grid;
  grid-template-columns:minmax(0, 1fr);
  /* Equal rows, so the three cards stay exactly the same height even when one
     value wraps — at 1024 the email address wraps and the card grew to 97px
     beside two 84px siblings. */
  grid-auto-rows:1fr;
  gap:12px;
  max-width:460px;
  margin:0;
  /* End-aligned in its row so the last card's bottom edge lands on the form
     card's bottom edge. The row is the 1fr track, so it absorbs whatever
     height difference is left between the two columns. */
  align-self:end;
}
.page-contact .contact-studio__details > * { min-width:0; }
.page-contact .contact-studio__details span { display:block; margin-bottom:8px; color:#957142; font-size:9px; font-weight:700; letter-spacing:.16em; text-transform:uppercase; }
.page-contact .contact-studio__details p { margin:0; color:var(--ink); font-size:13px; font-weight:600; line-height:1.55; overflow-wrap:anywhere; }
/* Icon chip + stacked label/value. Text-only, the three cards read as one grey
   mass and nothing separates Call from WhatsApp at a glance. */
.page-contact .contact-detail-button {
  position:relative;
  display:grid;
  grid-template-columns:auto minmax(0, 1fr);
  grid-template-areas:
    'icon label'
    'icon value';
  column-gap:16px;
  row-gap:3px;
  /* 118px was sized for a four-across row. Stacked three-deep in a rail that
     has to sit beside the form, that is 400px of column for three links. */
  min-height:84px;
  align-content:center;
  /* 52px of right padding, not 24: the arrow is absolutely positioned in that
     gutter, and a long email address would otherwise run underneath it. */
  padding:18px 52px 18px 22px;
  border:1px solid rgba(13,12,46,.14);
  border-radius:16px;
  background:#fffdf8;
  box-shadow:0 9px 20px rgba(13,12,46,.04);
  color:var(--ink);
  text-decoration:none;
  transition:transform .3s var(--ease), border-color .3s ease, box-shadow .3s ease, background-color .3s ease;
}
.page-contact .contact-detail-button span { grid-area:label; margin:0; }
.page-contact .contact-detail-button strong { grid-area:value; font-size:15px; line-height:1.4; letter-spacing:-.01em; overflow-wrap:anywhere; }
.page-contact .contact-detail-button__icon {
  grid-area:icon;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:42px;
  height:42px;
  border-radius:50%;
  background:rgba(13,12,46,.055);
  color:var(--ink);
  transition:background-color .3s ease, color .3s ease;
}
/* The one card allowed its own colour — it is the action people scan for. */
.page-contact .contact-detail-button--wa .contact-detail-button__icon { background:rgba(31,157,85,.12); color:#177c42; }
/* Centred on the shorter card rather than pinned to a bottom corner it no
   longer has room for. */
.page-contact .contact-detail-button b { position:absolute; right:19px; top:50%; transform:translateY(-50%); color:#9b6d36; font-size:20px; font-weight:400; transition:transform .3s var(--ease); }
/* The address now lives in the intro, outside .contact-studio__details, so it
   can no longer inherit that block's span/p styling — restated here so it looks
   identical wherever it sits. */
.page-contact .contact-studio__address { max-width:37ch; margin-top:clamp(18px, 2vw, 26px); padding:0; }
.page-contact .contact-studio__address span { display:block; margin-bottom:7px; color:#957142; font-size:9px; font-weight:700; letter-spacing:.16em; text-transform:uppercase; }
.page-contact .contact-studio__address p { margin:0; color:var(--ink); font-size:13px; font-weight:600; line-height:1.55; overflow-wrap:anywhere; }
@media (hover:hover) and (pointer:fine) {
  .page-contact .contact-detail-button:hover { border-color:rgba(185,140,80,.58); background:#fffefb; box-shadow:0 14px 26px rgba(13,12,46,.10); transform:translate3d(0, -2px, 0); }
  /* Must re-state the centring offset, or hovering drops the arrow. */
  .page-contact .contact-detail-button:hover b { transform:translateY(-50%) translateX(5px); }
}
.page-contact .contact-detail-button:focus-visible { outline:3px solid rgba(185,140,80,.6); outline-offset:3px; }
/* These routes remain in the direct-contact ledger above. Removing the global
   dock on the contact page prevents it from obscuring the primary submit CTA. */
.page-contact .contact-dock,
.page-contact .wa-float { display:none !important; }
/* Between roughly 900 and 1200 the rail is at its narrowest while still beside
   the form, and the email address is the string that runs out of room first. */
@media (max-width:1200px) and (min-width:901px) {
  .page-contact .contact-detail-button { column-gap:13px; padding:16px 44px 16px 18px; }
  .page-contact .contact-detail-button__icon { width:38px; height:38px; }
  .page-contact .contact-detail-button strong { font-size:14px; }
}

@media (max-width:900px) {
  /* The rail drops BELOW the form here: on one column the form is what the
     page is for, and three contact cards above it would push it under the
     fold. Named areas make that a reorder, not a markup change. */
  .page-contact .contact-studio__grid {
    grid-template-columns:minmax(0, 1fr);
    grid-template-areas:'intro' 'brief' 'details';
    grid-template-rows:auto auto auto;
    row-gap:34px;
    max-width:700px;
  }
  .page-contact .contact-studio__intro h1 { max-width:12ch; }
  .page-contact .contact-studio__details { grid-template-columns:repeat(3, minmax(0, 1fr)); max-width:700px; align-self:auto; }
}
@media (max-width:560px) {
  .page-contact .contact-studio__stage { padding-top:50px; background:radial-gradient(circle at 100% 0, rgba(213,186,136,.2), transparent 24%), #f2eee5; }
  .page-contact .contact-studio__intro h1 { font-size:clamp(44px, 13vw, 59px); }
  .page-contact .contact-studio__lead { margin-top:22px; }
  .page-contact .contact-brief { padding:25px 19px; box-shadow:10px 11px 0 rgba(12,12,43,.05), 0 18px 34px rgba(35,30,40,.08); }
  .page-contact .contact-brief__row { grid-template-columns:1fr; gap:0; }
  .page-contact .contact-brief .field { margin-bottom:21px; }
  .page-contact .contact-studio__details { grid-template-columns:minmax(0, 1fr); gap:10px; margin-top:0; max-width:none; }
  .page-contact .contact-brief__heading { grid-template-columns:auto 1fr; margin-bottom:26px; }
  .page-contact .contact-brief__heading small { grid-column:1 / -1; margin-top:-5px; }
  .page-contact .contact-detail-button { min-height:108px; padding:18px 40px 18px 18px; }
}
@media (prefers-reduced-motion:reduce) {
  .page-contact .contact-brief__submit,
  .page-contact .contact-brief__submit-icon,
  .page-contact .contact-brief .field > input,
  .page-contact .contact-brief__submit.is-sending .contact-brief__submit-icon { animation:none; }
}

/* ---------- Studio map ----------
   The iframe is lazy-loaded, so Google's ~800KB of map tiles and script are not
   on the critical path for a page whose job is the form above it. */
.page-contact .contact-map {
  padding:0 0 clamp(44px, 5vw, 78px);
  background:#f2eee5;
}
.page-contact .contact-map__head {
  display:flex;
  flex-wrap:wrap;
  align-items:flex-end;
  justify-content:space-between;
  gap:16px 28px;
  max-width:1190px;
  margin:0 auto clamp(18px, 2.2vw, 26px);
  padding-top:clamp(28px, 3.4vw, 44px);
  border-top:1px solid rgba(12,12,43,.15);
}
.page-contact .contact-map__eyebrow {
  display:block;
  margin-bottom:8px;
  color:#957142;
  font-size:9px;
  font-weight:700;
  letter-spacing:.16em;
  text-transform:uppercase;
}
.page-contact .contact-map__head h2 {
  max-width:none;
  margin:0;
  color:var(--ink);
  font:400 clamp(22px, 2.1vw, 30px)/1.1 'Montserrat', sans-serif;
  letter-spacing:-.035em;
}
.page-contact .contact-map__address {
  max-width:40ch;
  margin:10px 0 0;
  color:#5b5968;
  font-size:14px;
  line-height:1.6;
}
.page-contact .contact-map__directions {
  display:inline-flex;
  align-items:center;
  gap:10px;
  min-height:44px;
  padding:12px 24px;
  border:1px solid rgba(13,12,46,.2);
  border-radius:999px;
  background:rgba(255,254,250,.7);
  color:var(--ink);
  font-size:12px;
  font-weight:700;
  letter-spacing:.1em;
  text-transform:uppercase;
  text-decoration:none;
  transition:background-color .3s ease, border-color .3s ease, transform .3s var(--ease);
}
.page-contact .contact-map__directions b { font-weight:400; font-size:17px; transition:transform .3s var(--ease); }
@media (hover:hover) and (pointer:fine) {
  .page-contact .contact-map__directions:hover { background:#fffefb; border-color:rgba(185,140,80,.58); transform:translateY(-2px); }
  .page-contact .contact-map__directions:hover b { transform:translateX(4px); }
}
.page-contact .contact-map__directions:focus-visible { outline:3px solid rgba(185,140,80,.6); outline-offset:3px; }

.page-contact .contact-map__frame {
  position:relative;
  overflow:hidden;
  max-width:1190px;
  margin-inline:auto;
  height:clamp(320px, 42vw, 520px);
  border:1px solid rgba(12,12,43,.15);
  border-radius:18px;
  background:#e9e4d8;
  box-shadow:0 18px 40px rgba(13,12,46,.08);
}
.page-contact .contact-map__fallback {
  position:absolute;
  inset:0;
  z-index:0;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:24px;
  color:#5b5968;
  font-size:13px;
  font-weight:600;
  letter-spacing:.04em;
  text-align:center;
  text-decoration:none;
}
/* Above the fallback, so it covers it whenever the map actually paints. */
.page-contact .contact-map__frame iframe {
  position:relative;
  z-index:1;
  display:block;
  width:100%;
  height:100%;
  border:0;
}

@media (max-width:560px) {
  .page-contact .contact-map__head { align-items:flex-start; flex-direction:column; }
  .page-contact .contact-map__directions { width:100%; justify-content:center; }
  .page-contact .contact-map__frame { height:300px; border-radius:14px; }
}
@media (prefers-reduced-motion:reduce) {
  .page-contact .contact-map__directions,
  .page-contact .contact-map__directions b,
  .page-contact .contact-detail-button,
  .page-contact .contact-detail-button b { transition:none; }
  .page-contact .contact-detail-button:hover,
  .page-contact .contact-map__directions:hover { transform:none; }
}

/* ============================================================
   INNER-PAGE DEPTH SYSTEM — 2026-08
   ------------------------------------------------------------
   One shared vocabulary for Services, the nine service detail
   pages, About and Gallery. The homepage is deliberately NOT in
   scope: it stays the benchmark, and nothing in this section is
   authored against a .page-home selector.

   Two signature movements, and only two, so the four pages read
   as one site rather than four experiments:

     1. PLATE REVEAL — a photograph arrives as a framed plate:
        the frame opens from the bottom edge while the image
        inside settles from a slight over-scale. It reads as a
        print being placed, not as a card fading in.
     2. PLANE DRIFT  — layered planes travel at different rates
        against the scroll, which is what actually sells depth.
        One scroll job in main.js writes --cs-drift; every rule
        here only reads it.

   Everything is transform, opacity and clip-path. No rule in
   this section reads layout, and nothing is hidden without
   html.js, so a JavaScript failure leaves every photograph on
   screen at full size.
   ============================================================ */
:root {
  /* Shared so a plate rotated in one section matches one rotated
     in another. Long focal length on purpose: architecture is
     shot long, and a short perspective makes interiors look like
     a funhouse. */
  --cs-persp: 1600px;

  /* Plates are near-square-cornered. Interior work is about edges
     and reveals; a 12px radius makes every photograph look like
     an app tile. */
  --cs-plate-radius: 2px;

  /* Three shadow depths, matched to the three plane depths, so a
     plane sitting further back also casts softer and wider.
     Tinted with the brand navy rather than black — a neutral
     black shadow over warm paper reads as dirt. */
  --cs-shadow-1: 0 1px 2px rgba(20,19,42,.05), 0 10px 26px rgba(20,19,42,.09);
  --cs-shadow-2: 0 2px 6px rgba(20,19,42,.07), 0 26px 62px rgba(20,19,42,.16);
  --cs-shadow-3: 0 4px 12px rgba(5,5,31,.16), 0 52px 116px rgba(5,5,31,.34);

  /* How far a drifting plane travels across its whole pass through
     the viewport. Deliberately small: parallax past about 40px
     stops reading as depth and starts reading as the page
     sliding apart. */
  --cs-drift-range: 26px;
}

/* ---------- The plate ----------
   The single photographic unit. Everything image-led on these
   four pages is a plate, so crop, shadow, hairline and vignette
   are decided once here instead of per section. */
.cs-plate {
  position: relative;
  isolation: isolate;
  /* Explicit, because a plate is not always a <figure>: inside the gallery's
     lightbox buttons it is a <span>, which would otherwise be inline and
     collapse the aspect-ratio box. */
  display: block;
  overflow: hidden;
  margin: 0;
  border-radius: var(--cs-plate-radius);
  background: var(--paper-warm);
  box-shadow: var(--cs-shadow-1);
}
.cs-plate > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--cs-focal, center);
}
/* Inner hairline plus a slight corner vignette, above the image
   and below any caption. This is the framed-print cue that stops
   a plate reading as a raw <img>. */
.cs-plate::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.10);
  background: radial-gradient(120% 90% at 50% 40%, transparent 58%, rgba(20,19,42,.13) 100%);
}
.cs-plate--flat::after { background: none; }
.cs-plate--deep { box-shadow: var(--cs-shadow-2); }
.cs-plate--lifted { box-shadow: var(--cs-shadow-3); }

/* Caption sits inside the plate, bottom-left, over a scrim that
   only covers the lower band — a full-plate scrim greys down the
   photograph, which is the thing being sold. */
.cs-plate__cap {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  padding: 34px 16px 13px;
  background: linear-gradient(180deg, transparent, rgba(5,5,31,.68));
  color: rgba(255,255,255,.92);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
}
.cs-plate__cap b { font-weight: 600; color: var(--gold-lit); }

/* ---------- Scene ----------
   Establishes the shared perspective. Applied only where planes
   actually overlap: a flat grid does not need a 3D context, and
   paying for one creates a stacking context for nothing. */
.cs-scene { perspective: var(--cs-persp); }
.cs-scene__stage { position: relative; transform-style: preserve-3d; }

/* Depth planes. translateZ alone changes apparent size, so each
   step compensates with scale — the plane moves in depth without
   the photograph changing how big it reads. */
.cs-plane { transform: translate3d(0, 0, var(--cs-z, 0px)) scale(var(--cs-z-scale, 1)); }
.cs-plane--back  { --cs-z: -120px; --cs-z-scale: 1.078; }
.cs-plane--mid   { --cs-z: -46px;  --cs-z-scale: 1.029; }
.cs-plane--front { --cs-z: 64px;   --cs-z-scale: .961; }

/* ---------- Signature 1: plate reveal ----------
   Gated on html.js exactly like .reveal, for the same reason:
   without scripting no curtain is drawn and every plate is fully
   visible on first paint.

   The hidden state is a CURTAIN, not a clip on the plate itself.
   That distinction is load-bearing: clip-path: inset(0 0 100% 0)
   gives the element zero intersection area, and
   IntersectionObserver — including the observer that exists to
   reveal it — then never reports it as visible. The plate stays
   unclipped and fully observable; a pseudo-element covers it and
   wipes away. It also means a caption or a focus ring inside the
   plate is never cut off by a finished animation, so there is no
   cleanup class to remember.

   z-index 3 puts it above the hairline/vignette (1) and the
   caption (2). visibility flips at the end of the transition so a
   spent curtain stops costing a composited layer — on the gallery
   that is dozens of them. */
.js [data-cs-plate]::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: var(--cs-curtain, var(--paper-warm));
  transform: scaleY(1);
  transform-origin: bottom;
  transition: transform .9s var(--ease), visibility 0s linear .9s;
}
.js [data-cs-plate].cs-in::before { transform: scaleY(0); visibility: hidden; }
.js [data-cs-plate] > img {
  transform: scale(1.085);
  transition: transform 1.25s var(--ease);
}
.js [data-cs-plate].cs-in > img { transform: none; }
/* Dark bands curtain in the band colour, or a warm-paper panel
   flashes over a navy section. */
.cs-on-dark { --cs-curtain: var(--noir); }

/* ---------- Signature 2: plane drift ----------
   --cs-drift is a -1..1 scroll progress written by main.js onto
   each plane. --cs-px / --cs-py are a -1..1 pointer position
   written ONCE onto the scene and inherited by every plane inside
   it, so a fine pointer moving across a composition costs one
   style write per frame rather than one per plane.

   Both feed the same transform, and each plane scales them by its
   own --cs-drift-mult / --cs-pointer-mult. That is what produces
   depth: the planes respond to the same input at different rates
   and in different directions. */
.js [data-cs-drift] {
  transform:
    translate3d(
      calc(var(--cs-px, 0) * var(--cs-pointer-mult, 0) * 9px),
      calc(
        var(--cs-drift, 0) * var(--cs-drift-mult, 1) * var(--cs-drift-range)
        + var(--cs-py, 0) * var(--cs-pointer-mult, 0) * 9px
      ),
      var(--cs-z, 0px)
    )
    scale(var(--cs-z-scale, 1));
  will-change: transform;
}
/* Pointer response is opt-in per plane and only on a real mouse.
   Touch reports (hover: none), and a tilt that never resets
   because there is no pointerleave is worse than no tilt. */
@media (hover: hover) and (pointer: fine) {
  .js [data-cs-drift] { --cs-pointer-mult: 1; }
  .js [data-cs-drift].cs-plane--back  { --cs-pointer-mult: .45; }
  .js [data-cs-drift].cs-plane--mid   { --cs-pointer-mult: 1; }
  .js [data-cs-drift].cs-plane--front { --cs-pointer-mult: 1.75; }
  /* The scene eases back to centre on pointerleave; without this
     the composition stays frozen wherever the cursor left it. */
  .js .cs-scene[data-cs-pointer] { transition: none; }
  .js [data-cs-drift] { transition: transform .5s var(--ease); }
  .js .cs-scene[data-cs-pointer].cs-tracking [data-cs-drift] { transition: none; }
}

/* ---------- Reduced motion ----------
   Every plate fully open, every plane at rest, no perspective
   travel. The composition is unchanged; only the movement goes. */
@media (prefers-reduced-motion: reduce) {
  .js [data-cs-plate]::before { display: none; }
  .js [data-cs-plate] > img,
  .js [data-cs-drift] { transform: none; transition: none; will-change: auto; }
  .cs-plane { transform: none; }
  .cs-scene { perspective: none; }
}

/* Touch and narrow viewports get the reveal but not the drift: a
   scroll-linked transform on a phone competes with momentum
   scrolling for the same frames, and the depth is not legible at
   that width anyway. */
@media (hover: none), (max-width: 860px) {
  .js [data-cs-drift] { transform: translate3d(0, 0, var(--cs-z, 0px)) scale(var(--cs-z-scale, 1)); will-change: auto; }
}

/* ---------- Shared inner-page chrome ---------- */
/* Rule-and-number index marker, used on all four pages. */
.cs-index {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.cs-index i { display: block; width: clamp(20px, 3vw, 44px); height: 1px; background: currentColor; opacity: .45; }

/* The standing disclosure control. One component, four pages, so
   a visitor learns it once. Kept as <details> so it works with
   scripting off and stays indexable. */
.cs-disc { border-top: 1px solid var(--line); }
.cs-disc > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  min-height: 48px;
  padding: 13px 0;
  cursor: pointer;
  list-style: none;
  color: var(--ink);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
}
.cs-disc > summary::-webkit-details-marker { display: none; }
.cs-disc > summary:focus-visible { outline: 3px solid var(--clay); outline-offset: 3px; }
.cs-disc__icon { position: relative; flex: none; width: 15px; height: 15px; }
.cs-disc__icon::before,
.cs-disc__icon::after {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  background: currentColor;
  transform: translate(-50%, -50%);
}
.cs-disc__icon::before { width: 100%; height: 1.5px; }
.cs-disc__icon::after { width: 1.5px; height: 100%; transition: opacity .3s var(--ease); }
.cs-disc[open] .cs-disc__icon::after { opacity: 0; }
.cs-disc__body { padding-bottom: 20px; }
.cs-disc__body > p {
  max-width: 68ch;
  margin-top: 12px;
  color: var(--ink-soft);
  font-size: clamp(14px, 1.15vw, 15.5px);
  line-height: 1.75;
  text-wrap: pretty;
}
.cs-disc__body > p:first-child { margin-top: 0; }
/* Dark bands invert the component rather than redeclaring it. */
.cs-on-dark .cs-disc { border-color: var(--hairline-dark); }
.cs-on-dark .cs-disc > summary { color: var(--paper); }
.cs-on-dark .cs-disc__body > p { color: rgba(255,255,255,.74); }

/* Shared inner-page section rhythm and the enquiry affordance
   that every one of these pages ends a proof run with. */
.cs-lede {
  max-width: 46ch;
  color: var(--ink-soft);
  font-size: clamp(15px, 1.3vw, 18px);
  line-height: 1.7;
  text-wrap: pretty;
}
.cs-on-dark .cs-lede { color: rgba(255,255,255,.78); }

/* ============================================================
   SERVICES HUB — THE SERVICE ATLAS  (services.php)
   ------------------------------------------------------------
   Replaces the nine-up .svc-grid card wall. The old .svc-card
   rules are deleted rather than left behind, because nothing
   else in the site rendered them.

   The rhythm is the point: three shapes (feature / tall / wide)
   in the cadence F · T T · W · F · T T · W · F, so a visitor
   scrolling the nine never meets the same tile twice in a row
   and the page never reads as a grid.
   ============================================================ */
.services-hub { overflow-x: clip; }

/* ---------- Hero ---------- */
.atlas-hero {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  min-height: min(84svh, 790px);
  padding-block: clamp(58px, 8vh, 92px) clamp(42px, 5vw, 72px);
  background:
    linear-gradient(90deg, rgba(5,5,31,.96) 0%, rgba(5,5,31,.88) 38%, rgba(5,5,31,.52) 65%, rgba(5,5,31,.32) 100%),
    var(--atlas-hero-image) center / cover no-repeat;
  color: var(--white);
}
/* The fine editorial grid is subdued beneath the copy, so it never competes
   with the background photograph. */
.atlas-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    linear-gradient(90deg, transparent 0 41.9%, rgba(255,255,255,.07) 42%, transparent 42.1%),
    linear-gradient(0deg, transparent 0 76.9%, rgba(255,255,255,.06) 77%, transparent 77.1%);
  mask-image: linear-gradient(90deg, #000, transparent 62%);
  opacity: .38;
}
.atlas-hero__grid {
  width: 100%;
}
.atlas-hero__copy { position: relative; z-index: 1; min-width: 0; max-width: 680px; }
.atlas-hero .breadcrumb { color: rgba(255,255,255,.84); }
.atlas-hero__kicker { color: var(--gold-lit); margin-bottom: 20px; }
.atlas-hero h1 {
  max-width: 13ch;
  font-size: clamp(40px, 5.4vw, 78px);
  line-height: .98;
  letter-spacing: -.035em;
  margin-bottom: clamp(16px, 2.2vw, 26px);
}
.atlas-hero__lede {
  max-width: 46ch;
  color: rgba(255,255,255,.82);
  font-size: clamp(16px, 1.5vw, 20px);
  line-height: 1.6;
  text-wrap: pretty;
}
.atlas-hero__scope {
  max-width: 42ch;
  margin-top: 18px;
  color: var(--gold-lit);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .14em;
  line-height: 1.65;
  text-transform: uppercase;
}
.atlas-hero__scope span { margin-inline: 6px; color: rgba(255,255,255,.42); }
.atlas-hero__actions {
  display: grid;
  grid-template-columns: auto auto;
  align-items: center;
  justify-content: start;
  gap: 14px 26px;
  margin-top: clamp(26px, 3.6vw, 42px);
}
.atlas-hero__actions .btn {
  min-height: 52px;
  border: 1px solid var(--white);
  background: var(--white);
  color: var(--ink);
  box-shadow: 0 8px 24px rgba(0,0,0,.2);
}
.atlas-hero__actions .btn:hover,
.atlas-hero__actions .btn:focus-visible {
  border-color: var(--gold-lit);
  background: var(--gold-lit);
  color: var(--ink);
}
.atlas-hero__jump {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  border-bottom: 1px solid rgba(255,255,255,.38);
  color: var(--white);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
}
.atlas-hero__jump span { transition: transform .3s var(--ease); }
.atlas-hero__jump:hover span, .atlas-hero__jump:focus-visible span { transform: translateY(3px); }

/* ---------- Section scaffolding ---------- */
.atlas-section, .atlas-work { padding-block: clamp(48px, 6vw, 84px); }
.atlas-section { background: var(--paper); scroll-margin-top: 72px; }
.atlas-work { background: var(--white); border-top: 1px solid var(--line); }

.atlas-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, .82fr);
  gap: clamp(22px, 4vw, 68px);
  align-items: end;
  margin-bottom: clamp(34px, 5vw, 62px);
}
.atlas-head__kicker { color: var(--clay); margin-bottom: 16px; }
.atlas-head .section-title { margin-bottom: 0; max-width: 16ch; }
.atlas-head__lede {
  color: var(--ink-soft);
  font-size: clamp(14px, 1.15vw, 16px);
  line-height: 1.75;
  text-wrap: pretty;
}

/* ---------- Service directory ---------- */
.service-directory__head {
  max-width: 780px;
  margin-bottom: clamp(28px, 4vw, 48px);
}
.service-directory__head .section-title {
  max-width: 18ch;
  margin-bottom: 16px;
}
.service-directory__lede {
  max-width: 64ch;
  color: var(--ink-soft);
  font-size: clamp(15px, 1.25vw, 17px);
  line-height: 1.7;
  text-wrap: pretty;
}

.service-paths {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-bottom: clamp(52px, 7vw, 88px);
  border-block: 1px solid var(--line);
}
.service-paths a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  min-height: 72px;
  padding: 14px clamp(16px, 2.4vw, 30px);
  color: var(--ink);
  text-decoration: none;
  transition: background-color .24s var(--ease), color .24s var(--ease);
}
.service-paths a + a { border-left: 1px solid var(--line); }
.service-paths a:hover,
.service-paths a:focus-visible { background: var(--ink); color: var(--white); }
.service-paths a:focus-visible { outline: 3px solid var(--clay); outline-offset: 3px; }
.service-paths span { font-size: clamp(17px, 1.5vw, 21px); font-weight: 600; letter-spacing: -.02em; }
.service-paths small { color: var(--clay); font-size: 10px; font-weight: 700; letter-spacing: .13em; text-transform: uppercase; white-space: nowrap; }

.service-groups { display: grid; gap: clamp(72px, 9vw, 122px); }
.service-group { scroll-margin-top: 108px; }
.service-group__head {
  max-width: 690px;
  margin-bottom: clamp(24px, 3.4vw, 38px);
}
.service-group__head h3 {
  margin-bottom: 10px;
  font: 400 clamp(30px, 3.3vw, 48px)/1.08 'Fraunces', Georgia, serif;
  letter-spacing: -.035em;
}
.service-group__head p {
  max-width: 62ch;
  color: var(--ink-soft);
  font-size: clamp(14px, 1.1vw, 16px);
  line-height: 1.7;
}

.service-wall {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(18px, 2.2vw, 30px);
  margin: 0;
  padding: 0;
  list-style: none;
}
.service-wall__item { min-width: 0; }
.service-wall__item--lead { grid-column: span 7; }
.service-wall__item--side { grid-column: span 5; }
.service-wall__item--wide { grid-column: 1 / -1; }
.service-wall__link {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--ink);
  text-decoration: none;
  box-shadow: 0 18px 44px rgba(20,19,42,.045);
  transition: transform .28s var(--ease), border-color .28s var(--ease), box-shadow .28s var(--ease);
}
.service-wall__link:hover,
.service-wall__link:focus-visible {
  transform: translateY(-4px);
  border-color: rgba(138,76,45,.45);
  box-shadow: 0 24px 60px rgba(20,19,42,.1);
}
.service-wall__link:active { transform: translateY(-1px); }
.service-wall__link:focus-visible { outline: 3px solid var(--clay); outline-offset: 4px; }
.service-wall__media { aspect-ratio: 16 / 10; overflow: hidden; }
.service-wall__item--side .service-wall__media { aspect-ratio: 4 / 3; }
.service-wall__item--wide .service-wall__media { aspect-ratio: 21 / 8; }
.service-wall__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .55s var(--ease);
}
.service-wall__link:hover .service-wall__media img,
.service-wall__link:focus-visible .service-wall__media img { transform: scale(1.025); }
.service-wall__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
  padding: clamp(20px, 2.5vw, 30px);
}
.service-wall__family {
  margin-bottom: 12px;
  color: var(--clay);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.service-wall__body h4 {
  max-width: 19ch;
  font-size: clamp(24px, 2.45vw, 36px);
  line-height: 1.08;
  letter-spacing: -.03em;
  text-wrap: balance;
}
.service-wall__desc {
  max-width: 52ch;
  margin-top: 12px;
  color: var(--ink-soft);
  font-size: clamp(14px, 1.08vw, 16px);
  line-height: 1.68;
  text-wrap: pretty;
}
.service-wall__cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  margin-top: auto;
  padding-top: 18px;
  color: var(--ink);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.service-wall__cta span { color: var(--clay); transition: transform .28s var(--ease); }
.service-wall__link:hover .service-wall__cta span,
.service-wall__link:focus-visible .service-wall__cta span { transform: translateX(5px); }

/* ---------- Service mosaic ----------
   Nine services, nine identical cards.

   This block used to be an art-directed 12-column mosaic: every slug
   carried its own grid-column/grid-row span, and the photograph sat
   under a dark gradient with the title printed on top of it. Two
   things retired that. First, the tiles used object-fit:cover, and
   two of the nine source files are portrait 2:3 (the villa service,
   residential construction) , cropped into a landscape tile they lost
   most of the frame. Second, nine different tile shapes made the hub
   read as a collage instead of a directory a visitor can compare down
   a column.

   The rules now: one grid, equal columns, one media ratio, and
   nothing drawn over a photograph. The per-slug
   .service-mosaic__item--<slug> class is still emitted by
   services.php, but it is a hook only , it must never set a span, a
   height or an aspect ratio again.

   The frame does still fill edge to edge (object-fit:cover). That was
   reviewed: a contain frame showed all nine photographs whole, but the
   seven landscape files sat in a band of empty paper and the two
   portrait files stranded half the card. The ratio below is chosen so
   cover crops nothing at all on seven of the nine. */
.service-mosaic-section {
  padding-block: clamp(46px, 5.5vw, 76px);
  background: var(--paper);
}
.service-mosaic__wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--page-padding);
}
.service-mosaic__intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, .72fr);
  gap: clamp(24px, 5vw, 74px);
  align-items: end;
  margin-bottom: clamp(28px, 3.4vw, 46px);
}
.service-mosaic__kicker { margin-bottom: 16px; color: var(--clay); }
.service-mosaic__intro .section-title { max-width: 15ch; margin: 0; }
.service-mosaic__lede {
  max-width: 43ch;
  margin: 0;
  color: var(--ink-soft);
  font-size: clamp(14px, 1.1vw, 16px);
  line-height: 1.72;
  text-wrap: pretty;
}
.service-mosaic {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: stretch;
  gap: clamp(14px, 1.35vw, 22px);
  margin: 0;
  padding: 0;
  list-style: none;
}
/* No item spans. Every card is one column of one row, at every width. */
.service-mosaic__item {
  min-width: 0;
  grid-column: auto;
  grid-row: auto;
}
/* Column layout so the CTA can be pushed to the foot of the card , titles wrap
   to one or two lines and the cards still line up along the bottom. */
.service-mosaic__link {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  color: var(--ink);
  text-decoration: none;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(20, 19, 42, .04), 0 8px 20px rgba(20, 19, 42, .05);
  transition: transform .34s var(--ease), box-shadow .34s var(--ease), border-color .34s var(--ease);
  cursor: pointer;
}
/* One frame ratio for all nine. 4:3 is the compromise the two portrait
   originals need , a wider frame strands them in more empty space, a narrower
   one strands the seven landscapes. */
/* 3:2, not 4:3, and the ratio is load-bearing. Seven of the nine card files are
   3:2 landscape (the other two are 2:3 portrait), so a 3:2 frame fills edge to
   edge on seven of them with nothing cropped at all , the frame and the
   photograph are the same shape. A 4:3 frame was tried first and cost every one
   of those seven a band of empty paper top and bottom.

   overflow:hidden because the sitewide .wipe entrance settles the image from
   scale(1.035); without it those few per cent spill past the frame's bottom
   border into the content area. */
.service-mosaic__media {
  position: relative;
  flex: 0 0 auto;
  min-height: 0;
  margin: 0;
  overflow: hidden;
  aspect-ratio: 3 / 2;
  background: var(--paper-warm);
  border-bottom: 1px solid var(--line);
}
/* cover, centred , the frame is filled, never letterboxed and never stretched.
   The two portrait originals (the villa service, residential construction) are
   the only files this crops: they are shown as a centred band. That is a
   deliberate trade , contain showed them whole but stranded half the card in
   empty paper, which is the state this replaced.

   The image is taken out of flow on purpose. As a flex item in flow it carried
   its own intrinsic height into the frame's min-height:auto, and those same two
   portrait files pushed their frames to 2:3 while the other seven stayed at the
   declared ratio , exactly the uneven card height this layout exists to remove.
   inset:0 pins every frame to the ratio above whatever shape the file is. */
.service-mosaic__media img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  transition: transform .6s var(--ease-soft), filter .34s ease;
}
/* One framing exception, and it is framing , not sizing. A centred band suits
   the villa stairwell: the window and the head of the stair run sit in the
   middle of that source. It does not suit the construction tower, whose crown
   sits near the top of the frame , centred, the card keeps a wall of facade and
   throws away the one detail that makes it read as a completed tower. Raise the
   band. The hook class must still never set a dimension. */
.service-mosaic__item--residential-construction .service-mosaic__media img {
  object-position: center 25%;
}

.service-mosaic__content {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  padding: clamp(16px, 1.35vw, 20px) clamp(16px, 1.35vw, 20px) clamp(12px, 1vw, 16px);
}
.service-mosaic__meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
  color: var(--ink-soft);
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.service-mosaic__meta i {
  width: 13px;
  height: 1px;
  background: var(--gold);
  transition: background .34s ease;
}
.service-mosaic__content h3 {
  margin: 0;
  color: var(--ink);
  font-family: 'Montserrat', Arial, sans-serif;
  font-size: clamp(19px, 1.45vw, 24px);
  font-weight: 500;
  line-height: 1.16;
  letter-spacing: -.028em;
  text-wrap: balance;
}
/* margin-top:auto is what aligns the CTA across a row whose titles wrap to
   different depths. */
.service-mosaic__cta {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  margin: auto 0 0;
  padding-top: 16px;
  color: var(--clay);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.service-mosaic__arrow {
  font-size: 15px;
  line-height: 1;
  transition: transform .3s var(--ease);
}
/* Hover lifts the card and nudges the arrow. The image itself never scales ,
   scaling it inside a contain frame would push its edges out of view, which is
   exactly what this layout exists to prevent. */
.service-mosaic__link:hover,
.service-mosaic__link:focus-visible {
  transform: translateY(-4px);
  border-color: rgba(20, 19, 42, .18);
  box-shadow: 0 4px 10px rgba(20, 19, 42, .05), 0 18px 40px rgba(20, 19, 42, .11);
}
.service-mosaic__link:hover .service-mosaic__media img,
.service-mosaic__link:focus-visible .service-mosaic__media img {
  filter: saturate(1.04) brightness(1.02);
  transform: scale(1.035);
}
.service-mosaic__link:hover .service-mosaic__arrow,
.service-mosaic__link:focus-visible .service-mosaic__arrow { transform: translateX(4px); }
.service-mosaic__link:hover .service-mosaic__meta i,
.service-mosaic__link:focus-visible .service-mosaic__meta i { background: var(--clay); }
.service-mosaic__link:focus-visible {
  outline: 3px solid var(--clay);
  outline-offset: 3px;
}
.service-mosaic__link:active { transform: translateY(-1px); }

@media (max-width: 1100px) {
  .service-mosaic { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 640px) {
  .service-mosaic-section { padding-block: 38px; }
  .service-mosaic {
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
  }
  .service-mosaic__link { border-radius: 10px; }
  .service-mosaic__content h3 { font-size: clamp(21px, 5.4vw, 26px); }
}

/* ---------- Proof ---------- */
.atlas-proof {
  padding-block: clamp(46px, 5.5vw, 76px);
  background: var(--ink);
  color: var(--paper);
}
.atlas-proof__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(28px, 4vw, 64px);
  align-items: start;
}
.atlas-proof__intro .cs-index { color: var(--gold-lit); margin-bottom: 16px; }
.atlas-proof .section-title { color: var(--white); max-width: 12ch; margin-bottom: 0; }
.atlas-proof__figures { display: grid; gap: 22px; margin: 0; }
.atlas-proof__figures div { display: grid; gap: 6px; padding-bottom: 18px; border-bottom: 1px solid var(--hairline-dark); }
.atlas-proof__figures dt { color: rgba(255,255,255,.6); font-size: 9.5px; font-weight: 700; letter-spacing: .17em; text-transform: uppercase; order: 2; }
.atlas-proof__figures dd { margin: 0; color: var(--paper); font: 400 clamp(34px, 3.6vw, 54px)/1 'Fraunces', Georgia, serif; letter-spacing: -.04em; order: 1; }
.atlas-proof__clients { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; }
.atlas-proof__clients li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px 16px;
  padding: 14px 0;
  border-bottom: 1px solid var(--hairline-dark);
}
.atlas-proof__clients li:first-child { border-top: 1px solid var(--hairline-dark); }
.atlas-proof__clients span:first-child { color: var(--white); font-size: clamp(15px, 1.3vw, 18px); }
.atlas-proof__clients span:last-child { color: rgba(255,255,255,.55); font-size: 9.5px; font-weight: 700; letter-spacing: .15em; text-transform: uppercase; }

/* ---------- Project index ---------- */
.atlas-work__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: clamp(22px, 2.8vw, 36px);
  margin: 0 0 clamp(34px, 4vw, 56px);
  padding: 0;
  list-style: none;
}
.atlas-work__item { display: flex; flex-direction: column; min-width: 0; scroll-margin-top: 96px; }
.atlas-work__media { aspect-ratio: 3 / 2; margin-bottom: 18px; }
/* The two projects with no photography supplied. They keep a frame
   so the row still reads as a set, but the frame is empty paper
   with a rule — not a borrowed photograph. */
.atlas-work__item--textual .atlas-work__body { padding-top: 22px; border-top: 2px solid var(--ink); }
.atlas-work__sector { color: var(--clay); font-size: 10px; font-weight: 700; letter-spacing: .15em; text-transform: uppercase; }
.atlas-work__body h3 { margin: 10px 0 8px; font-size: clamp(20px, 1.9vw, 26px); line-height: 1.16; text-wrap: balance; }
.atlas-work__desc { color: var(--ink-soft); font-size: clamp(13px, 1.05vw, 14.5px); line-height: 1.7; text-wrap: pretty; }
.atlas-work__link { margin-top: 12px; }
.atlas-work__link a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  color: var(--ink);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--line);
  transition: color .3s var(--ease), border-color .3s var(--ease);
}
.atlas-work__link a:hover, .atlas-work__link a:focus-visible { color: var(--clay); border-color: var(--clay); }

/* ---------- The gate into /gallery ---------- */
.atlas-gate {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, .92fr);
  gap: clamp(24px, 4vw, 60px);
  align-items: center;
  overflow: hidden;
  padding: clamp(34px, 4.6vw, 64px) clamp(24px, 4vw, 58px);
  border-radius: var(--cs-plate-radius);
  background: var(--noir);
  color: var(--white);
  text-decoration: none;
}
.atlas-gate:focus-visible { outline: 3px solid var(--gold); outline-offset: 4px; }
.atlas-gate__copy { display: grid; gap: 16px; justify-items: start; min-width: 0; }
.atlas-gate__copy .cs-index { color: var(--gold-lit); }
.atlas-gate__title {
  max-width: 15ch;
  font: 400 clamp(28px, 3.6vw, 52px)/1.04 'Fraunces', Georgia, serif;
  letter-spacing: -.03em;
  text-wrap: balance;
}
.atlas-gate__cue {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  border-bottom: 1px solid rgba(255,255,255,.4);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.atlas-gate__cue span { transition: transform .35s var(--ease); }
.atlas-gate:hover .atlas-gate__cue span, .atlas-gate:focus-visible .atlas-gate__cue span { transform: translateX(6px); }

/* Three overlapping plates, fanned. Decorative, so they carry no
   alt and no caption; the deck exists to say "there are more
   photographs through here" in one glance. */
.atlas-gate__deck { position: relative; aspect-ratio: 2 / 1; min-width: 0; }
.atlas-gate__plate { position: absolute; display: block; transition: transform .6s var(--ease); }
.atlas-gate__plate--a { left: 0;   top: 14%;  width: 40%; aspect-ratio: 3 / 4; transform: rotate(-5deg); }
.atlas-gate__plate--b { left: 30%; top: 0;    width: 46%; aspect-ratio: 3 / 2; z-index: 2; }
.atlas-gate__plate--c { right: 0;  bottom: 6%; width: 38%; aspect-ratio: 4 / 5; transform: rotate(4.5deg); z-index: 3; }
@media (hover: hover) and (pointer: fine) {
  .atlas-gate:hover .atlas-gate__plate--a { transform: rotate(-7.5deg) translate3d(-6px, -6px, 0); }
  .atlas-gate:hover .atlas-gate__plate--b { transform: translate3d(0, -9px, 0); }
  .atlas-gate:hover .atlas-gate__plate--c { transform: rotate(7deg) translate3d(6px, -4px, 0); }
}

/* ---------- Responsive ---------- */
@media (max-width: 1100px) {
  .atlas-proof__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .atlas-proof__intro { grid-column: 1 / -1; }
}

@media (max-width: 860px) {
  .atlas-hero { min-height: 0; padding-block: clamp(46px, 8vw, 72px) clamp(34px, 6vw, 56px); }
  .atlas-hero h1 { font-size: clamp(52px, 12vw, 92px); }
  .atlas-hero__lede { max-width: 40ch; }
  .atlas-hero { background-position: 62% center; }

  .atlas-head { grid-template-columns: minmax(0, 1fr); gap: 16px; align-items: start; }
  .atlas-head .section-title { max-width: 20ch; }
  .service-mosaic__intro { grid-template-columns: minmax(0, 1fr); gap: 14px; align-items: start; }

  .service-wall__item--lead,
  .service-wall__item--side { grid-column: span 6; }
  .service-wall__item--wide { grid-column: 1 / -1; }
  .service-wall__media,
  .service-wall__item--side .service-wall__media { aspect-ratio: 4 / 3; }
  .service-wall__item--wide .service-wall__media { aspect-ratio: 16 / 7; }

  .atlas-gate { grid-template-columns: minmax(0, 1fr); }
  .atlas-gate__deck { order: -1; aspect-ratio: 5 / 2; }
}

@media (max-width: 560px) {
  .atlas-section { scroll-margin-top: 67px; }
  .atlas-hero h1 { font-size: clamp(46px, 15vw, 68px); }
  .atlas-hero__scope { margin-top: 14px; font-size: 9px; letter-spacing: .11em; }
  .atlas-hero__actions { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); width: 100%; gap: 10px; }
  .atlas-hero__actions .btn { justify-content: center; padding-inline: 12px; }
  .atlas-hero__jump { justify-content: center; min-width: 0; font-size: 10px; letter-spacing: .1em; }

  .service-paths { grid-template-columns: minmax(0, 1fr); }
  .service-paths a { min-height: 64px; padding-inline: 12px; }
  .service-paths a + a { border-left: 0; border-top: 1px solid var(--line); }
  .service-wall__item--lead,
  .service-wall__item--side,
  .service-wall__item--wide { grid-column: 1 / -1; }
  .service-wall__media,
  .service-wall__item--side .service-wall__media,
  .service-wall__item--wide .service-wall__media { aspect-ratio: 4 / 3; }
  .service-wall__body { padding: 20px; }
  .service-wall__body h4 { font-size: clamp(24px, 7vw, 30px); }

  .atlas-proof__grid { grid-template-columns: minmax(0, 1fr); }
  .atlas-proof__figures { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
  .atlas-proof__figures div { padding-bottom: 12px; }
  .atlas-proof__figures dd { font-size: clamp(24px, 8vw, 34px); }
  .atlas-proof__figures dt { font-size: 8px; letter-spacing: .12em; }

  .atlas-gate__deck { aspect-ratio: 3 / 2; }
}

@media (prefers-reduced-motion: reduce) {
  .service-mosaic__link,
  .service-mosaic__media img,
  .service-mosaic__meta i,
  .service-mosaic__arrow,
  .service-wall__link,
  .service-wall__media img,
  .service-wall__cta span,
  .atlas-gate__plate,
  .atlas-hero__jump span,
  .atlas-gate__cue span { transition: none; }
  .service-wall__link:hover,
  .service-wall__link:focus-visible,
  .service-wall__link:active,
  .service-wall__link:hover .service-wall__media img,
  .service-wall__link:focus-visible .service-wall__media img { transform: none; }
  /* The lift and the arrow travel go; the shadow, border and gold rule still
     change, so the hovered/focused state is still legibly a state. */
  .service-mosaic__link:hover,
  .service-mosaic__link:focus-visible,
  .service-mosaic__link:active,
  .service-mosaic__link:hover .service-mosaic__arrow,
  .service-mosaic__link:focus-visible .service-mosaic__arrow { transform: none; }
}

/* ============================================================
   SERVICE DETAIL — ONE SYSTEM, NINE PERSONALITIES
   (services/service-page-template.php)
   ------------------------------------------------------------
   Everything below is scoped to .svcx. There is no per-page block
   anywhere in this stylesheet and there must not be one: a tenth
   vertical needs a row in the PHP variant table and nothing here.

   The variation is driven by exactly two attributes —
   data-mood on <main>, and one modifier on the project band. The
   moods are temperaments, not themes: same palette, same type,
   same plates. What changes is pacing, density, rule weight and
   how the project band is ordered.

   THE SPINE. One brass hairline runs down the left edge of the
   capability chapter, marks the head of each block, and reappears
   as the rule above each case-study title. It is the drawing-set
   line an interior designer works against — hierarchy, not
   decoration, and the only ornament this system adds.

   NO NEW COLOURS. --noir and --clay are the deep indigos,
   --paper-warm the warm stone, --gold / --gold-lit the brass,
   --ink-soft the charcoal text. Nothing below introduces a value
   the brand did not already own.
   ============================================================ */
.svcx {
  overflow-x: clip;

  /* The vertical rhythm of the whole page. Every band uses one of
     these two, never a hand-picked number. */
  --svcx-band:       clamp(56px, 7.6vw, 106px);
  --svcx-band-tight: clamp(38px, 4.6vw, 64px);
  /* The one column gutter. */
  --svcx-gap:        clamp(28px, 4.4vw, 72px);
  /* Radius. Deliberately close to the homepage's 9-10px cards
     rather than the 20px+ that makes architecture photography
     look like app tiles. Three steps, used everywhere. */
  --svcx-r-ui:       8px;
  --svcx-r-media:    clamp(10px, 1.1vw, 14px);
  --svcx-r-panel:    clamp(14px, 1.6vw, 20px);
  --svcx-spine:      var(--gold);
  /* Height of the sticky global header, so the anchor nav parks
     against it and headings clear both when jumped to. */
  --svcx-nav-top:    72px;
}
.svcx a:focus-visible,
.svcx summary:focus-visible,
.svcx button:focus-visible { outline: 3px solid var(--clay); outline-offset: 4px; }
.svcx-band--dark a:focus-visible,
.svcx-cta a:focus-visible,
.svcx-hero a:focus-visible { outline-color: var(--gold-lit); }

/* Anything the anchor nav can jump to clears the header AND the
   nav bar itself, so a jumped-to heading is never parked under
   the chrome that took you there. */
.svcx [id] { scroll-margin-top: calc(var(--svcx-nav-top) + 62px); }

/* ---------- Hero ----------
   Every service uses one service-specific hero photograph as its background.
   A graduated indigo overlay preserves text contrast while leaving the room
   visible on the right side of the composition. */
.svcx-hero {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  min-height: min(82svh, 780px);
  padding-block: clamp(56px, 8vh, 104px) clamp(44px, 6vh, 82px);
  background:
    linear-gradient(90deg, rgba(5,5,31,.96) 0%, rgba(5,5,31,.88) 38%, rgba(5,5,31,.52) 65%, rgba(5,5,31,.32) 100%),
    var(--svcx-hero-image) center / cover no-repeat;
  color: var(--white);
}
/* Fine editorial grid, kept subtle so it never competes with the photograph. */
.svcx-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    linear-gradient(90deg, transparent 0 43.9%, rgba(255,255,255,.06) 44%, transparent 44.1%),
    linear-gradient(0deg, transparent 0 78.9%, rgba(255,255,255,.05) 79%, transparent 79.1%);
  mask-image: linear-gradient(90deg, #000, transparent 62%);
  opacity: .38;
}
.svcx-hero__grid {
  width: 100%;
}
.svcx-hero__copy { position: relative; z-index: 1; min-width: 0; max-width: 680px; }
.svcx-hero .breadcrumb { color: rgba(255,255,255,.84); }
.svcx-hero__kicker { color: var(--gold-lit); margin-bottom: 18px; }
.svcx-hero h1 {
  max-width: 13ch;
  font-size: clamp(40px, 5.4vw, 78px);
  line-height: .98;
  letter-spacing: -.035em;
  margin-bottom: clamp(14px, 2vw, 22px);
  text-wrap: balance;
}
.svcx-hero__lede {
  max-width: 46ch;
  color: rgba(255,255,255,.82);
  font-size: clamp(15px, 1.35vw, 18.5px);
  line-height: 1.62;
  text-wrap: pretty;
}
.svcx-hero__actions {
  display: grid;
  grid-template-columns: auto auto;
  align-items: center;
  justify-content: start;
  gap: 14px 24px;
  margin-top: clamp(24px, 3.2vw, 38px);
}
.svcx-hero__actions .btn {
  min-height: 52px;
  border: 1px solid var(--white);
  background: var(--white);
  color: var(--ink);
  box-shadow: 0 12px 28px rgba(0,0,0,.26);
}
.svcx-hero__actions .btn:hover,
.svcx-hero__actions .btn:focus-visible {
  border-color: var(--gold-lit);
  background: var(--gold-lit);
  color: var(--ink);
  transform: translateY(-2px);
}
.svcx-hero__jump {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  border-bottom: 1px solid rgba(255,255,255,.8);
  color: var(--white);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
  text-shadow: 0 1px 10px rgba(0,0,0,.52);
  transition: border-color .3s var(--ease), color .3s var(--ease);
}
.svcx-hero__jump span { transition: transform .3s var(--ease); }
.svcx-hero__jump:hover, .svcx-hero__jump:focus-visible { border-color: var(--gold-lit); color: var(--gold-lit); }
.svcx-hero__jump:hover span, .svcx-hero__jump:focus-visible span { transform: translateY(3px); }

/* ---------- Anchor nav ----------
   Real links, sticky under the global header. It is a <nav> of
   anchors, so it works with scripting off; main.js only adds the
   active-stop class. */
.svcx-nav {
  position: sticky;
  top: var(--svcx-nav-top);
  z-index: 4;
  /* Solid first: color-mix() is unsupported in Safari below 16.2 and in older
     Chromium, where an unsupported value drops the whole declaration and the
     bar would go transparent over the content scrolling beneath it. */
  background: var(--white);
  background: color-mix(in srgb, var(--white) 88%, transparent);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border-bottom: 1px solid var(--line);
}
.svcx-nav__list {
  display: flex;
  gap: clamp(4px, 1.4vw, 26px);
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.svcx-nav__list::-webkit-scrollbar { display: none; }
.svcx-nav__list a {
  display: inline-flex;
  align-items: center;
  min-height: 46px;
  padding: 0 2px;
  border-bottom: 2px solid transparent;
  color: var(--ink-soft);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color .28s var(--ease), border-color .28s var(--ease);
}
.svcx-nav__list a:hover,
.svcx-nav__list a:focus-visible { color: var(--ink); }
.svcx-nav__list a.is-current { color: var(--clay); border-bottom-color: var(--svcx-spine); }

/* ---------- Shared band scaffolding ----------
   The rhythm of the page, decided once. Dark hero, then a
   deliberate alternation of paper, white and warm stone, then a
   dark close — so no page is nine white bands in a row. */
.svcx-work,
.svcx-intro,
.svcx-band,
.svcx-chapter,
.svcx-process,
.svcx-cases   { padding-block: var(--svcx-band); }
.svcx-areas   { padding-block: var(--svcx-band-tight); }

.svcx-work    { background: var(--paper); }
.svcx-intro   { background: var(--white);      border-top: 1px solid var(--line); }
.svcx-chapter { background: var(--paper-warm); border-top: 1px solid var(--line); }
.svcx-process { background: var(--paper);      border-top: 1px solid var(--line); }
.svcx-cases   { background: var(--white);      border-top: 1px solid var(--line); }
.svcx-band    { background: var(--white);      border-top: 1px solid var(--line); }
.svcx-areas   { background: var(--paper); border-block: 1px solid var(--line); }
.svcx-band--dark { background: var(--clay); color: var(--paper); border-top: 0; }
.svcx-band--dark .section-title { color: var(--white); }

.svcx-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, .78fr);
  gap: clamp(18px, 4vw, 60px);
  align-items: end;
  margin-bottom: clamp(28px, 4.2vw, 52px);
}
.svcx-head__kicker { color: var(--clay); margin-bottom: 14px; }
.svcx-band--dark .svcx-head__kicker,
.cs-on-dark .svcx-head__kicker { color: var(--gold-lit); }
.svcx-head .section-title { margin-bottom: 0; }
.svcx-head__lede {
  color: var(--ink-soft);
  font-size: clamp(13.5px, 1.1vw, 15.5px);
  line-height: 1.72;
  text-wrap: pretty;
}
.svcx-band__head { margin-bottom: clamp(24px, 3.4vw, 42px); }

.svcx-lead {
  max-width: 66ch;
  margin-top: 18px;
  color: var(--ink-soft);
  font-size: clamp(15px, 1.35vw, 17.5px);
  line-height: 1.74;
  text-wrap: pretty;
}
.svcx-band--dark .svcx-lead { color: rgba(255,255,255,.82); }
.svcx-disc { max-width: 66ch; margin-top: 22px; }
.svcx-band--dark .svcx-disc { border-top-color: var(--hairline-dark); }
.svcx-band--dark .svcx-disc > summary { color: var(--white); }
.svcx-band--dark .cs-disc__icon::before,
.svcx-band--dark .cs-disc__icon::after { background: var(--gold-lit); }
.svcx-band--dark .cs-disc__body p { color: rgba(255,255,255,.76); }

/* ---------- Project band ----------
   One cell shape for all six layouts: a plate, then a caption
   that is ALWAYS visible. Nothing here is revealed on hover, so a
   touch screen loses nothing a desktop has. Hover only eases the
   photograph. */
.svcx-work__set { display: grid; gap: clamp(18px, 2.3vw, 32px); margin: 0; padding: 0; list-style: none; }
.svcx-work__cell { display: flex; flex-direction: column; min-width: 0; }
.svcx-work__fig { display: flex; flex-direction: column; margin: 0; height: 100%; }
.svcx-work__plate {
  width: 100%;
  aspect-ratio: 3 / 2;
  border-radius: var(--svcx-r-media);
}
.svcx-work__plate img { transition: transform .8s var(--ease-soft); }
@media (hover: hover) and (pointer: fine) {
  .svcx-work__cell:hover .svcx-work__plate img,
  .svcx-work__cell:focus-within .svcx-work__plate img { transform: scale(1.035); }
}
.svcx-work__cap {
  display: grid;
  gap: 5px;
  padding-top: 14px;
  min-width: 0;
}
.svcx-work__sector {
  color: var(--clay);
  /* 11px, not 10: this file sets 11px as the site's floor for the
     tracked-uppercase label tier and enforces it on small screens
     further down. Meeting it here means the label never changes
     size across a breakpoint. */
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.svcx-work__name {
  color: var(--ink);
  font-size: clamp(15px, 1.3vw, 18px);
  font-weight: 600;
  line-height: 1.24;
  letter-spacing: -.02em;
}
.svcx-work__line {
  max-width: 46ch;
  color: var(--ink-soft);
  font-size: clamp(13px, 1.05vw, 14.5px);
  line-height: 1.6;
  text-wrap: pretty;
}
.svcx-work__through {
  display: flex;
  width: 100%;
  max-width: none;
  justify-content: center;
  align-items: center;
  text-align: center;
  margin: clamp(28px, 3.4vw, 44px) 0 0;
}
.svcx-work__through a {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
  transition: color .3s var(--ease), border-color .3s var(--ease);
}
.svcx-work__through a span { transition: transform .3s var(--ease); }
.svcx-work__through a:hover, .svcx-work__through a:focus-visible { color: var(--clay); border-color: var(--clay); }
.svcx-work__through a:hover span, .svcx-work__through a:focus-visible span { transform: translateX(4px); }
.svcx-work__through .svcx-work__gallery-button {
  justify-content: center;
  min-height: 48px;
  padding: 12px 20px;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--white);
}
.svcx-work__through .svcx-work__gallery-button:hover,
.svcx-work__through .svcx-work__gallery-button:focus-visible {
  border-color: var(--clay);
  background: var(--clay);
  color: var(--white);
}

/* --- mosaic: irregular and flowing. Residential. ---
   The repeating unit is FIVE cells on a 6-column field, and that
   is arithmetic rather than taste: 4,2,2,2,2 spans exactly 12 —
   two clean rows per unit, at any image count. A six-cell unit
   spans 14, which is not a whole number of rows, and every third
   row ends one column short. */
.svcx-work--mosaic .svcx-work__set { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.svcx-work--mosaic .svcx-work__cell { grid-column: span 2; }
.svcx-work--mosaic .svcx-work__cell:nth-child(5n + 1) { grid-column: span 4; }
/* Paired so the two tiles sharing a row resolve to nearly the
   same height: 4 columns at 3:2 = 2.67 units, 2 columns at 4:5 =
   2.5 units. */
.svcx-work--mosaic .svcx-work__cell:nth-child(5n + 1) .svcx-work__plate { aspect-ratio: 3 / 2; }
.svcx-work--mosaic .svcx-work__cell:nth-child(5n + 2) .svcx-work__plate { aspect-ratio: 4 / 5; }
.svcx-work--mosaic .svcx-work__cell:nth-child(5n + 3) .svcx-work__plate { aspect-ratio: 1 / 1; }
.svcx-work--mosaic .svcx-work__cell:nth-child(5n + 4) .svcx-work__plate { aspect-ratio: 4 / 5; }
.svcx-work--mosaic .svcx-work__cell:nth-child(5n + 5) .svcx-work__plate { aspect-ratio: 1 / 1; }

/* --- gallery: tall frames, generous scale, slow pacing. Villa, Luxury. --- */
.svcx-work--gallery .svcx-work__set {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(26px, 4vw, 64px) clamp(20px, 3vw, 48px);
}
.svcx-work--gallery .svcx-work__plate { aspect-ratio: 4 / 5; }
.svcx-work--gallery .svcx-work__cell:nth-child(4n + 1) .svcx-work__plate { aspect-ratio: 3 / 4; }
/* Every second frame drops, so the two columns never run level
   and the eye travels rather than scanning rows. */
.svcx-work--gallery .svcx-work__cell:nth-child(even) { transform: translateY(clamp(20px, 3.4vw, 54px)); }

/* --- rhythm: even, modular, calm. Healthcare. --- */
.svcx-work--rhythm .svcx-work__set { grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr)); }
.svcx-work--rhythm .svcx-work__plate { aspect-ratio: 3 / 2; }

/* --- uniform: one consistent frame for a residential portfolio. ---
   A fixed two-column grid makes each selected room equally legible.
   The crops use the same 4:3 proportion, so a photograph never gains
   visual weight simply because its tile is taller or wider. */
.svcx-work--uniform .svcx-work__set { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.svcx-work--uniform .svcx-work__plate { aspect-ratio: 4 / 3; }
.svcx-work--uniform .svcx-work__fig {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  border-radius: var(--svcx-r-media);
}
.svcx-work--uniform .svcx-work__plate {
  border-radius: inherit;
  box-shadow: none;
}
.svcx-work--uniform .svcx-work__cap {
  position: absolute;
  z-index: 2;
  inset: auto 0 0;
  box-sizing: border-box;
  width: 100%;
  gap: 4px;
  padding: 38px 18px 16px;
  background: linear-gradient(to top, rgba(7, 7, 35, .9), rgba(7, 7, 35, 0));
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
  transition: opacity .24s var(--ease), transform .24s var(--ease);
}
.svcx-work--uniform .svcx-work__sector,
.svcx-work--uniform .svcx-work__name,
.svcx-work--uniform .svcx-work__line { color: var(--white); }
@media (hover: hover) and (pointer: fine) {
  .svcx-work--uniform .svcx-work__cell:hover .svcx-work__cap,
  .svcx-work--uniform .svcx-work__cell:focus-within .svcx-work__cap {
    opacity: 1;
    transform: translateY(0);
  }
}
/* --- index: disciplined civic geometry. Government. ---
   A hairline field with the cells drawn inside it, square
   corners, everything on one module. */
.svcx-work--index .svcx-work__set {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
  gap: 0;
  border: 1px solid var(--line);
  background: var(--white);
}
.svcx-work--index .svcx-work__cell {
  padding: clamp(12px, 1.4vw, 18px);
  box-shadow: inset -1px 0 0 var(--line), inset 0 -1px 0 var(--line);
}
.svcx-work--index .svcx-work__plate { aspect-ratio: 1 / 1; border-radius: 0; }
.svcx-work--index .svcx-work__cap { padding-top: 12px; }

/* --- rail: horizontal workplace movement. Commercial, Office. ---
   Reuses the existing .rail-wrap / .rail machinery and its
   prev/next buttons, so initRails in main.js needs no changes.
   The cell width leaves the next card partly visible, which is
   how a rail says "there is more" without an instruction. */
.svcx-work--rail .svcx-work__cell {
  flex: 0 0 clamp(240px, 30vw, 350px);
  scroll-snap-align: start;
}
.svcx-work--rail .svcx-work__plate { aspect-ratio: 4 / 3; }

/* --- pair: a deliberate diptych where photography is thin. --- */
.svcx-work--pair .svcx-work__set {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 48px);
  max-width: 1040px;
}
.svcx-work--pair .svcx-work__plate { aspect-ratio: 3 / 4; }
.svcx-work--pair .svcx-work__cell:nth-child(2) { transform: translateY(clamp(22px, 4vw, 62px)); }

/* ---------- Introduction ----------
   An editorial split: one statement paragraph at size against a
   detail crop. The rest of the introduction is still in the DOM
   behind the disclosure — this only changes which paragraph is
   set large. */
.svcx-intro__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  gap: var(--svcx-gap);
  align-items: center;
}
.svcx-intro__copy { min-width: 0; }
.svcx-intro__lead {
  max-width: 34ch;
  color: var(--ink);
  font-size: clamp(19px, 2.05vw, 28px);
  font-weight: 400;
  line-height: 1.36;
  letter-spacing: -.02em;
  text-wrap: pretty;
}
.svcx-intro__plate { aspect-ratio: 4 / 5; border-radius: var(--svcx-r-media); }

/* ---------- Capability index ----------
   Three kinds of content arrive mixed together in these sections
   and they each want a completely different treatment, which is
   why the page read as one undifferentiated wall of words when
   they all rendered the same way.

   A label WITH an explanation becomes a row: the label is always
   visible, the explanation opens on demand. It is a drawing
   schedule, not a card wall — and <details> keeps every word in
   the DOM, in the accessibility tree and in the index. */
.svcx-index {
  margin: clamp(24px, 3.2vw, 40px) 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}
.svcx-band--dark .svcx-index { border-color: var(--hairline-dark); }
.svcx-index__row { border-bottom: 1px solid var(--line); }
.svcx-band--dark .svcx-index__row { border-color: var(--hairline-dark); }
.svcx-index__disc > summary {
  display: grid;
  grid-template-columns: clamp(38px, 4vw, 58px) minmax(0, 1fr) 22px;
  align-items: baseline;
  gap: 14px;
  min-height: 56px;
  padding: clamp(13px, 1.5vw, 18px) 0;
  cursor: pointer;
  list-style: none;
}
.svcx-index--unnumbered .svcx-index__disc > summary { grid-template-columns: minmax(0, 1fr) 22px; gap: 16px; }
.svcx-index__disc > summary::-webkit-details-marker { display: none; }
.svcx-index__disc > summary:focus-visible { outline: 3px solid var(--clay); outline-offset: 3px; }
.svcx-index__n { color: var(--clay); font-size: 11px; font-weight: 700; letter-spacing: .14em; }
.svcx-band--dark .svcx-index__n { color: var(--gold-lit); }
.svcx-index__label {
  min-width: 0;
  font-size: clamp(16px, 1.45vw, 20px);
  line-height: 1.34;
  letter-spacing: -.015em;
  text-wrap: pretty;
  transition: color .3s var(--ease);
}
.svcx-band--dark .svcx-index__label { color: var(--white); }
.svcx-index__disc:hover .svcx-index__label,
.svcx-index__disc[open] .svcx-index__label { color: var(--clay); }
.svcx-band--dark .svcx-index__disc:hover .svcx-index__label,
.svcx-band--dark .svcx-index__disc[open] .svcx-index__label { color: var(--gold-lit); }
.svcx-index__icon { position: relative; width: 15px; height: 15px; align-self: center; }
.svcx-index__icon::before,
.svcx-index__icon::after {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  background: var(--clay);
  transform: translate(-50%, -50%);
}
.svcx-band--dark .svcx-index__icon::before,
.svcx-band--dark .svcx-index__icon::after { background: var(--gold-lit); }
.svcx-index__icon::before { width: 100%; height: 1.5px; }
.svcx-index__icon::after { width: 1.5px; height: 100%; transition: opacity .3s var(--ease); }
.svcx-index__disc[open] .svcx-index__icon::after { opacity: 0; }
.svcx-index__body { padding: 0 34px clamp(16px, 2vw, 22px) clamp(52px, 5.4vw, 72px); }
.svcx-index--unnumbered .svcx-index__body { padding-left: 0; padding-right: 22px; }
.svcx-index__body p {
  max-width: 70ch;
  color: var(--ink-soft);
  font-size: clamp(14px, 1.15vw, 15.5px);
  line-height: 1.75;
  text-wrap: pretty;
}
.svcx-band--dark .svcx-index__body p { color: rgba(255,255,255,.76); }

/* Chips and points, for labels with no explanation. Short labels
   are a set and read as chips; long ones wrap inside a pill and
   look like a broken button, so those become a ruled two-column
   index instead. The template decides which, on the longest label
   in the section. */
.svcx-chips, .svcx-points { margin: clamp(22px, 2.8vw, 34px) 0 0; padding: 0; list-style: none; }
.svcx-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.svcx-chips li {
  padding: 9px 15px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-soft);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.4;
}
.svcx-chapter .svcx-chips li { background: var(--white); }
.svcx-band--dark .svcx-chips li { border-color: var(--hairline-dark); background: transparent; color: rgba(255,255,255,.84); }
.svcx-points {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 0 clamp(24px, 4vw, 56px);
}
.svcx-points li {
  position: relative;
  padding: 13px 0 13px 26px;
  border-bottom: 1px solid var(--line);
  color: var(--ink-soft);
  font-size: clamp(14px, 1.15vw, 15.5px);
  line-height: 1.6;
}
.svcx-points li::before {
  content: '';
  position: absolute;
  left: 2px; top: 20px;
  width: 7px; height: 7px;
  border: 1px solid var(--gold);
  transform: rotate(45deg);
}
.svcx-band--dark .svcx-points li { border-color: var(--hairline-dark); color: rgba(255,255,255,.8); }

/* ---------- Capability chapter ----------
   Two or more consecutive capability sections were the flattest
   part of these pages: identical eyebrow, identical heading,
   identical white band, three and four times in a row. They are
   one chapter now — a sticky index on the left, the blocks
   running down the brass spine on the right. */
.svcx-chapter__grid {
  display: grid;
  grid-template-columns: minmax(0, .78fr) minmax(0, 1.22fr);
  gap: var(--svcx-gap);
  align-items: start;
}
.svcx-chapter__sticky { position: sticky; top: calc(var(--svcx-nav-top) + 74px); }
.svcx-chapter__nav { margin-top: clamp(20px, 2.4vw, 30px); }
.svcx-chapter__nav ul { margin: 0; padding: 0; list-style: none; }
.svcx-chapter__nav a {
  display: flex;
  align-items: center;
  min-height: 46px;
  border-top: 1px solid var(--line);
  color: var(--ink);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .02em;
  transition: color .3s var(--ease), padding-left .3s var(--ease);
}
.svcx-chapter__nav li:last-child a { border-bottom: 1px solid var(--line); }
.svcx-chapter__nav a:hover,
.svcx-chapter__nav a:focus-visible { color: var(--clay); padding-left: 6px; }

/* The spine: a hairline down the whole chapter with a brass
   segment at the head of each block, so the eye reads the brass
   ticks as the stops the index lists. */
.svcx-chapter__block {
  position: relative;
  padding-left: clamp(20px, 2.4vw, 36px);
  border-left: 1px solid var(--line);
}
.svcx-chapter__block::before {
  content: '';
  position: absolute;
  left: -1px;
  top: 0;
  width: 1px;
  height: clamp(38px, 4.6vw, 62px);
  background: var(--svcx-spine);
}
.svcx-chapter__block + .svcx-chapter__block { padding-top: clamp(38px, 4.6vw, 62px); }
.svcx-chapter__title {
  margin: 0 0 clamp(14px, 1.8vw, 22px);
  color: var(--ink);
  font-size: clamp(20px, 2vw, 27px);
  font-weight: 500;
  line-height: 1.16;
  letter-spacing: -.02em;
  text-wrap: pretty;
}
/* Inside a chapter the lists carry the block, so they start tight
   against their heading rather than at section spacing. */
.svcx-chapter__block .svcx-index,
.svcx-chapter__block .svcx-chips,
.svcx-chapter__block .svcx-points { margin-top: 0; }
.svcx-chapter__block .svcx-lead { margin-top: 0; }

/* ---------- Process ----------
   A sequence, drawn as one. Reuses the site's .timeline component
   and its scroll handler in main.js — same classes, same --draw
   variable, no second implementation — but vertical at EVERY
   width. These sections run to six, seven and eight stages, and a
   horizontal track with eight stops and a paragraph under each is
   unreadable on anything narrower than a desktop. */
.svcx-process__line { margin-top: clamp(26px, 3.2vw, 44px); }
.svcx-process .timeline-track {
  left: 8px; right: auto; top: 0; bottom: 0;
  width: 2px; height: auto;
  background: var(--line);
}
.svcx-process .timeline-track::after { transform: scaleY(var(--draw, 0)); transform-origin: center top; }
.svcx-process__steps { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; }
.svcx-process__step {
  position: relative;
  padding: 0 0 clamp(26px, 3.2vw, 46px) clamp(34px, 3.6vw, 48px);
}
.svcx-process__step:last-child { padding-bottom: 0; }
.svcx-process__step::before {
  left: 0; top: 4px;
  width: 18px; height: 18px;
  background: var(--paper);
  border: 2px solid var(--line);
}
.svcx-process__step .n { color: var(--ink-soft); }
.svcx-process__step h3 {
  margin-top: 6px;
  color: var(--ink);
  font-size: clamp(17px, 1.55vw, 22px);
  font-weight: 600;
  line-height: 1.24;
  letter-spacing: -.02em;
  text-wrap: pretty;
}
.svcx-process__step p {
  max-width: 62ch;
  margin-top: 8px;
  color: var(--ink-soft);
  font-size: clamp(14px, 1.15vw, 15.5px);
  line-height: 1.72;
  text-wrap: pretty;
}
/* Desktop: number and stage on the left, the explanation beside
   it. Two columns keep eight stages inside one screen-and-a-half
   instead of three. */
@media (min-width: 861px) {
  .svcx-process__step {
    display: grid;
    grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr);
    gap: 0 clamp(24px, 3vw, 56px);
    align-items: start;
  }
  .svcx-process__step .n { grid-column: 1; grid-row: 1; }
  .svcx-process__step h3 { grid-column: 1; grid-row: 2; margin-top: 6px; }
  .svcx-process__step p  { grid-column: 2; grid-row: 1 / span 2; margin-top: 0; }
}

/* ---------- Featured projects, as case studies ----------
   Alternating image and text on desktop; image first, then text,
   on mobile. The descriptions are long single paragraphs of
   room-by-room detail, so they are set at reading width rather
   than crushed into a card. */
.svcx-cases__set { display: grid; gap: clamp(44px, 6vw, 92px); }
.svcx-case {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(26px, 4vw, 60px);
  align-items: center;
}
/* Grid placement rather than `order`, so the DOM order stays
   image-then-text and the mobile stack needs no reversal. */
.svcx-case:nth-child(even) .svcx-case__plate { grid-column: 2; grid-row: 1; }
.svcx-case:nth-child(even) .svcx-case__body  { grid-column: 1; grid-row: 1; }
.svcx-case__plate { aspect-ratio: 4 / 3; border-radius: var(--svcx-r-media); }
.svcx-case__body { min-width: 0; }
/* A project photographed but not yet shot, or shot but not yet
   released, gets a text study at reading width — never an empty
   frame and never a borrowed photograph. */
.svcx-case--noshot { grid-template-columns: minmax(0, 1fr); max-width: 74ch; }
.svcx-case__sector {
  color: var(--clay);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}
/* The spine, arriving as a short brass rule above the name. */
.svcx-case__title::before {
  content: '';
  display: block;
  width: 42px;
  height: 2px;
  margin: clamp(12px, 1.5vw, 18px) 0 clamp(12px, 1.6vw, 18px);
  background: var(--svcx-spine);
}
.svcx-case__title {
  margin: 0 0 14px;
  color: var(--ink);
  font-size: clamp(21px, 2.2vw, 31px);
  font-weight: 500;
  line-height: 1.14;
  letter-spacing: -.025em;
  text-wrap: balance;
}
.svcx-case__copy {
  max-width: 56ch;
  color: var(--ink-soft);
  font-size: clamp(14px, 1.15vw, 16px);
  line-height: 1.75;
  text-wrap: pretty;
}

/* ---------- Areas served ----------
   A band, not another full section. Location SEO copy turns into
   a keyword cloud the moment it is set as prose; as two labelled
   runs it stays legible and useful. Priority areas carry the
   brass rule, the wider list stays quiet. */
.svcx-areas__grid {
  display: grid;
  grid-template-columns: minmax(0, .72fr) minmax(0, 1.28fr);
  gap: clamp(24px, 4vw, 64px);
  align-items: start;
}
.svcx-areas .section-title { margin-bottom: 10px; font-size: clamp(20px, 1.9vw, 27px); }
.svcx-areas__lede {
  max-width: 36ch;
  color: var(--ink-soft);
  font-size: clamp(13.5px, 1.1vw, 15px);
  line-height: 1.65;
  text-wrap: pretty;
}
.svcx-areas__cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: clamp(20px, 3vw, 48px);
}
.svcx-areas__label {
  margin: 0 0 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--gold);
  color: var(--ink);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.svcx-areas__col:not(:first-child) .svcx-areas__label { border-bottom-color: var(--line); color: var(--ink-soft); }
.svcx-areas__col ul {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 0;
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--ink-soft);
  font-size: clamp(13.5px, 1.1vw, 15px);
  line-height: 1.6;
}
/* An inline run, not pills — but each place is still its own list
   item for a screen reader. */
.svcx-areas__col li + li::before { content: '·'; margin: 0 8px; color: var(--gold); }
.svcx-areas__prose { color: var(--ink-soft); font-size: clamp(13.5px, 1.1vw, 15px); line-height: 1.7; }

/* ---------- The close ----------
   One recognisable ending on all nine pages. Only the supporting
   line changes, and it is written per vertical so the close
   speaks to what the visitor actually came for. */
.svcx-cta {
  position: relative;
  isolation: isolate;
  padding-block: clamp(58px, 8vw, 116px);
  background:
    radial-gradient(circle at 76% 12%, rgba(186,143,77,.16), transparent 30%),
    radial-gradient(circle at 8% 92%, rgba(62,70,128,.22), transparent 36%),
    var(--noir);
  color: var(--paper);
  text-align: center;
}
.svcx-cta__inner {
  max-width: 860px;
  margin-inline: auto;
  text-align: center;
}
.svcx-cta__kicker {
  width: fit-content;
  max-width: 100%;
  justify-content: center;
  margin: 0 auto 18px;
  color: var(--gold-lit);
}
.svcx-cta__title {
  max-width: 20ch;
  margin: 0 auto;
  color: var(--white);
  font-size: clamp(30px, 4.2vw, 56px);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: -.04em;
  text-wrap: balance;
}
.svcx-cta__line {
  max-width: 58ch;
  margin: clamp(18px, 2.4vw, 26px) auto 0;
  color: rgba(255,255,255,.78);
  font-size: clamp(14.5px, 1.25vw, 17px);
  line-height: 1.68;
  text-wrap: pretty;
}
.svcx-cta__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 16px 30px;
  margin-top: clamp(26px, 3.2vw, 38px);
}
/* Ivory on indigo. .btn-dark would be ink on near-ink here. */
.svcx-cta__btn {
  min-width: min(100%, 230px);
  min-height: 56px;
  justify-content: center;
  border-radius: 999px;
  background: var(--paper);
  border: 1px solid var(--paper);
  color: var(--ink);
  box-shadow: 0 12px 26px rgba(5,5,31,.28);
  transition: background-color .3s var(--ease), color .3s var(--ease), transform .3s var(--ease), box-shadow .3s var(--ease);
}
.svcx-cta__btn:hover, .svcx-cta__btn:focus-visible {
  background: var(--gold-lit);
  border-color: var(--gold-lit);
  color: var(--ink);
  transform: translateY(-3px);
  box-shadow: 0 18px 32px rgba(5,5,31,.34);
}
.svcx-cta__alt {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  border-bottom: 1px solid rgba(255,255,255,.36);
  color: var(--white);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
  transition: border-color .3s var(--ease), color .3s var(--ease);
}
.svcx-cta__alt span { transition: transform .3s var(--ease); }
.svcx-cta__alt:hover, .svcx-cta__alt:focus-visible { color: var(--gold-lit); border-color: var(--gold-lit); }
.svcx-cta__alt:hover span, .svcx-cta__alt:focus-visible span { transform: translateX(4px); }

/* ============================================================
   MOODS — the only place the nine pages diverge.
   ============================================================ */

/* Warm — residential. Paper rather than white, softer rules, the
   project band flows straight out of the hero. */
.svcx[data-mood='warm'] .svcx-work { background: var(--paper); }
.svcx[data-mood='warm'] .svcx-intro { background: var(--paper-warm); }
.svcx[data-mood='warm'] .svcx-chapter { background: var(--white); }

/* Gallery — villa and luxury. Generous scale, wider gutters,
   larger headings, more air between bands. A printed portfolio. */
.svcx[data-mood='gallery'] .svcx-work,
.svcx[data-mood='gallery'] .svcx-intro,
.svcx[data-mood='gallery'] .svcx-chapter,
.svcx[data-mood='gallery'] .svcx-cases,
.svcx[data-mood='gallery'] .svcx-band { padding-block: clamp(66px, 9.4vw, 136px); }
.svcx[data-mood='gallery'] .section-title { font-size: clamp(31px, 4.1vw, 54px); }
.svcx[data-mood='gallery'] .svcx-hero h1 { font-size: clamp(42px, 6vw, 88px); }
.svcx[data-mood='gallery'] .svcx-work { background: var(--paper-warm); }

/* Clinical — healthcare. Cooler, brighter, tighter and more even.
   Nothing is staggered or rotated: the whole point is that the
   space is orderly. */
.svcx[data-mood='clinical'] .svcx-work { background: var(--white); }
.svcx[data-mood='clinical'] .svcx-work__set { gap: clamp(16px, 1.8vw, 24px); }
.svcx[data-mood='clinical'] .cs-plate { box-shadow: var(--cs-shadow-1); }
.svcx[data-mood='clinical'] .svcx-work__plate { border-radius: 4px; }
.svcx[data-mood='clinical'] .section-title { letter-spacing: -.015em; }
.svcx[data-mood='clinical'] .svcx-intro { background: var(--paper); }

/* Civic — government. Structural: hairline grid, square corners,
   everything aligned to the same module. */
.svcx[data-mood='civic'] .svcx-work { background: var(--paper-warm); }
.svcx[data-mood='civic'] .cs-plate,
.svcx[data-mood='civic'] .svcx-hero__plate { border-radius: 0; }
.svcx[data-mood='civic'] .svcx-index__label { letter-spacing: 0; }
.svcx[data-mood='civic'] .svcx-band,
.svcx[data-mood='civic'] .svcx-process { border-top-width: 2px; border-top-color: var(--ink); }

/* Workplace — commercial and office. Horizontal energy; the rail
   carries the band on a dark ground, and the type sits tighter. */
.svcx[data-mood='workplace'] .svcx-work { background: var(--ink); color: var(--paper); --cs-curtain: var(--ink); }
.svcx[data-mood='workplace'] .svcx-work .section-title { color: var(--white); }
.svcx[data-mood='workplace'] .svcx-work .svcx-head__kicker { color: var(--gold-lit); }
.svcx[data-mood='workplace'] .svcx-work .svcx-head__lede { color: rgba(255,255,255,.74); }
.svcx[data-mood='workplace'] .svcx-work__sector { color: var(--gold-lit); }
.svcx[data-mood='workplace'] .svcx-work__name { color: var(--white); }
.svcx[data-mood='workplace'] .svcx-work__line { color: rgba(255,255,255,.72); }
.svcx[data-mood='workplace'] .svcx-work__through a { color: var(--white); border-color: rgba(255,255,255,.4); }
.svcx[data-mood='workplace'] .svcx-work__through a:hover,
.svcx[data-mood='workplace'] .svcx-work__through a:focus-visible { color: var(--gold-lit); border-color: var(--gold-lit); }
.svcx[data-mood='workplace'] .svcx-work .rail-btn { border-color: rgba(255,255,255,.34); color: var(--white); }
.svcx[data-mood='workplace'] .svcx-work .rail-btn:hover:not(:disabled) { background: var(--gold-lit); border-color: var(--gold-lit); color: var(--ink); }

/* Structural — construction. Heavier typography, stronger rules,
   square plates. The two sparse verticals live here, so the mood
   has to hold up with two photographs. */
.svcx[data-mood='structural'] .svcx-work { background: var(--paper-warm); }
.svcx[data-mood='structural'] .cs-plate,
.svcx[data-mood='structural'] .svcx-hero__plate { border-radius: 0; }
.svcx[data-mood='structural'] .section-title { letter-spacing: -.04em; }
.svcx[data-mood='structural'] .svcx-band,
.svcx[data-mood='structural'] .svcx-chapter,
.svcx[data-mood='structural'] .svcx-process { border-top-width: 2px; border-top-color: var(--ink); }

/* ============================================================
   RESPONSIVE
   Mobile is composed, not shrunk: the compositions change shape,
   the staggers come off, and the crops are chosen for a portrait
   screen rather than inherited from the desktop ratios.
   ============================================================ */
@media (max-width: 1100px) {
  .svcx-work--mosaic .svcx-work__set { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .svcx-work--mosaic .svcx-work__cell { grid-column: span 2; }
  .svcx-work--mosaic .svcx-work__cell:nth-child(5n + 1) { grid-column: span 4; }
}

/* Tablet. This range is designed, not inherited: the two-column
   editorial splits are what break first, well before the phone
   layout takes over. */
@media (max-width: 1000px) {
  .svcx-chapter__grid,
  .svcx-areas__grid { grid-template-columns: minmax(0, 1fr); }
  /* Sticky is a desktop affordance; at one column it would pin the
     index over the content it indexes. */
  .svcx-chapter__sticky { position: static; }
  .svcx-chapter__nav { display: none; }

  .svcx-case { grid-template-columns: minmax(0, 1fr); }
  .svcx-case:nth-child(even) .svcx-case__plate,
  .svcx-case:nth-child(even) .svcx-case__body { grid-column: 1; grid-row: auto; }
  .svcx-case__plate { aspect-ratio: 16 / 10; }

  .svcx-work--gallery .svcx-work__cell:nth-child(even) { transform: translateY(clamp(14px, 2.4vw, 30px)); }
}

@media (max-width: 900px) {
  .svcx { --svcx-nav-top: 66px; }
  .svcx-work--rhythm .svcx-work__set,
  .svcx-work--uniform .svcx-work__set,
  .svcx-work--index .svcx-work__set { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
  .svcx-hero {
    min-height: 0;
    padding-block: clamp(40px, 7vw, 66px) clamp(32px, 6vw, 52px);
    background-position: 62% center;
  }
  .svcx-hero h1 { max-width: 16ch; font-size: clamp(38px, 9.2vw, 62px); }
  .svcx-hero__lede { font-size: clamp(15px, 4vw, 17px); }
  .svcx-head { grid-template-columns: minmax(0, 1fr); gap: 14px; align-items: start; }
  .svcx-intro__grid { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .svcx-intro__plate { aspect-ratio: 16 / 10; order: -1; }
  .svcx-intro__lead { max-width: 38ch; }

  /* Staggers come off: at this width they only cost vertical space. */
  .svcx-work--gallery .svcx-work__cell:nth-child(even),
  .svcx-work--pair .svcx-work__cell:nth-child(2) { transform: none; }
  .svcx-work--gallery .svcx-work__set { gap: clamp(20px, 4vw, 34px); }
}

@media (max-width: 640px) {
  /* One strong frame per row, and a deliberate sequence rather
     than a column of identical squares: the anchor tile of each
     mosaic cycle stays portrait, everything after it settles to
     4:3. */
  .svcx-work--mosaic .svcx-work__set,
  .svcx-work--gallery .svcx-work__set,
  .svcx-work--rhythm .svcx-work__set,
  .svcx-work--uniform .svcx-work__set,
  .svcx-work--pair .svcx-work__set { grid-template-columns: minmax(0, 1fr); }
  .svcx-work--mosaic .svcx-work__cell,
  .svcx-work--mosaic .svcx-work__cell:nth-child(5n + 1) { grid-column: auto; }
  .svcx-work--mosaic .svcx-work__cell .svcx-work__plate,
  .svcx-work--gallery .svcx-work__plate,
  .svcx-work--rhythm .svcx-work__plate,
  .svcx-work--uniform .svcx-work__plate,
  .svcx-work--pair .svcx-work__plate { aspect-ratio: 4 / 3; }
  .svcx-work--mosaic .svcx-work__cell:nth-child(5n + 1) .svcx-work__plate { aspect-ratio: 4 / 5; }
  .svcx-work--index .svcx-work__set { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* The rail shows the edge of the next card, which is how a
     horizontal set says "there is more" without an instruction. */
  .svcx-work--rail .svcx-work__cell { flex-basis: 80vw; }

  .svcx-hero__actions {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 10px;
    width: 100%;
  }
  .svcx-hero__actions .btn { justify-content: center; padding-inline: 12px; }
  .svcx-hero__jump { justify-content: center; min-width: 0; font-size: 10px; letter-spacing: .1em; }

  .svcx-index__disc > summary { grid-template-columns: 32px minmax(0, 1fr) 20px; gap: 10px; }
  .svcx-index--unnumbered .svcx-index__disc > summary { grid-template-columns: minmax(0, 1fr) 20px; }
  .svcx-index__body { padding-left: 42px; padding-right: 0; }
  .svcx-index--unnumbered .svcx-index__body { padding-left: 0; }

  .svcx-chapter__block { padding-left: 16px; }
  .svcx-cta__actions .svcx-cta__btn {
    flex: 0 1 240px;
    inline-size: min(240px, calc(100% - 40px));
    min-width: 0;
    min-height: 52px;
    padding-inline: 18px;
    margin-inline: auto;
  }
}

/* 380px and below is the real floor — a 320px viewport with the
   page gutters leaves about 284px of content. */
@media (max-width: 380px) {
  .svcx-hero h1 { font-size: clamp(32px, 10vw, 40px); }
  .svcx-nav__list { gap: 14px; }
  .svcx-work--rail .svcx-work__cell { flex-basis: 84vw; }
  .svcx-chapter__block { padding-left: 14px; }
}

@media (prefers-reduced-motion: reduce) {
  .svcx-hero__jump span,
  .svcx-index__label,
  .svcx-index__icon::after,
  .svcx-work__plate img,
  .svcx-work__through a,
  .svcx-work__through a span,
  .svcx-chapter__nav a,
  .svcx-cta__btn,
  .svcx-cta__alt span,
  .svcx-nav__list a { transition: none; }
  .svcx-work--gallery .svcx-work__cell:nth-child(even),
  .svcx-work--pair .svcx-work__cell:nth-child(2) { transform: none; }
  .svcx-work__cell:hover .svcx-work__plate img,
  .svcx-work__cell:focus-within .svcx-work__plate img { transform: none; }
  .svcx-cta__btn:hover, .svcx-cta__btn:focus-visible { transform: none; }
  .svcx-chapter__nav a:hover, .svcx-chapter__nav a:focus-visible { padding-left: 0; }
}

/* ============================================================
   ABOUT — THE STUDIO  (about.php)
   ------------------------------------------------------------
   Replaces .page-hero + .sticky-story + .clients-band on this
   page. The old rules stay in the stylesheet because the
   homepage still uses .sticky-story and contact still uses
   .page-hero; nothing here overrides them, it simply does not
   use them.
   ============================================================ */
.studio { overflow-x: clip; }
.studio a:focus-visible,
.studio summary:focus-visible { outline: 3px solid var(--clay); outline-offset: 4px; }

/* ---------- Hero ---------- */
.studio-hero {
  position: relative;
  isolation: isolate;
  padding-block: clamp(58px, 8vh, 96px) clamp(52px, 7vw, 96px);
  background: var(--noir);
  color: var(--white);
}
.studio-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    linear-gradient(90deg, transparent 0 33.2%, rgba(255,255,255,.06) 33.3%, transparent 33.4%),
    linear-gradient(90deg, transparent 0 66.5%, rgba(255,255,255,.06) 66.6%, transparent 66.7%);
  mask-image: linear-gradient(180deg, #000, transparent 70%);
  opacity: .7;
}
.studio-hero .breadcrumb { color: rgba(255,255,255,.84); }
.studio-hero__copy { max-width: 60ch; }
.studio-hero__kicker { color: var(--gold-lit); margin-bottom: 18px; }
.studio-hero h1 {
  /* 11ch puts each of the three words on its own line on desktop without a
     <br> — see the note in about.php. */
  max-width: 11ch;
  font-size: clamp(34px, 6.6vw, 104px);
  line-height: .96;
  letter-spacing: -.038em;
  margin-bottom: clamp(16px, 2vw, 24px);
}
.studio-hero__lede {
  max-width: 52ch;
  color: rgba(255,255,255,.8);
  font-size: clamp(15px, 1.35vw, 18px);
  line-height: 1.68;
  text-wrap: pretty;
}

/* The triptych. Three plates on three planes, middle one nearest,
   so the row reads as depth rather than as a filmstrip. The labels
   are permanently visible — the whole device fails if the pillar
   names only appear on hover. */
.studio-hero__triptych {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(14px, 2.2vw, 34px);
  align-items: end;
  margin: clamp(38px, 5.5vw, 74px) 0 0;
  padding: 0;
  list-style: none;
}
.studio-pillar { min-width: 0; }
.studio-pillar__plate { width: 100%; aspect-ratio: 3 / 4; }
/* The middle pillar is the nearest plane, so it stands taller and
   sits slightly proud of its neighbours. */
.studio-pillar--1 .studio-pillar__plate { aspect-ratio: 3 / 4.5; }
.studio-pillar__label {
  display: grid;
  gap: 4px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid rgba(255,255,255,.24);
}
.studio-pillar__label span:first-child {
  color: var(--white);
  font: 400 clamp(19px, 2vw, 29px)/1.1 'Fraunces', Georgia, serif;
  letter-spacing: -.02em;
}
.studio-pillar__label span:last-child {
  color: rgba(255,255,255,.6);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
}

/* ---------- Shared band scaffolding ---------- */
.studio-story, .studio-process { padding-block: clamp(58px, 8vw, 112px); }
.studio-story { background: var(--paper); }
.studio-process { background: var(--white); border-block: 1px solid var(--line); }

.studio-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, .8fr);
  gap: clamp(20px, 4vw, 62px);
  align-items: end;
  margin-bottom: clamp(34px, 5vw, 64px);
}
.studio-head__kicker { color: var(--clay); margin-bottom: 14px; }
.cs-on-dark .studio-head__kicker { color: var(--gold-lit); }
.studio-head .section-title { margin-bottom: 0; }
.studio-head__lede { color: var(--ink-soft); font-size: clamp(13.5px, 1.1vw, 16px); line-height: 1.74; text-wrap: pretty; }
.cs-on-dark .studio-head__lede { color: rgba(255,255,255,.74); }

/* ---------- Story beats ---------- */
.studio-beats { display: grid; gap: clamp(48px, 8vw, 128px); margin: 0; padding: 0; list-style: none; }
.studio-beat {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: clamp(26px, 5vw, 78px);
  align-items: center;
}
/* Alternate sides so the sequence reads as a reel rather than a list. */
.studio-beat:nth-child(even) { grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr); }
.studio-beat:nth-child(even) .studio-beat__frames { order: 2; }

/* Two overlapping frames. The aside is positioned as a percentage of
   the pair, and the pair is a ratio box, so the offset frame can
   never spill into the beat above or below at any width. */
.studio-beat__frames { position: relative; aspect-ratio: 3 / 2.25; min-width: 0; }
.studio-beat__main { position: absolute; left: 0; top: 0; width: 82%; aspect-ratio: 3 / 2; }
.studio-beat__aside { position: absolute; right: 0; bottom: 0; width: 38%; aspect-ratio: 3 / 4; z-index: 2; }
.studio-beat:nth-child(even) .studio-beat__main { left: auto; right: 0; }
.studio-beat:nth-child(even) .studio-beat__aside { right: auto; left: 0; }

.studio-beat__copy { min-width: 0; }
.studio-beat__n { color: var(--clay); margin-bottom: 16px; }
.studio-beat__copy h3 {
  max-width: 15ch;
  font-size: clamp(25px, 3.1vw, 44px);
  line-height: 1.08;
  letter-spacing: -.028em;
  text-wrap: balance;
}
.studio-beat__copy p {
  max-width: 46ch;
  margin-top: 14px;
  color: var(--ink-soft);
  font-size: clamp(14.5px, 1.2vw, 16.5px);
  line-height: 1.74;
  text-wrap: pretty;
}

/* ---------- Process ----------
   No photography here on purpose — see the note at the head of
   about.php. The scroll-drawn .timeline component is reused
   unchanged; only the surrounding band is new. */
.studio-process .timeline { margin-top: clamp(10px, 2vw, 24px); }

/* ---------- Trust ---------- */
.studio-trust {
  padding-block: clamp(58px, 8vw, 112px);
  background: var(--ink);
  color: var(--paper);
}
.studio-trust__grid {
  display: grid;
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.15fr);
  gap: clamp(30px, 5vw, 74px);
  align-items: start;
}
.studio-trust .section-title { color: var(--white); max-width: 13ch; margin-bottom: 0; }
.studio-trust__figures { display: flex; flex-wrap: wrap; gap: clamp(24px, 4vw, 56px); margin: clamp(26px, 3.4vw, 40px) 0 0; }
.studio-trust__figures div { display: grid; gap: 6px; }
.studio-trust__figures dt { order: 2; color: rgba(255,255,255,.58); font-size: 9.5px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; }
.studio-trust__figures dd { order: 1; margin: 0; color: var(--paper); font: 400 clamp(34px, 3.8vw, 56px)/1 'Fraunces', Georgia, serif; letter-spacing: -.04em; }

.studio-trust__clients { margin: 0; padding: 0; list-style: none; }
.studio-trust__clients li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 18px;
  padding: 15px 0;
  border-bottom: 1px solid var(--hairline-dark);
}
.studio-trust__clients li:first-child { border-top: 1px solid var(--hairline-dark); }
.studio-trust__clients .nm { color: var(--white); font-size: clamp(15px, 1.35vw, 19px); line-height: 1.3; }
.studio-trust__clients .ty { color: rgba(255,255,255,.55); font-size: 9.5px; font-weight: 700; letter-spacing: .15em; text-transform: uppercase; }

.studio-trust__gate {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 32px;
  margin-top: clamp(14px, 2vw, 26px);
  padding: clamp(22px, 3vw, 34px) clamp(20px, 3vw, 34px);
  border: 1px solid var(--hairline-dark);
  color: var(--white);
  text-decoration: none;
  transition: background-color .4s var(--ease), border-color .4s var(--ease);
}
.studio-trust__gate:hover, .studio-trust__gate:focus-visible { background: rgba(255,255,255,.05); border-color: var(--gold); }
.studio-trust__gate .cs-index { color: var(--gold-lit); }
.studio-trust__gate-title {
  flex: 1 1 14ch;
  font: 400 clamp(21px, 2.4vw, 34px)/1.08 'Fraunces', Georgia, serif;
  letter-spacing: -.03em;
}
.studio-trust__gate-cue {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  border-bottom: 1px solid rgba(255,255,255,.4);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
}
.studio-trust__gate-cue span { transition: transform .35s var(--ease); }
.studio-trust__gate:hover .studio-trust__gate-cue span,
.studio-trust__gate:focus-visible .studio-trust__gate-cue span { transform: translateX(6px); }

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .studio-head { grid-template-columns: minmax(0, 1fr); gap: 14px; align-items: start; }
  .studio-trust__grid { grid-template-columns: minmax(0, 1fr); }
  .studio-beat,
  .studio-beat:nth-child(even) { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .studio-beat:nth-child(even) .studio-beat__frames { order: 0; }
  .studio-beat__frames { aspect-ratio: 3 / 2.4; }
}

@media (max-width: 560px) {
  /* "Accountability." is 15 characters and cannot hyphenate; at 38px it is
     wider than a 320px column. 9.6vw keeps the longest word inside the wrap
     from 320px up. */
  .studio-hero h1 { max-width: 100%; font-size: clamp(31px, 9.6vw, 58px); }
  /* The triptych stays three-up rather than stacking: three tall
     frames across a phone is the composition, and stacking them
     would turn the page's one strong statement into three screens
     of scrolling. The labels shrink with them. */
  .studio-hero__triptych { gap: 8px; }
  .studio-pillar__plate,
  .studio-pillar--1 .studio-pillar__plate { aspect-ratio: 3 / 4.2; }
  .studio-pillar__label { margin-top: 10px; padding-top: 9px; }
  .studio-pillar__label span:first-child { font-size: 15px; }
  .studio-pillar__label span:last-child { font-size: 7.5px; letter-spacing: .1em; }

  .studio-beat__frames { aspect-ratio: 3 / 2.6; }
  .studio-beat__main { width: 86%; }
  .studio-beat__aside { width: 40%; }

  .studio-trust__figures { gap: 26px; }
  .studio-trust__gate { flex-direction: column; align-items: flex-start; }
}

@media (prefers-reduced-motion: reduce) {
  .studio-trust__gate, .studio-trust__gate-cue span { transition: none; }
}

/* ============================================================
   ABOUT — IMAGE-LED STUDIO STORY (about.php)
   ------------------------------------------------------------
   The dark ground is continuous by design: each chapter shifts only a shade,
   letting the completed work rather than decorative UI carry the contrast.
   ============================================================ */
.about-page {
  --about-card-radius: clamp(18px, 2vw, 30px);
  --about-card-radius-sm: clamp(14px, 1.5vw, 22px);
  overflow-x: clip;
  background: var(--paper);
  color: var(--ink);
}
.about-page :focus-visible { outline-color: var(--clay); outline-offset: 4px; }
.about-page .breadcrumb { color: rgba(247,243,234,.72); }
.about-page .breadcrumb a:hover { color: #f7f3ea; }
.about-kicker { color: #e9bd76; margin-bottom: 16px; }

.about-hero {
  position: relative;
  isolation: isolate;
  /* A compact opening keeps the image-led introduction in view without
     creating a second, empty screen before the studio story begins. */
  padding-block: clamp(32px, 4vw, 56px) clamp(48px, 5vw, 68px);
  overflow: hidden;
  background:
    radial-gradient(circle at 84% 24%, rgba(201,163,106,.19), transparent 23%),
    radial-gradient(circle at 35% 105%, rgba(76,91,159,.28), transparent 38%),
    linear-gradient(128deg, #08091d 0%, #11132d 51%, #171513 100%);
}
.about-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    linear-gradient(90deg, transparent 0 49.95%, rgba(255,255,255,.075) 50%, transparent 50.05%),
    linear-gradient(0deg, transparent 0 77.95%, rgba(255,255,255,.045) 78%, transparent 78.05%);
  opacity: .85;
}
.about-hero::before {
  content: '';
  position: absolute;
  z-index: -1;
  width: min(60vw, 820px);
  aspect-ratio: 1;
  right: -20vw;
  top: -28vw;
  border: 1px solid rgba(233,189,118,.2);
  border-radius: 50%;
  box-shadow: 0 0 0 68px rgba(233,189,118,.035), 0 0 0 136px rgba(233,189,118,.025);
  pointer-events: none;
}
.about-hero__layout {
  display: grid;
  grid-template-columns: minmax(290px, .83fr) minmax(480px, 1.17fr);
  gap: clamp(28px, 4.5vw, 72px);
  align-items: center;
  margin-top: clamp(22px, 3.5vw, 48px);
}
.about-hero__copy { padding-bottom: clamp(0px, 2vw, 24px); }
.about-hero h1 {
  max-width: 11ch;
  margin: 0;
  color: #fbf7ef;
  font-size: clamp(42px, 5.35vw, 78px);
  line-height: .98;
  letter-spacing: -.055em;
}
.about-hero h1.about-hero__title > span {
  display: block !important;
  width: 100%;
  white-space: nowrap;
}
.about-hero__lede {
  max-width: 47ch;
  margin: clamp(18px, 2.2vw, 28px) 0 0;
  color: rgba(247,243,234,.76);
  font-size: clamp(15px, 1.25vw, 18px);
  line-height: 1.7;
}
.about-hero__cta {
  display: flex;
  justify-content: center;
  width: fit-content;
  min-height: 52px;
  margin: clamp(24px, 3vw, 36px) 0 0;
  border-color: var(--white);
  border-radius: 999px;
  background: var(--white);
  color: var(--ink);
  box-shadow: 0 8px 24px rgba(0,0,0,.2);
}
.about-hero__cta:hover,
.about-hero__cta:focus-visible {
  border-color: var(--gold-lit);
  background: var(--gold-lit);
  color: var(--ink);
}
.about-closing__cta {
  display: flex;
  justify-content: center;
  width: fit-content;
  margin: clamp(26px, 3.2vw, 40px) auto 0;
}
.about-spaces__link span { transition: transform .25s var(--ease); }
@media (hover:hover) { .about-spaces__link:hover span { transform: translateX(4px); } }

.about-hero__composition {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(10px, 1.35vw, 18px);
  min-width: 0;
  aspect-ratio: 4 / 3;
}
.about-hero__frame {
  position: relative;
  margin: 0;
  overflow: hidden;
  min-width: 0;
  width: auto;
  aspect-ratio: 4 / 3;
  background: #2b2a27;
  border: 1px solid rgba(247,243,234,.22);
  border-radius: var(--about-card-radius);
  box-shadow: 0 22px 56px rgba(0,0,18,.32);
  transition: transform .42s var(--ease), box-shadow .42s var(--ease);
}
.about-hero__frame::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(145deg, rgba(255,255,255,.12), transparent 28%, rgba(2,3,20,.3) 100%);
}
.about-hero__frame img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease-soft); }
.about-hero__frame--lead { overflow: hidden; }
@media (hover:hover) {
  .about-hero__frame:hover { transform: translateY(-5px); box-shadow: 0 28px 62px rgba(0,0,18,.42); }
  .about-hero__frame:hover img { transform: scale(1.045); }
}

.about-story,
.about-process,
.about-spaces { padding-block: clamp(42px, 4vw, 64px); }
.about-story { background: var(--paper-warm); }
.about-process { background: var(--paper); border-block: 1px solid var(--line); }
.about-story .about-kicker,
.about-process .about-kicker,
.about-spaces .about-kicker { color: var(--ink); }
.about-spaces {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background:
    radial-gradient(circle at 8% 0%, rgba(201,163,106,.16), transparent 24%),
    linear-gradient(135deg, var(--paper-warm), #f4efe5);
}
.about-section-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(270px, .78fr);
  gap: clamp(20px, 4vw, 64px);
  align-items: end;
  margin-bottom: clamp(24px, 2.5vw, 36px);
}
.about-section-head .section-title { margin: 0; color: var(--ink); max-width: 14ch; }
.about-section-head__lede {
  margin: 0;
  color: var(--ink-soft);
  font-size: clamp(14px, 1.1vw, 16px);
  line-height: 1.75;
}
.about-beats { display: grid; gap: clamp(34px, 3.5vw, 52px); margin: 0; padding: 0; list-style: none; }
.about-beat {
  display: grid;
  grid-template-columns: minmax(0, 1.23fr) minmax(270px, .77fr);
  gap: clamp(26px, 4.5vw, 72px);
  align-items: center;
}
.about-beat:nth-child(even) { grid-template-columns: minmax(270px, .77fr) minmax(0, 1.23fr); }
.about-beat:nth-child(even) .about-beat__frames { order: 2; }
.about-beat__frames { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(12px, 1.6vw, 22px); min-width: 0; }
.about-beat__main,
.about-beat__aside { position: relative; margin: 0; overflow: hidden; min-width: 0; aspect-ratio: 4 / 3; background: var(--ink); border: 1px solid rgba(20,19,42,.08); border-radius: var(--about-card-radius-sm); box-shadow: 0 20px 38px rgba(20,19,42,.14); }
.about-beat__main img,
.about-beat__aside img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease-soft); }
@media (hover:hover) { .about-beat:hover .about-beat__main img, .about-beat:hover .about-beat__aside img { transform: scale(1.04); } }
.about-beat__number { color: var(--clay); margin-bottom: 14px; }
.about-beat__copy h3 {
  max-width: 12ch;
  margin: 0;
  color: var(--ink);
  font-size: clamp(28px, 3.2vw, 48px);
  line-height: 1.05;
  letter-spacing: -.04em;
}
.about-beat__copy > p:last-child {
  max-width: 43ch;
  margin: 16px 0 0;
  color: var(--ink-soft);
  font-size: clamp(14.5px, 1.15vw, 16.5px);
  line-height: 1.75;
}

.about-process .timeline { margin-top: clamp(2px, .5vw, 8px); }
.about-process .timeline-track { top: 12px; height: 1px; background: #d8d2c6; }
.about-process .timeline-track::after { background: var(--clay); }
.about-process .timeline-steps { gap: 0; }
/* The process is a sequence, not a set of feature cards.  A continuous rule
   gives the four hand-off points equal weight and removes the artificial gaps. */
.about-process .timeline-step { min-height: 118px; padding: 38px clamp(12px, 2vw, 28px) 0 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; }
.about-process .timeline-step::before { left: 0; top: 0; width: 24px; height: 24px; background: var(--paper); border-color: #d8d2c6; }
.about-process .timeline-step.is-lit::before { background: var(--clay); border-color: var(--clay); }
.about-process .timeline-step .n { color: var(--ink-soft); }
.about-process .timeline-step.is-lit .n { color: var(--clay); }
.about-process .timeline-step h3 { margin-top: 10px; color: var(--ink); font-size: clamp(18px, 1.8vw, 27px); line-height: 1.2; }

@media (max-width: 900px) {
  .about-process .timeline-track { left: 11px; top: 0; bottom: 0; width: 1px; height: auto; }
  .about-process .timeline-step { min-height: 0; padding: 0 0 clamp(26px, 4vw, 34px) 42px; }
  .about-process .timeline-step::before { left: 0; top: 0; }
}

.about-spaces__head { margin-bottom: clamp(26px, 3vw, 40px); }
.about-spaces__mosaic {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 1.4vw, 22px);
}
.about-space {
  display: block;
  min-width: 0;
  margin: 0;
}
.about-space__image {
  position: relative;
  display: block;
  min-height: 0;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border: 1px solid rgba(20,19,42,.08);
  border-radius: var(--about-card-radius-sm);
  background: var(--ink);
  box-shadow: 0 14px 28px rgba(20,19,42,.1);
  isolation: isolate;
  transition: box-shadow .32s var(--ease), transform .32s var(--ease);
}
.about-space__image::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, transparent 28%, rgba(7,8,25,.18) 55%, rgba(7,8,25,.88) 100%);
  opacity: 0;
  transition: opacity .32s var(--ease);
  pointer-events: none;
}
.about-space__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .65s var(--ease-soft), filter .45s var(--ease);
}
.about-space__hover {
  position: absolute;
  inset: auto 0 0;
  z-index: 2;
  display: grid;
  gap: 6px;
  padding: clamp(16px, 2vw, 24px);
  color: var(--white);
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .28s var(--ease), transform .34s var(--ease);
  pointer-events: none;
}
.about-space__hover > span { color: #f5ce91; font-size: 9px; font-weight: 700; letter-spacing: .15em; text-transform: uppercase; }
.about-space__hover small { max-width: 31ch; color: rgba(255,255,255,.9); font-size: clamp(12px, 1vw, 14px); line-height: 1.45; }
.about-space__hover b { display: inline-flex; align-items: center; gap: 8px; margin-top: 5px; color: var(--white); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; }
.about-space__hover i { font-style: normal; font-size: 15px; transition: transform .28s var(--ease); }
.about-space__image:focus-visible { outline: 3px solid var(--clay); outline-offset: 4px; }
@media (hover:hover) {
  .about-space__image:hover { transform: translateY(-5px); box-shadow: 0 22px 40px rgba(20,19,42,.18); }
  .about-space__image:hover::after { opacity: 1; }
  .about-space__image:hover img { transform: scale(1.075); filter: saturate(1.06); }
  .about-space__image:hover .about-space__hover { opacity: 1; transform: none; }
  .about-space__image:hover .about-space__hover i { transform: translateX(4px); }
}
.about-space__image:focus-visible::after,
.about-space__image:focus-visible .about-space__hover { opacity: 1; transform: none; }
.about-spaces__link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: fit-content;
  gap: 11px;
  min-height: 44px;
  margin: clamp(22px, 3vw, 34px) auto 0;
  padding: 12px 20px;
  border: 1px solid var(--ink);
  border-radius: 999px;
  background: var(--ink);
  color: var(--white);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  transition: transform .25s var(--ease), background-color .25s var(--ease), border-color .25s var(--ease), color .25s var(--ease);
}
.about-spaces__link:hover, .about-spaces__link:focus-visible { transform: translateY(-2px); border-color: var(--clay); background: var(--clay); color: var(--white); }

.about-closing {
  padding-block: clamp(70px, 8vw, 118px);
  background: var(--paper);
  text-align: center;
}
.about-closing .wrap {
  max-width: 780px;
  padding: 0 var(--page-padding);
}
.about-closing h2 {
  max-width: 21ch;
  margin: 0 auto;
  color: var(--ink);
  font-size: clamp(30px, 3.45vw, 48px);
  line-height: 1.08;
  letter-spacing: -.045em;
}
.about-closing .btn-dark {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--white);
}
.about-closing .btn-dark:hover,
.about-closing .btn-dark:focus-visible {
  border-color: var(--clay-deep);
  background: var(--clay-deep);
  color: var(--white);
}

@media (max-width: 1024px) {
  .about-hero__layout { grid-template-columns: minmax(250px, .82fr) minmax(390px, 1.18fr); gap: clamp(28px, 4vw, 54px); }
  .about-hero__composition { aspect-ratio: 4 / 3; }
  .about-spaces__mosaic { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 18px; }
}
@media (max-width: 760px) {
  .about-hero__layout,
  .about-section-head,
  .about-beat,
  .about-beat:nth-child(even) { grid-template-columns: minmax(0, 1fr); }
  .about-hero__layout { margin-top: 22px; gap: 28px; }
  .about-hero__copy { padding-bottom: 0; }
  .about-hero h1 { font-size: clamp(42px, 10.5vw, 70px); }
  .about-hero__composition { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; aspect-ratio: 4 / 3; }
  .about-hero__frame,
  .about-hero__frame--lead,
  .about-hero__frame--detail,
  .about-hero__frame--public,
  .about-hero__frame--workplace { position: relative; width: auto; aspect-ratio: 4 / 3; }
  .about-hero__frame--lead { grid-column: auto; aspect-ratio: 4 / 3; }
  .about-hero__frame--detail,
  .about-hero__frame--public { aspect-ratio: 4 / 3; transform: none; }
  .about-section-head { gap: 15px; }
  .about-beat { gap: 20px; }
  .about-beat:nth-child(even) .about-beat__frames { order: 0; }
  .about-process .timeline-step { min-height: 0; padding: 0 0 28px 42px; border: 0; background: transparent; box-shadow: none; }
  .about-process .timeline { margin-top: 10px; }
}
@media (max-width: 560px) {
  .about-hero,
  .about-story,
  .about-process,
  .about-spaces { padding-block: 38px; }
  .about-hero { padding-top: 32px; padding-bottom: 44px; }
  .about-hero h1 { font-size: clamp(36px, 10.1vw, 54px); }
  .about-hero__lede { font-size: 15px; }
  .about-beats { gap: 34px; }
  .about-beat__frames { aspect-ratio: auto; }
  .about-beat__frames { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .about-beat__main,
  .about-beat__aside { border-radius: 18px; }
  .about-spaces__mosaic { grid-template-columns: minmax(0, 1fr); gap: 20px; }
  .about-space__image { border-radius: 18px; }
  .about-space__image::after { opacity: 1; }
  .about-space__hover { opacity: 1; transform: none; }
  .about-process .timeline-step { padding: 0 0 26px 42px; }
  .about-process .timeline-step::before { left: 0; top: 0; }
  .about-closing { padding-block: 64px; }
  .about-closing .wrap { padding: 0 22px; }
}
@media (prefers-reduced-motion: reduce) {
  .about-page *, .about-page *::before, .about-page *::after { scroll-behavior: auto; transition: none !important; animation: none !important; }
}

/* ============================================================
   GALLERY — THE EXHIBITION  (gallery.php)
   ------------------------------------------------------------
   Five projects, five rhythms. The rhythm is chosen from what the
   photographs of that project actually are, so the page never
   settles into the repeating thumbnail grid it replaces.
   ============================================================ */
.exhibit { overflow-x: clip; }
.exhibit a:focus-visible,
.exhibit summary:focus-visible,
.exhibit button:focus-visible { outline: 3px solid var(--clay); outline-offset: 3px; }

/* ---------- Hero ---------- */
.exhibit-hero {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  min-height: min(80svh, 760px);
  padding-block: clamp(60px, 8vh, 100px) clamp(44px, 6vh, 78px);
  overflow: hidden;
  background:
    radial-gradient(circle at 84% 22%, rgba(201,163,106,.22), transparent 20%),
    radial-gradient(circle at 18% 110%, rgba(70,87,166,.36), transparent 38%),
    linear-gradient(130deg, #08091e 0%, var(--noir) 48%, #171411 100%);
  color: var(--white);
}
.exhibit-hero::before,
.exhibit-hero::after {
  content: '';
  position: absolute;
  z-index: -1;
  pointer-events: none;
}
.exhibit-hero::before {
  width: min(60vw, 780px);
  aspect-ratio: 1;
  right: -19vw;
  top: -25vw;
  border: 1px solid rgba(240,198,129,.22);
  border-radius: 50%;
  box-shadow: 0 0 0 56px rgba(240,198,129,.04), 0 0 0 112px rgba(240,198,129,.025);
}
.exhibit-hero::after {
  inset: 0;
  background:
    linear-gradient(90deg, transparent 0 49.95%, rgba(255,255,255,.055) 50%, transparent 50.05%),
    linear-gradient(0deg, transparent 0 77.95%, rgba(255,255,255,.045) 78%, transparent 78.05%);
}
.exhibit-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr);
  gap: clamp(32px, 5vw, 78px);
  align-items: center;
  width: 100%;
}
.exhibit-hero__copy { min-width: 0; }
.exhibit-hero .breadcrumb { color: rgba(255,255,255,.84); }
.exhibit-hero__kicker { color: var(--gold-lit); margin-bottom: 18px; }
.exhibit-hero h1 {
  max-width: 11ch;
  font-size: clamp(48px, 7vw, 108px);
  line-height: .94;
  letter-spacing: -.038em;
  margin-bottom: clamp(14px, 2vw, 22px);
}
.exhibit-hero__lede {
  max-width: 40ch;
  color: rgba(255,255,255,.8);
  font-size: clamp(15px, 1.35vw, 18px);
  line-height: 1.66;
  text-wrap: pretty;
}

/* The hero uses a precise four-image contact sheet: it fills the visual column
   completely and gives each photograph equal importance. */
.exhibit-hero__deck {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: clamp(10px, 1.35vw, 18px);
  min-width: 0;
  aspect-ratio: 4 / 3;
  filter: drop-shadow(0 30px 36px rgba(0,0,20,.24));
}
.exhibit-hero__plate {
  position: relative;
  min-width: 0;
  width: auto;
  aspect-ratio: 4 / 3;
}
.exhibit-hero__plate.cs-plate { height: 100%; border-radius: clamp(14px, 1.8vw, 26px); }
/* The grid is intentionally calm; pointer drift would knock its card edges out
   of alignment, so it is reserved for the deeper editorial scenes. */
.js .exhibit-hero__plate[data-cs-drift] { transform: none; transition: none; }

/* ---------- Sticky project index ----------
   --cs-header-h is written by main.js from the real header height,
   because the header compacts on scroll and hard-coding 68px leaves
   the index either overlapped or floating. Falls back to 68px if
   scripting never runs. */
.exhibit-index {
  position: sticky;
  top: calc(var(--cs-header-h, 68px) - 1px);
  z-index: 40;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}
.exhibit-index__inner { display: flex; align-items: center; gap: clamp(12px, 2vw, 26px); min-height: 58px; }
.exhibit-index__label {
  flex: none;
  color: var(--clay);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .17em;
  text-transform: uppercase;
}
.exhibit-index__list {
  display: flex;
  gap: clamp(4px, 1vw, 14px);
  margin: 0;
  padding: 0;
  list-style: none;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-padding-inline: var(--page-padding);
  overscroll-behavior-inline: contain;
}
.exhibit-index__list::-webkit-scrollbar { display: none; }
.exhibit-index__list li { flex: none; }
.exhibit-index__list a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: none;
  min-height: 44px;
  padding: 8px 13px;
  border: 1px solid transparent;
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  transition: color .25s var(--ease), border-color .25s var(--ease), background-color .25s var(--ease);
}
.exhibit-index__n { color: var(--clay); font-size: 9px; font-weight: 700; letter-spacing: .1em; }
.exhibit-index__list a:hover { color: var(--ink); border-color: var(--line); }
/* Scrollspy state, set by main.js. Also styled for :focus-visible so
   keyboard users see the same emphasis. */
.exhibit-index__list a[aria-current='true'] { background: var(--ink); border-color: var(--ink); color: var(--white); }
.exhibit-index__list a[aria-current='true'] .exhibit-index__n { color: var(--gold-lit); }

/* ---------- Chapters ---------- */
.exhibit-chapter {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding-block: clamp(52px, 7vw, 100px);
  border-top: 1px solid var(--line);
  /* Clears the sticky header AND the sticky index, so a jump link
     does not land the chapter title underneath them. */
  scroll-margin-top: calc(var(--cs-header-h, 68px) + 58px);
}
.exhibit-chapter:nth-of-type(even) { background: var(--paper); }
.exhibit-chapter:nth-of-type(odd) { background: linear-gradient(135deg, var(--paper-warm), #f3eee5); }
.exhibit-chapter::after {
  content: attr(id);
  position: absolute;
  z-index: -1;
  right: -1.6ch;
  bottom: -.34em;
  color: rgba(20,19,42,.027);
  font: 600 clamp(70px, 11vw, 176px)/.8 'Montserrat', sans-serif;
  letter-spacing: -.08em;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
}
.exhibit-chapter__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, .78fr);
  gap: clamp(18px, 4vw, 60px);
  align-items: end;
  margin-bottom: clamp(26px, 4vw, 48px);
}
.exhibit-chapter__meta { color: var(--clay); margin-bottom: 12px; }
.exhibit-chapter__head .section-title { margin-bottom: 0; }
.exhibit-chapter__copy { color: var(--ink-soft); font-size: clamp(13.5px, 1.1vw, 16px); line-height: 1.72; text-wrap: pretty; }

/* ---------- Frames ---------- */
.exhibit-set { display: grid; gap: clamp(12px, 1.6vw, 20px); margin: 0; padding: 0; list-style: none; }
.exhibit-frame { min-width: 0; }
.exhibit-frame__btn {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  /* A zoom cursor is the honest affordance here: the control opens a
     larger view, it does not navigate. */
  cursor: zoom-in;
  border-radius: clamp(12px, 1.4vw, 20px);
  transition: transform .35s var(--ease), filter .35s var(--ease);
}
.exhibit-frame__plate {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: clamp(12px, 1.4vw, 20px) !important;
  box-shadow: 0 14px 30px rgba(17,18,43,.12);
}
.exhibit-frame__plate::after {
  background:
    linear-gradient(180deg, transparent 37%, rgba(7,8,26,.06) 55%, rgba(7,8,26,.84) 100%),
    radial-gradient(120% 90% at 50% 40%, transparent 58%, rgba(20,19,42,.13) 100%);
}
.exhibit-frame__plate > img { transition: transform .72s var(--ease-soft), filter .45s var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .exhibit-frame__btn:hover { transform: translateY(-6px); filter: drop-shadow(0 16px 16px rgba(20,19,42,.13)); }
  .exhibit-frame__btn:hover .exhibit-frame__plate > img { transform: scale(1.075); filter: saturate(1.08); }
}
/* The cue is a hover nicety only. It never carries information the
   visitor needs — the caption is the image's alt text and the
   button's accessible name, both of which exist without hovering. */
.exhibit-frame__cue {
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 2;
  padding: 7px 12px;
  background: rgba(5,5,31,.72);
  color: var(--white);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.exhibit-frame__btn:hover .exhibit-frame__cue,
.exhibit-frame__btn:focus-visible .exhibit-frame__cue { opacity: 1; transform: none; }
.exhibit-frame__info {
  position: absolute;
  inset: auto 0 0;
  z-index: 2;
  display: grid;
  gap: 4px;
  padding: clamp(16px, 2vw, 23px);
  color: var(--white);
  opacity: 0;
  transform: translateY(13px);
  transition: opacity .3s var(--ease), transform .36s var(--ease);
  text-align: left;
  pointer-events: none;
}
.exhibit-frame__info strong { color: #f3c984; font-size: 9px; font-weight: 700; letter-spacing: .15em; text-transform: uppercase; }
.exhibit-frame__info small { max-width: 33ch; color: rgba(255,255,255,.92); font-size: clamp(12px, 1vw, 14px); line-height: 1.42; }
.exhibit-frame__info b { display: inline-flex; align-items: center; gap: 8px; margin-top: 4px; color: var(--white); font-size: 9px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; }
.exhibit-frame__info i { font-style: normal; font-size: 15px; transition: transform .3s var(--ease); }
.exhibit-frame__btn:hover .exhibit-frame__info,
.exhibit-frame__btn:focus-visible .exhibit-frame__info { opacity: 1; transform: none; }
.exhibit-frame__btn:hover .exhibit-frame__info i { transform: translateX(4px); }

/* --- mosaic: irregular, lived-in. Five-cell unit spanning exactly
       12 columns, so the grid tiles without holes at any count. --- */
.exhibit-chapter--mosaic .exhibit-set { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.exhibit-chapter--mosaic .exhibit-frame { grid-column: span 2; }
.exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 1) { grid-column: span 3; }
.exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 1) .exhibit-frame__plate { aspect-ratio: 4 / 3; }
.exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 2) { grid-column: span 3; }
.exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 2) .exhibit-frame__plate { aspect-ratio: 3 / 2; }
.exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 3) .exhibit-frame__plate { aspect-ratio: 1 / 1; }
.exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 4) .exhibit-frame__plate { aspect-ratio: 4 / 5; }
.exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 5) .exhibit-frame__plate { aspect-ratio: 3 / 2; }

/* --- frames: tall paired portraits, for crafted vertical detail. --- */
.exhibit-chapter--frames .exhibit-set { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(16px, 2.4vw, 34px); }
.exhibit-chapter--frames .exhibit-frame__plate { aspect-ratio: 3 / 4; }
.exhibit-chapter--frames .exhibit-frame:nth-child(3n + 2) { transform: translateY(clamp(16px, 2.6vw, 44px)); }

/* --- modular: even, calm, clinical. The 270px minimum gave four
       columns of 287px on a 1440 viewport, which is thumbnail scale
       on the most image-forward page of the site. 340px holds it to
       three. --- */
.exhibit-chapter--modular .exhibit-set { grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); }
.exhibit-chapter--modular .exhibit-frame__plate { aspect-ratio: 3 / 2; }
.exhibit-chapter--modular .cs-plate { border-radius: clamp(12px, 1.4vw, 20px); }

/* --- civic: structured hairline grid, square modules. --- */
.exhibit-chapter--civic .exhibit-set {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
  gap: 0;
  border: 1px solid var(--line);
  background: var(--white);
}
.exhibit-chapter--civic .exhibit-frame {
  padding: clamp(10px, 1.2vw, 16px);
  box-shadow: inset -1px 0 0 var(--line), inset 0 -1px 0 var(--line);
}
.exhibit-chapter--civic .exhibit-frame__plate { aspect-ratio: 1 / 1; }

/* --- sequence: a horizontal run. Reuses .rail / .rail-nav. --- */
.exhibit-chapter--sequence .exhibit-set { display: flex; }
.exhibit-chapter--sequence .exhibit-frame { flex: 0 0 clamp(220px, 28vw, 320px); scroll-snap-align: start; }
.exhibit-chapter--sequence .exhibit-frame__plate { aspect-ratio: 4 / 3; }

/* ---------- View more ---------- */
.exhibit-more { margin-top: clamp(20px, 2.6vw, 32px); border-top: 1px solid var(--line); }
.exhibit-more > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  min-height: 52px;
  padding: 14px 0;
  cursor: pointer;
  list-style: none;
  color: var(--ink);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
}
.exhibit-more > summary::-webkit-details-marker { display: none; }
.exhibit-more[open] > summary { border-bottom: 1px solid var(--line); }
.exhibit-more .exhibit-set--more { margin-top: clamp(14px, 2vw, 24px); }
.exhibit-set--more { grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); }
.exhibit-set--more .exhibit-frame,
.exhibit-set--more .exhibit-frame:nth-child(n) { grid-column: auto; transform: none; padding: 0; box-shadow: none; }
.exhibit-set--more .exhibit-frame__plate { aspect-ratio: 3 / 2 !important; }

/* ---------- Uniform gallery cards ----------
   Every completed-space image now lives in the same 4:3 frame. The
   photography still fills each plate with object-fit:cover, but none of the
   individual project rhythms can change a card's width or height. */
.exhibit .exhibit-set,
.exhibit .exhibit-chapter--sequence .exhibit-set {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(14px, 1.7vw, 24px);
  overflow: visible;
  padding: 0;
}
.exhibit .exhibit-frame,
.exhibit .exhibit-chapter--mosaic .exhibit-frame:nth-child(n),
.exhibit .exhibit-chapter--frames .exhibit-frame:nth-child(n),
.exhibit .exhibit-chapter--sequence .exhibit-frame {
  grid-column: auto;
  flex: auto;
  padding: 0;
  transform: none;
  box-shadow: none;
}
.exhibit .exhibit-frame__plate,
.exhibit .exhibit-chapter--mosaic .exhibit-frame__plate,
.exhibit .exhibit-chapter--frames .exhibit-frame__plate,
.exhibit .exhibit-chapter--modular .exhibit-frame__plate,
.exhibit .exhibit-chapter--civic .exhibit-frame__plate,
.exhibit .exhibit-chapter--sequence .exhibit-frame__plate,
.exhibit .exhibit-set--more .exhibit-frame__plate {
  aspect-ratio: 4 / 3 !important;
}
.exhibit .exhibit-chapter--civic .exhibit-set { border: 0; background: transparent; }
.exhibit .exhibit-chapter--sequence .rail-nav { display: none; }

/* Jakkur Workspaces is a practical office survey, so its photographs read best
   as a disciplined, equal-height grid rather than growing with an ultrawide
   desktop. This also keeps the chapter introduction compact. */
#jakkur-workspaces { padding-block: clamp(48px, 4vw, 64px); }
#jakkur-workspaces .exhibit-chapter__head { margin-bottom: clamp(22px, 2vw, 30px); }
#jakkur-workspaces .exhibit-set {
  width: 100%;
  max-width: 100%;
  padding-inline: 0;
  overflow: visible;
  scroll-snap-type: none;
}
#jakkur-workspaces .exhibit-frame__plate {
  height: clamp(260px, 20vw, 340px);
  aspect-ratio: auto !important;
}

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .exhibit-hero { min-height: 0; padding-block: clamp(42px, 7vw, 66px) clamp(30px, 5vw, 48px); }
  .exhibit-hero__grid { grid-template-columns: minmax(0, 1fr); gap: clamp(26px, 5vw, 40px); }
  .exhibit-hero h1 { max-width: 14ch; font-size: clamp(44px, 10vw, 78px); }
  .exhibit-hero__deck { width: min(100%, 680px); aspect-ratio: 4 / 3; }
  .exhibit-chapter__head { grid-template-columns: minmax(0, 1fr); gap: 14px; align-items: start; }
  .exhibit-chapter--frames .exhibit-set { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .exhibit-chapter--frames .exhibit-frame:nth-child(3n + 2) { transform: none; }
  .exhibit-chapter--frames .exhibit-frame:nth-child(even) { transform: translateY(clamp(14px, 2.4vw, 30px)); }
  .exhibit .exhibit-set,
  .exhibit .exhibit-chapter--sequence .exhibit-set { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 560px) {
  .exhibit-hero {
    align-items: flex-start;
    padding-block: 32px 28px;
  }
  .exhibit-hero__grid { gap: 26px; }
  .exhibit-hero .breadcrumb { font-size: 11px; }
  .exhibit-hero__kicker { margin-bottom: 12px; }
  .exhibit-hero h1 { max-width: 10ch; font-size: clamp(38px, 11vw, 52px); line-height: .98; }
  .exhibit-hero__lede { max-width: 33ch; font-size: 14px; line-height: 1.58; }
  .exhibit-hero__deck { width: 100%; gap: 8px; }
  .exhibit-hero__plate { aspect-ratio: 4 / 3; }

  .exhibit-index__inner { min-height: 48px; gap: 0; }
  .exhibit-index__label { display: none; }
  /* The scroller runs to the screen edges so it reads as scrollable
     rather than as a clipped row. */
  .exhibit-index__list { gap: 2px; margin-inline: calc(var(--page-padding) * -1); padding-inline: var(--page-padding); }
  .exhibit-index__list a { min-height: 46px; gap: 6px; padding-inline: 11px; font-size: 11px; }

  .exhibit-chapter { padding-block: 42px; scroll-margin-top: calc(var(--cs-header-h, 68px) + 48px); }
  .exhibit-chapter__head { gap: 10px; margin-bottom: 26px; }
  .exhibit-chapter__meta { margin-bottom: 8px; }
  .exhibit-chapter__copy { font-size: 14px; line-height: 1.62; }

  .exhibit-chapter--mosaic .exhibit-set { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .exhibit-chapter--mosaic .exhibit-frame,
  .exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 1),
  .exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 2) { grid-column: span 2; }
  .exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 3),
  .exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 4) { grid-column: span 1; }
  .exhibit-chapter--mosaic .exhibit-frame__plate { aspect-ratio: 4 / 3 !important; }
  .exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 3) .exhibit-frame__plate,
  .exhibit-chapter--mosaic .exhibit-frame:nth-child(5n + 4) .exhibit-frame__plate { aspect-ratio: 1 / 1 !important; }

  .exhibit-chapter--frames .exhibit-set { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .exhibit-chapter--civic .exhibit-set { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .exhibit-set--more { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .exhibit-frame__plate { border-radius: 14px !important; }
  .exhibit-frame__info { padding: 14px; opacity: 1; transform: none; }
  .exhibit-frame__info small { font-size: 12px; }
  .exhibit-frame__cue { display: none; }
  .exhibit .exhibit-set,
  .exhibit .exhibit-chapter--sequence .exhibit-set { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  #jakkur-workspaces .exhibit-frame__plate { height: 250px; }
}

@media (prefers-reduced-motion: reduce) {
  .exhibit-frame__btn, .exhibit-frame__plate > img, .exhibit-frame__cue, .exhibit-frame__info, .exhibit-frame__info i, .exhibit-index__list a { transition: none; }
  .exhibit-chapter--frames .exhibit-frame:nth-child(3n + 2),
  .exhibit-chapter--frames .exhibit-frame:nth-child(even) { transform: none; }
}

/* ============================================================
   GLOBAL HEADER LOCK
   This is intentionally the final header rule in the stylesheet: every page
   shares the same logo and navigation dimensions before and after scrolling.
   ============================================================ */
.site-header .nav,
.site-header.is-stuck .nav {
  min-height:72px !important;
  height:72px !important;
}
.site-header {
  position:sticky !important;
  top:0 !important;
  width:100% !important;
  margin:0 !important;
  border:0 !important;
  border-bottom:1px solid var(--line) !important;
  border-radius:0 !important;
}
.site-header .brand,
.site-header.is-stuck .brand {
  width:clamp(96px, 7.5vw, 104px) !important;
}
.site-header .brand img,
.site-header.is-stuck .brand img,
.page-home .site-header .brand img {
  width:100% !important;
  height:auto !important;
}

@media (max-width:900px) {
  .site-header .nav,
  .site-header.is-stuck .nav {
    min-height:66px !important;
    height:66px !important;
  }
  .site-header .brand,
  .site-header.is-stuck .brand {
    width:92px !important;
  }
}

@media (max-width:420px) {
  .site-header .brand,
  .site-header.is-stuck .brand {
    width:84px !important;
  }
}

/* ============================================================
   SHARED ACTION BUTTON SHAPE
   Primary actions use the same pill silhouette as the header's “Start a
   Project” button. Compact icon controls intentionally keep their circular or
   square geometry so arrows, sliders and the mobile menu remain recognisable.
   ============================================================ */
.btn,
.nav-cta,
.hero-more-toggle,
.gallery-more > summary,
.svcx-work__gallery-button,
.services-menu-all,
.wa,
.page-contact .contact-brief__submit,
.page-home .home-enquiry-submit {
  border-radius:999px !important;
}

.contact-dock {
  border-radius:999px !important;
  overflow:hidden;
}
.contact-dock a:first-child { border-radius:999px 0 0 999px; }
.contact-dock a:last-child { border-radius:0 999px 999px 0; }

@media (max-width:880px) {
  .contact-dock,
  .contact-dock a:first-child,
  .contact-dock a:last-child { border-radius:0 !important; }
}

/* ============================================================
   SMALL-SCREEN FLOORS — PART 2
   Continues two sections that already exist further up this file:
   "Touch targets" and "Mobile legibility floor". Both of those were
   written against the HOMEPAGE, and both are bounded at 900px. The
   components below belong to About, the gallery, contact and the
   service detail template, which are authored lower in this file and
   therefore win the cascade against those earlier blocks. That is the
   only reason this is a separate section rather than more lines in
   them , it is the same policy, applied where it can actually take
   effect. Keep it last.

   Measured, not assumed: every value below was read off the rendered
   page at 320px and 375px with touch emulation on. Nothing here
   changes desktop , 901px and up keeps the label tier and the control
   sizes it was designed with.
   ============================================================ */

/* ---------- Touch targets ----------
   This file sets 44px as the site's own standard in a dozen places and
   the earlier "Touch targets" block treats it as the rule. Later phone
   blocks then step several controls back DOWN , the footer links to
   36px, the footer social icons to 40px, the testimonial arrows to
   40px below 380px. Targets getting smaller on the smallest screens is
   backwards; these put them back.

   Not a WCAG failure either way: all of them clear the 24x24 minimum
   in 2.5.8. This is the 44px comfort standard the site already chose.

   Deliberately NOT included: .home-process__dots. Those five thumbnails
   are a 44px-wide vertical stack overlaid on the process photograph,
   and at 44px tall each the stack (5x44 + gaps + two arrows) grows past
   the bottom of the image it sits on. They are 42x32, they clear 2.5.8,
   and the primary control next to them , the prev/next arrows , already
   carries a 44px hit area from its ::after. Left alone on purpose. */
@media (max-width: 900px) {
  /* Covers .footer-services a too: those links are inside a .footer-col. */
  .footer-col a { min-height: 44px; }
  .footer-social .social-link { width: 44px; height: 44px; }
  .page-faq-contact { min-height: 44px; }
  /* The nine service links in the open mobile menu , the primary navigation on
     a phone , sat at 42px. */
  .services-menu-cols .services-col a { min-height: 44px; }
}
@media (max-width: 380px) {
  .testimonial-stage .testimonial-controls button { width: 44px; height: 44px; }
}

/* ---------- Mobile legibility floor, part 2 ----------
   Same 11px floor for the label tier, same reasoning as the block
   further up: uppercase, 600-700 weight and letter-spaced .1-.2em stops
   being readable well before it stops being renderable. These are the
   components that pass sweep missed.

   The worst of them was the About hero triptych at 7.5px. The comment
   on that rule explains why the three frames stay side by side on a
   phone , the composition is the three of them together , and that
   still holds. It is the label under the frame that had been shrunk to
   match, and a label nobody can read is not carrying the composition.
   Letter-spacing eases back as the size goes up so the label occupies
   roughly the width it did and the triptych does not re-flow. */
@media (max-width: 900px) {
  .cs-index span { font-size: 11px; }
  .svcx-index__n { font-size: 11px; }
  /* Plate captions , shared by the service detail template, services hub and
     about. Sector name plus what the photograph shows; at 10px over an image
     neither half was reliably readable. */
  .cs-plate__cap b,
  .cs-plate__cap span { font-size: 11px; }

  /* About */
  .studio-pillar__label span:last-child { font-size: 11px; letter-spacing: .06em; }
  .studio-trust__figures dt { font-size: 11px; }
  .studio-trust__clients .ty { font-size: 11px; }
  .marquee-item .ty { font-size: 11px; letter-spacing: .16em; }

  /* Gallery */
  .exhibit-index__n { font-size: 11px; }
  .exhibit-frame__cue { font-size: 11px; }

  /* Services hub. The proof figures were the smallest type on the site
     after the About triptych , 8px for the label under a headline
     number, which is the half of the pair that says what the number
     means. */
  .service-mosaic__meta { font-size: 11px; }
  .atlas-proof__figures dt { font-size: 11px; }
  .atlas-proof__clients span:last-child { font-size: 11px; }
  .atlas-work__sector { font-size: 11px; }

  /* The homepage enquiry card heading , same form, same conversion path
     as /contact, so it gets the same treatment. The reassurance line
     under it is a sentence, not a label. */
  /* .page-home to match the specificity of the rule these override. */
  .page-home .home-contact-card__heading span { font-size: 11px; }
  .page-home .home-contact-card__heading small { font-size: 12px; }

  /* Contact. The form is the site's conversion path, so its labels get
     12px rather than the 11px floor, and a validation message is read
     as a sentence , 13px, per the same rule the earlier block used. */
  .page-contact .contact-studio__details > div > span:first-child { font-size: 11px; }
  .page-contact .contact-brief .field > label { font-size: 12px; }
  .page-contact .contact-brief .field-error { font-size: 13px; }
}

/* ============================================================
   HOMEPAGE UNIFORM IMAGE CARDS
   The homepage service showcase and work mosaic share one card size, so the
   two collections read as one system. Hero and editorial storytelling images
   are intentionally not included: they are full-bleed compositions, not cards.

   This block used to also normalise every .svcx-work-- layout on the service
   pages to the same 3-up 4:3 grid, with !important on the aspect ratio and
   `display:none` on the rail's prev/next buttons. That silently deleted the
   six project-band layouts the service template selects between, and removed
   the only visible control on the two rail pages. The service bands now own
   their own geometry; see SERVICE DETAIL further up this file.
   ============================================================ */
.page-home .service-showcase-grid,
.page-home .home-work .mosaic {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: auto;
  gap: clamp(14px, 1.7vw, 24px);
  max-width: none;
  overflow: visible;
  padding: 0;
}
.page-home .service-showcase-card,
.page-home .service-showcase-card--residential,
.page-home .service-showcase-card--villa,
.page-home .service-showcase-card--healthcare,
.page-home .service-showcase-card--commercial,
.page-home .service-showcase-card--government,
.page-home .service-showcase-card--luxury,
.page-home .service-showcase-card--residential-build,
.page-home .service-showcase-card--commercial-build,
.page-home .service-showcase-card--office,
.page-home .home-work .mosaic > .proj-card,
.page-home .home-work .mosaic > :nth-child(n) {
  grid-column: auto;
  grid-row: auto;
  flex: auto;
  min-height: 0;
  padding: 0;
  transform: none;
  box-shadow: none;
}
.page-home .service-showcase-card,
.page-home .home-work .proj-card { aspect-ratio: 4 / 3 !important; }

@media (max-width: 900px) {
  .page-home .service-showcase-grid,
  .page-home .home-work .mosaic { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 560px) {
  .page-home .service-showcase-grid,
  .page-home .home-work .mosaic { grid-template-columns: minmax(0, 1fr); }
}

/* ============================================================
   HOMEPAGE TWO-COLUMN LAYOUT
   Keep the homepage collections in a calm editorial two-up rhythm on desktop.
   The previous three-up override made the portfolio feel like a thumbnail
   index and left the heading's two-column composition disconnected from it.
   ============================================================ */
.page-home .home-work .mosaic {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.page-home .home-work .mosaic {
  grid-auto-rows: auto;
}

.page-home .home-work .mosaic > .proj-card,
.page-home .home-work .mosaic > :nth-child(6n + 2),
.page-home .home-work .mosaic > :nth-child(6n + 3),
.page-home .home-work .mosaic > :nth-child(6n + 4),
.page-home .home-work .mosaic > :nth-child(6n + 6) {
  grid-column: span 1;
  grid-row: auto;
  aspect-ratio: 4 / 3;
}

@media (max-width: 560px) {
  .page-home .home-work .mosaic {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ============================================================
   HOMEPAGE PROCESS — DESKTOP CAROUSEL
   Desktop now follows the compact process-film composition used on phones.
   It stays in normal document flow; changing stages is automatic or directly
   controlled with the arrows/thumbnails, never tied to the mouse wheel.
   ============================================================ */
@media (min-width: 761px) {
  .page-home .home-system__intro {
    max-width:1180px;
    margin-inline:auto;
  }

  .home-process-scroll {
    height:auto;
    min-height:0;
  }
  .home-process {
    position:relative;
    top:auto;
    display:block;
    width:min(100%, 1180px);
    height:auto;
    aspect-ratio:4 / 3;
    margin-inline:auto;
    overflow:visible;
    border-radius:0;
    background:transparent;
    box-shadow:none;
  }
  .home-process__media {
    width:100%;
    height:100%;
    border-radius:11px;
    box-shadow:0 24px 62px rgba(20,19,42,.22);
  }
  .home-process__media::before,
  .home-process__media::after { width:38px; height:38px; }
  .home-process__media::before { top:12px; right:90px; }
  .home-process__media::after { bottom:12px; left:12px; }
  .home-process__slide { clip-path:inset(0 10% 0 0); }
  .home-process__slide.is-active { clip-path:inset(0); }

  .home-process__caption {
    right:102px;
    bottom:18px;
    left:18px;
    grid-template-columns:34px minmax(0, 1fr);
    width:auto;
    min-height:84px;
    padding:12px 16px;
    border-radius:7px;
    box-shadow:0 14px 38px rgba(8,7,34,.38);
  }
  .home-process__caption-copy { gap:3px; }
  .home-process__caption-copy strong { font-size:clamp(22px, 2.1vw, 27px); }

  .home-process__mobile-controls {
    position:absolute;
    top:50%;
    right:14px;
    bottom:auto;
    z-index:8;
    display:grid;
    grid-template-columns:58px;
    grid-template-rows:36px auto 36px;
    justify-items:center;
    gap:7px;
    transform:translateY(-50%);
  }
  .home-process__mobile-controls > button {
    display:grid;
    place-items:center;
    width:36px;
    height:36px;
    border:1px solid rgba(255,255,255,.42);
    border-radius:50%;
    background:rgba(8,7,34,.5);
    backdrop-filter:blur(8px);
    color:var(--white);
    cursor:pointer;
    font-size:14px;
    transition:background-color .25s ease, transform .25s var(--ease);
  }
  .home-process__mobile-controls > button:hover,
  .home-process__mobile-controls > button:focus-visible {
    background:rgba(8,7,34,.82);
    transform:scale(1.08);
  }
  .home-process__dots {
    display:flex;
    flex-direction:column;
    gap:6px;
  }
  .home-process__dots button {
    position:relative;
    width:58px;
    height:44px;
    overflow:hidden;
    padding:0;
    border:1px solid rgba(255,255,255,.3);
    border-radius:5px;
    background:#11102e;
    cursor:pointer;
    opacity:.58;
    transform:scale(.94);
    transition:opacity .3s ease, transform .4s var(--ease), border-color .3s ease, box-shadow .3s ease;
  }
  .home-process__dots button::before { display:none; }
  .home-process__dots button::after {
    content:'';
    position:absolute;
    right:0;
    bottom:0;
    left:0;
    width:100%;
    height:2px;
    background:var(--gold-lit);
    transform:scaleX(0);
    transform-origin:left;
  }
  .home-process__dots button img {
    display:block;
    width:100%;
    height:100%;
    object-fit:cover;
    filter:saturate(.7) brightness(.78);
    transition:filter .35s ease, transform .55s var(--ease-soft);
  }
  .home-process__dots button span { display:none; }
  .home-process__dots button.is-active {
    border-color:var(--gold-lit);
    box-shadow:0 8px 22px rgba(8,7,34,.42);
    opacity:1;
    transform:translateX(-7px) scale(1);
  }
  .home-process__dots button.is-active img {
    filter:saturate(1) brightness(1);
    transform:scale(1.08);
  }
  .home-process.is-playing .home-process__dots button.is-active::after {
    animation:home-process-dot 3.4s linear forwards;
  }
}

/* Desktop keeps the whole process introduction and its active frame in one
   viewport. The text follows the page's left gutter rather than centring in a
   narrow column; tablet and phone retain their existing compact layout. */
@media (min-width: 1025px) {
  .page-home .home-system {
    padding-block:clamp(22px, 3vh, 40px);
  }
  .page-home .home-system__grid { gap:clamp(12px, 1.8vh, 22px); }
  .page-home .home-system__intro {
    max-width:none;
    margin-inline:0;
    text-align:left;
  }
  .page-home .home-system__intro .section-title {
    max-width:none;
    text-align:left;
    white-space:nowrap;
  }
  .home-process {
    width:min(100%, 1180px);
    height:clamp(400px, 48svh, 600px);
    aspect-ratio:auto;
    margin-inline:0;
  }
}

/* Process layout sizing by viewport: one normal-flow carousel, with a bounded
   media height on every non-phone screen so no breakpoint creates a giant
   image or horizontal overflow. */
.home-process,
.home-process__media { max-width:100%; }

@media (min-width: 761px) and (max-width: 1024px) {
  .page-home .home-system { padding-block:clamp(28px, 4vh, 42px); }
  .page-home .home-system__grid { gap:clamp(14px, 2vh, 20px); }
  .page-home .home-system__intro {
    max-width:none;
    margin-inline:0;
    text-align:left;
  }
  .page-home .home-system__intro .section-title {
    max-width:none;
    font-size:clamp(32px, 5vw, 46px);
    text-align:left;
  }
  .home-process {
    width:100%;
    height:clamp(360px, 54svh, 520px);
    aspect-ratio:auto;
    margin-inline:0;
  }
}

@media (min-width: 1025px) and (max-width: 1439px) {
  .home-process {
    width:100%;
    height:clamp(400px, 50svh, 560px);
  }
}

@media (max-width: 760px) {
  .home-process { width:100%; }
}

/* Desktop restores the original large process photograph. The carousel remains
   in normal flow; JavaScript advances the active image automatically instead
   of tying the stage to scrolling. */
@media (min-width: 761px) {
  .home-process-scroll {
    height:auto;
    min-height:0;
  }
  .home-process {
    width:min(100%, 1180px);
    height:min(660px, calc(100svh - 116px));
    min-height:480px;
    aspect-ratio:auto;
    margin-inline:0;
  }
}
