/* ==========================================================================
   GARD ASSETS — base.css

   THE PALETTE IS THE BRIEF
     White paper, black type, one gold. #b49e34 is the gold on white; #cbb64c is
     the same gold opened up so it survives on photographs. Nothing else has a
     hue: every grey here is black at a lower opacity, and every wash laid over
     a photograph is black. That restriction is the client's and it is the point
     — a second colour would make the page look like a brochure rather than a
     letterhead.

   THE SIGNATURE
     A hairline gold rail down the left of the page, filling as the page is
     read, and a short gold tick where each section begins. It is a measure, not
     an ornament: the firm sells precision and continuity, so the page keeps a
     scale running down its edge.

   TYPE
     Two variables and nothing else: --font-display and --font-text. They are
     rewritten by ?f= at runtime, so every rule below has to go through them.
   ========================================================================== */

:root {
  --paper: #ffffff;
  --ink: #0b0b0b;
  --ink-70: rgba(11, 11, 11, 0.68);
  --ink-45: rgba(11, 11, 11, 0.45);
  --gold: #b49e34;          /* on white */
  --gold-lite: #cbb64c;     /* on black and on photographs */
  --rule: rgba(11, 11, 11, 0.14);
  --rule-soft: rgba(11, 11, 11, 0.08);
  /* One step darker than the section hairlines: the enquiry button is drawn in
     it, and at 1px a 14% line simply disappears against white. */
  --rule-mid: rgba(11, 11, 11, 0.3);

  /* The client's pairing, chosen from the six in the showcase. ?f= still swaps
     both of these at runtime, so no rule below may name a face directly. */
  --font-display: 'Cormorant Garamond', 'Times New Roman', serif;
  --font-text: 'Jost', system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;

  --gut: clamp(20px, 5vw, 84px);
  --rail-x: clamp(14px, 2.6vw, 40px);
  --head-h: 76px;
  --max: 1440px;

  --step: clamp(64px, 9vw, 140px);   /* space between sections */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: clamp(15px, 0.55vw + 13.5px, 17px);
  font-weight: 400;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, .brand-text, .submit, .cue, .nav-toggle-text {
  font-family: var(--font-display);
  font-weight: 400;
}

img, video, picture, svg { display: block; max-width: 100%; }

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

.skip {
  position: absolute;
  left: 12px; top: -60px;
  z-index: 100;
  padding: 10px 16px;
  background: var(--ink);
  color: #fff;
  text-decoration: none;
  transition: top 0.2s var(--ease);
}
.skip:focus { top: 12px; }

.wrap {
  max-width: var(--max);
  margin: 0 auto;
  padding-inline: var(--gut);
}

/* --- placeholders ----------------------------------------------------------
   Loud on purpose. Anything still reading TBD has to be seen from across the
   room, or it is the thing that ships. */
.tbd {
  background: #ffe94a;
  color: #0b0b0b;
  padding: 0.1em 0.4em;
  box-shadow: 0 0 0 2px #0b0b0b;
  font-weight: 500;
  font-family: var(--font-text);
}

/* ==========================================================================
   The rail — the signature
   ========================================================================== */
.rail {
  position: fixed;
  left: var(--rail-x);
  top: 0; bottom: 0;
  width: 1px;
  background: rgba(180, 158, 52, 0.24);
  z-index: 40;
  opacity: 0;
  transition: opacity 0.5s var(--ease);
  pointer-events: none;
}
body.past-hero .rail { opacity: 1; }
.rail-fill {
  display: block;
  width: 1px;
  height: calc(var(--progress, 0) * 100%);
  background: var(--gold);
}
@media (max-width: 1100px) { .rail { display: none; } }

/* ==========================================================================
   Header and menu
   ========================================================================== */
.site-head {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  height: var(--head-h);
  display: flex;
  align-items: center;
  gap: 24px;
  padding-inline: var(--gut);
  color: #fff;
  transition: background 0.35s var(--ease), color 0.35s var(--ease), box-shadow 0.35s var(--ease);
}

/* Desktop, once the page has moved: frosted white over the white page. */
.site-head.is-stuck {
  background: rgba(255, 255, 255, 0.72);
  -webkit-backdrop-filter: blur(16px) saturate(1.6);
  backdrop-filter: blur(16px) saturate(1.6);
  color: var(--ink);
  box-shadow: inset 0 -1px 0 var(--rule);
}
/* The framed first screen already stands on white, so the header starts inked. */
body.v3 .site-head:not(.is-stuck) { color: var(--ink); }
/* The split first screen is white on one side and footage on the other, so the
   bar wears the frosted treatment from the very first pixel rather than at 24px. */
body.v4 .site-head {
  color: var(--ink);
  background: rgba(255, 255, 255, 0.78);
  -webkit-backdrop-filter: blur(16px) saturate(1.6);
  backdrop-filter: blur(16px) saturate(1.6);
  box-shadow: inset 0 -1px 0 var(--rule);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  margin-right: auto;
}
.brand-text {
  font-size: clamp(15px, 1.1vw, 19px);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  white-space: nowrap;
}
.mark {
  width: 30px; height: 30px;
  flex: none;
  color: var(--gold-lite);
  fill: none;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.site-head.is-stuck .mark, body.v3 .site-head .mark, body.v4 .site-head .mark { color: var(--gold); }
.mark:empty { display: none; }
.mark--hero { width: clamp(40px, 4vw, 58px); height: clamp(40px, 4vw, 58px); }

.site-nav ul {
  display: flex;
  gap: clamp(16px, 2.2vw, 38px);
  margin: 0; padding: 0;
  list-style: none;
}
.site-nav a {
  text-decoration: none;
  font-size: 12px;
  letter-spacing: 0.19em;
  text-transform: uppercase;
  padding-block: 6px;
  position: relative;
  opacity: 0.88;
  transition: opacity 0.2s var(--ease);
}
.site-nav a::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.32s var(--ease);
}
.site-nav a:hover { opacity: 1; }
.site-nav a:hover::after, .site-nav a.is-current::after { transform: scaleX(1); }
.site-nav a.is-current { color: var(--gold-lite); opacity: 1; }
.site-head.is-stuck .site-nav a.is-current,
body.v3 .site-head .site-nav a.is-current,
body.v4 .site-head .site-nav a.is-current { color: var(--gold); }

.nav-toggle {
  display: none;
  align-items: center;
  gap: 10px;
  background: none;
  border: 0;
  color: inherit;
  padding: 8px 0;
  cursor: pointer;
  font: inherit;
}
.nav-toggle-text { font-size: 12px; letter-spacing: 0.19em; text-transform: uppercase; }
.nav-toggle-bars {
  position: relative;
  width: 22px; height: 9px;
}
.nav-toggle-bars::before, .nav-toggle-bars::after {
  content: '';
  position: absolute;
  left: 0; right: 0;
  height: 1px;
  background: currentColor;
  transition: transform 0.3s var(--ease), opacity 0.2s var(--ease);
}
.nav-toggle-bars::before { top: 0; }
.nav-toggle-bars::after { bottom: 0; }
body.nav-open .nav-toggle-bars::before { transform: translateY(4px) rotate(45deg); }
body.nav-open .nav-toggle-bars::after { transform: translateY(-4px) rotate(-45deg); }

@media (max-width: 860px) {
  :root { --head-h: 64px; }
  .nav-toggle { display: inline-flex; }
  /* backdrop-filter is cleared here, not only background and box-shadow, and it
     is the line that keeps the menu's scrim on the screen. A backdrop-filter
     establishes a containing block for fixed-position descendants, and the
     dropdown IS a fixed descendant of this header — so while the frosted state
     is on, the panel's `inset: 0` resolves against a 64px-tall header instead of
     against the viewport, and the scrim covers the bar alone while the scrolled
     page shows through the list. With the menu open the frosting is invisible
     anyway (the background above is already none), so dropping it costs nothing
     and the frosted bar on the closed, scrolled page is untouched.
     This also covers the v3/v4 first screens, whose headers carry the same
     property with no scroll condition at all. */
  body.nav-open .site-head {
    color: #fff;
    background: none;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  body.nav-open .site-head .mark { color: var(--gold-lite); }
  /* The panel is a child of the header, so the wordmark and the close control
     have to be lifted above it or they disappear behind the blur. */
  body.nav-open .brand, body.nav-open .nav-toggle { position: relative; z-index: 2; }

  /* The dropdown's backdrop is black — the client asked for it by name. */
  .site-nav {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.72);
    -webkit-backdrop-filter: blur(22px);
    backdrop-filter: blur(22px);
    color: #fff;
    display: grid;
    place-items: center;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.32s var(--ease), visibility 0.32s;
  }
  body.nav-open .site-nav { opacity: 1; visibility: visible; }
  .site-nav ul {
    flex-direction: column;
    align-items: center;
    gap: 6px;
    text-align: center;
  }
  .site-nav a {
    font-family: var(--font-display);
    font-size: clamp(24px, 7vw, 34px);
    letter-spacing: 0.12em;
    padding-block: 10px;
  }
  .site-nav a.is-current { color: var(--gold-lite); }
}

/* ==========================================================================
   The first screen
   ========================================================================== */
.hero {
  position: relative;
  color: #fff;
  isolation: isolate;
}
.hero-media { position: absolute; inset: 0; overflow: hidden; z-index: 0; }
.hero-video {
  width: 100%; height: 100%;
  object-fit: cover;
}
/* Every wash over footage is black. Never anything else. */
.hero-scrim { position: absolute; inset: 0; }
.hero-inner { position: relative; z-index: 1; }

/* MEASURE BEFORE SIZE. The headline is a single sentence of capitals, and the
   client's own mockup sets it wide — one or two lines across most of the
   screen. A large size in a narrow column turns the same sentence into five
   short stacked lines, which is a different picture altogether. So the size is
   held down and every variant is given a measure in pixels rather than in `ch`:
   `ch` is computed from the *text* face at body size, so `22ch` on a container
   whose child is set at 60px display capitals is roughly a third of the column
   it looks like — the headline then overflows its own box to the right instead
   of centring in it. */
.hero-title {
  margin: 0;
  font-size: clamp(28px, 4.4vw, 60px);
  line-height: 1.1;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-wrap: balance;
}
/* 18px on a desktop, the client's number. Tracked capitals do not survive being
   scaled by the same ratio as the headline, so this one falls gently: ~15px on a
   tablet and 14px on a phone, where it is a line of its own under the title. */
.hero-sub {
  margin: 0;
  font-size: clamp(14px, 0.5vw + 10.8px, 18px);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold-lite);
}
.hero-rule {
  display: block;
  width: 64px; height: 1px;
  background: var(--gold-lite);
}
.cue {
  position: absolute;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-size: 11px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  text-decoration: none;
  color: inherit;
  opacity: 0.85;
}
.cue-line { width: 34px; height: 1px; background: currentColor; transform-origin: left; }

/* 1 — the client's mockup: even scrim, headline centred, capitals.
   Two rows, not one centred stack with a floating cue: the words take the free
   height and the scroll indicator gets a row of its own, so the subtitle and
   the cue can never arrive at the same pixel however long the copy runs. */
.hero--1 {
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto;
  justify-items: center;
  align-items: center;
  row-gap: clamp(20px, 3vh, 40px);
  padding: calc(var(--head-h) + 24px) var(--gut) clamp(28px, 5vh, 52px);
}
.hero--1 .hero-scrim { background: linear-gradient(180deg, rgba(0,0,0,0.62), rgba(0,0,0,0.46) 45%, rgba(0,0,0,0.66)); }
.hero--1 .hero-inner {
  display: grid;
  justify-items: center;
  gap: clamp(18px, 2.2vw, 28px);
  text-align: center;
  width: 100%;
  max-width: min(96vw, 1180px);
}
.hero--1 .hero-title { max-width: none; }
.hero--1 .cue { position: static; transform: none; }
.hero--1 .cue-line { display: none; }

/* 2 — footage left open, black only at the foot, headline in the corner. */
/* The foot padding is the cue's room and nothing else's: the indicator lives in
   the bottom corner, so the block above it stops a clear band short of it. */
.hero--2 { min-height: 100svh; display: flex; align-items: flex-end; padding: calc(var(--head-h) + 24px) var(--gut) clamp(96px, 13vh, 132px); }
.hero--2 .hero-scrim { background: linear-gradient(180deg, rgba(0,0,0,0.5) 0 12%, rgba(0,0,0,0.05) 34%, rgba(0,0,0,0.72)); }
.hero--2 .hero-inner { width: 100%; display: grid; gap: clamp(22px, 3vw, 38px); }
.hero--2 .hero-rule--wide { width: 100%; background: rgba(203, 182, 76, 0.55); }
.hero--2 .hero-row { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: clamp(24px, 4vw, 64px); align-items: end; }
.hero--2 .hero-title { max-width: none; }
.hero--2 .hero-aside { display: grid; gap: 18px; justify-items: start; align-content: end; }
.hero--2 .cue { right: var(--gut); bottom: clamp(30px, 4.5vh, 46px); flex-direction: row-reverse; }

/* 3 — the footage held inside a white margin, like a page in a magazine. */
.hero--3 { padding: var(--head-h) 0 0; background: var(--paper); }
.hero-frame {
  position: relative;
  height: calc(100svh - var(--head-h) - var(--gut));
  min-height: 460px;
  margin: 0 var(--gut) var(--gut);
  overflow: hidden;
  color: #fff;
}
.hero--3 .hero-scrim { background: linear-gradient(115deg, rgba(0,0,0,0.72) 0 34%, rgba(0,0,0,0.12) 74%); }
.hero--3 .hero-inner { position: absolute; inset: 0; display: flex; align-items: flex-end; padding: clamp(22px, 3vw, 46px); }
.hero--3 .hero-panel {
  display: grid;
  gap: 20px;
  max-width: min(90%, 560px);
  padding: clamp(24px, 3vw, 40px);
  background: rgba(0, 0, 0, 0.52);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border-left: 1px solid var(--gold-lite);
}
.hero--3 .hero-title { font-size: clamp(23px, 2.4vw, 34px); }
.hero--3 .cue { right: clamp(22px, 3vw, 46px); bottom: clamp(22px, 3vw, 46px); flex-direction: row-reverse; }

/* 4 — the screen cut in two: white column of black type, footage beside it. */
.hero--4 { background: var(--paper); color: var(--ink); }
/* The white column is given a little more of the screen than half the footage:
   the headline is the reason this variant exists, and it has to have somewhere
   to be wide. */
.hero-split {
  display: grid;
  grid-template-columns: minmax(0, 5.6fr) minmax(0, 6.4fr);
  min-height: 100svh;
}
.hero--4 .hero-card {
  position: relative;
  display: grid;
  align-content: center;
  gap: 26px;
  padding: calc(var(--head-h) + 40px) clamp(24px, 4vw, 72px) 64px;
}
.hero--4 .hero-title { color: var(--ink); font-size: clamp(27px, 3.5vw, 48px); }
.hero--4 .hero-rule { background: var(--gold); width: 88px; }
.hero--4 .hero-sub { color: var(--gold); }
.hero--4 .hero-media { position: relative; inset: auto; min-height: 320px; }
.hero--4 .hero-scrim { background: linear-gradient(90deg, rgba(0,0,0,0.28), rgba(0,0,0,0.05)); }
.hero--4 .cue { position: static; margin-top: 10px; color: var(--ink-45); }

@media (max-width: 860px) {
  .hero-split { grid-template-columns: 1fr; min-height: 0; }
  .hero--4 .hero-media { order: -1; height: 52svh; }
  .hero--4 .hero-card { padding: 44px var(--gut) 56px; }
  .hero--2 .hero-row { grid-template-columns: 1fr; align-items: start; }
  .hero--2 .hero-title { max-width: none; }
  .hero--2 .cue, .hero--3 .cue { display: none; }
  .hero-frame { height: calc(100svh - var(--head-h) - 20px); margin: 0 12px 12px; }
}

/* ==========================================================================
   Sections
   ========================================================================== */
.section, .hero { scroll-margin-top: calc(var(--head-h) - 1px); }
.section { padding-block: var(--step); }
.section--services { padding-block: var(--step) 0; }
.section--services + .section { padding-top: var(--step); }
.section--advantages { padding-bottom: var(--step); }

/* The section heading is now a display line, not an eyebrow: 45px in the
   display face at the client's instruction. The gold tick stays, but it can no
   longer hang off a baseline shared with 45px type — it is lifted against the
   heading's own cap height instead, so the rule sits mid-word rather than under
   the letters. */
.head {
  display: flex;
  align-items: baseline;
  gap: clamp(14px, 1.6vw, 24px);
  margin-bottom: clamp(30px, 3.4vw, 54px);
}
.head .tick {
  flex: none;
  align-self: center;
  width: clamp(28px, 4vw, 64px);
  height: 1px;
  background: var(--gold);
}
/* 45px on a desktop → ~34px on a tablet → 28px on a phone, where 45px capitals
   would take three lines of a 390px screen before the section has begun. The
   face comes from --font-display, so ?f= still swaps it with everything else. */
.head h2 {
  margin: 0;
  font-size: clamp(28px, 1.82vw + 18.8px, 45px);
  line-height: 1.12;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--ink);
}

.prose p { margin: 0 0 1.15em; }
.prose p:last-child { margin-bottom: 0; }

/* --- About: text left, photograph right ---------------------------------- */
/* Both paragraphs are set at the same size at the client's instruction — the
   hierarchy is carried by colour alone now, not by size. The block starts at the
   top of the row rather than centred in it, so its first line sits level with
   the top edge of the photograph beside it. `start` alone leaves the text a
   line's half-leading low, which is visible against a hard photographic edge, so
   the first line is pulled back up by exactly that half-leading. */
.about {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(28px, 5vw, 96px);
  align-items: stretch;
}
.about-copy { align-self: start; }
.about-copy p {
  font-family: var(--font-display);
  font-size: clamp(20px, 1.95vw, 28px);
  line-height: 1.36;
  letter-spacing: 0.005em;
}
.about-copy p:first-child { margin-top: -0.18em; }
.about-copy p + p {
  line-height: 1.36;
  color: var(--ink-70);
  max-width: 54ch;
  margin-top: 0.9em;
}
/* The photograph takes the height of the row rather than a height of its own,
   so it always stands level with the copy beside it instead of stopping short. */
.about-shot { display: grid; }
.about-shot picture { display: block; height: 100%; }
.about-shot img {
  width: 100%;
  height: 100%;
  min-height: clamp(300px, 32vw, 470px);
  object-fit: cover;
}

@media (max-width: 860px) {
  .about { grid-template-columns: 1fr; }
  .about-shot { order: -1; }
}

/* --- Services: two photographs that carry their own copy ------------------ */
.section--services .wrap { padding-inline: 0; max-width: none; }
.section--services .head { max-width: var(--max); margin-inline: auto; padding-inline: var(--gut); }
.services { display: grid; }
.service {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: flex-end;
  min-height: clamp(560px, 82vh, 780px);
  padding: clamp(36px, 6vw, 96px) var(--gut);
  color: #fff;
}
.service--right { justify-content: flex-end; }
.shot--cover { position: absolute; inset: 0; z-index: 0; }
.shot--cover img { width: 100%; height: 100%; object-fit: cover; }
/* Two black washes, never anything but black: one across the frame, one heavier
   on the side the words sit, so the copy holds on a bright photograph as well
   as a dark one. */
.service::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(90deg, rgba(0,0,0,0.86) 0 38%, rgba(0,0,0,0.3) 76%, rgba(0,0,0,0.2)),
    linear-gradient(180deg, rgba(0,0,0,0.4), rgba(0,0,0,0.62));
}
.service--right::after {
  background:
    linear-gradient(270deg, rgba(0,0,0,0.86) 0 38%, rgba(0,0,0,0.3) 76%, rgba(0,0,0,0.2)),
    linear-gradient(180deg, rgba(0,0,0,0.4), rgba(0,0,0,0.62));
}
.service-body { position: relative; z-index: 2; max-width: 58ch; display: grid; gap: clamp(20px, 2.4vw, 32px); }
.service-body h3 {
  margin: 0;
  font-size: clamp(26px, 3.4vw, 46px);
  line-height: 1.14;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
}
.lines { margin: 0; padding: 0; list-style: none; display: grid; }
/* 21px on a desktop, the client's number — these are long sentences, so the
   measure above (58ch) is what keeps them from running the width of the screen.
   ~18px on a tablet and ~16px on a phone, where 21px would give three or four
   lines per bullet. */
.lines li {
  padding: 14px 0 14px 26px;
  position: relative;
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  font-size: clamp(15.5px, 0.5vw + 13.8px, 21px);
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.9);
}
.lines li::before {
  content: '';
  position: absolute;
  /* the middle of the first line, whatever size that line ends up: the padding
     is fixed, half the line box is not */
  left: 0; top: calc(14px + 0.75em);
  width: 12px; height: 1px;
  background: var(--gold-lite);
}
.lines li:last-child { border-bottom: 1px solid rgba(255, 255, 255, 0.18); }

@media (max-width: 720px) {
  .service { min-height: 0; padding-block: 56px; }
  .service-body h3 { font-size: clamp(23px, 7vw, 30px); }
}

/* --- Sectors: the words set ON the photograph -----------------------------
   The client's instruction for this section was "the same as on the other
   site", and on that site a sector is not a thumbnail with a caption under it:
   it is a photograph with a permanent black veil, the title in gold and the
   list in white sitting at the foot of the frame, and the six tiles butt
   together into one block separated by hairlines. The hover is inverted on
   purpose — the photograph steps back so the words gain contrast, rather than
   the photograph coming forward. What stays ours: the page around it is white,
   the accent is our gold, and every veil is black. */
.tiles {
  margin: 0; padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 2.4vw, 40px) clamp(20px, 2.6vw, 48px);
}
.tiles--sectors { gap: 1px; background: var(--rule); }
.sector {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: clamp(320px, 27vw, 400px);
  padding: clamp(22px, 2.2vw, 34px);
  background: var(--ink);
  color: #fff;
}
.sector .shot--cover img {
  opacity: 0.7;
  filter: saturate(0.85) contrast(1.02);
  transition: opacity 0.55s var(--ease), filter 0.55s var(--ease);
}
.sector::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(0deg, rgba(0,0,0,0.92) 14%, rgba(0,0,0,0.34));
  transition: background 0.55s var(--ease);
}
.sector:hover .shot--cover img { opacity: 0.22; filter: saturate(0.5) contrast(1); }
.sector:hover::after { background: linear-gradient(0deg, rgba(0,0,0,0.96) 12%, rgba(0,0,0,0.8)); }
.sector-body { position: relative; z-index: 2; }
/* 32px on a desktop at the client's instruction. The tiles are three across, so
   a title has roughly 430px of frame to sit in — "Infrastructure" in tracked
   32px capitals is about 300px of that. Two across on a tablet is the same width
   again, so the size barely moves; on a phone the tile is full width and 24px is
   plenty. */
.sector h3 {
  margin: 0 0 14px;
  font-size: clamp(24px, 1vw + 17.6px, 32px);
  line-height: 1.15;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-lite);
}
/* 21px, the same number the client gave for the service bullets. */
.lines--tight li {
  padding: 9px 0 9px 22px;
  font-size: clamp(15.5px, 0.5vw + 13.8px, 21px);
}
.lines--tight li::before { top: calc(9px + 0.75em); width: 10px; }

/* --- Advantages: six photographs with the words set on them --------------- */
.advantage {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: flex-end;
  min-height: clamp(280px, 30vw, 400px);
  padding: clamp(22px, 2.2vw, 34px);
  color: #fff;
  overflow: hidden;
}
.advantage::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(0,0,0,0.12) 0 26%, rgba(0,0,0,0.72) 58%, rgba(0,0,0,0.92));
  transition: opacity 0.5s var(--ease);
}
.advantage .shot--cover img {
  filter: grayscale(0.5) contrast(1.05);
  transition: transform 0.8s var(--ease), filter 0.8s var(--ease);
}
.advantage:hover .shot--cover img { filter: grayscale(0) contrast(1); }
.advantage:hover .shot--cover img { transform: scale(1.05); }
.advantage-body { position: relative; z-index: 2; display: grid; gap: 10px; }
/* 32px, the same as a sector title — the client asked for the two sets to match.
   At that size two of the six titles take a second line, and with the block
   pinned to the foot of the tile that alone would put every title in the row at
   a different height. Two lines are therefore reserved for the title exactly as
   three are for the caption below it: both edges then hold across the row. On a
   phone the tiles are stacked one per row, nothing has to line up with anything,
   and the reservation is dropped so it does not read as a gap. */
.advantage h3 {
  margin: 0;
  min-height: 2.3em;
  font-size: clamp(24px, 1vw + 17.6px, 32px);
  line-height: 1.15;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-lite);
}
/* The captions run from one line to three, and with the block pinned to the
   foot of the tile that pushed each title to a different height — six tiles
   that ought to read as one set. Reserving three lines for the caption fixes
   both edges at once: the titles line up across the row and the block still
   ends level with the bottom of every frame. */
.advantage p {
  margin: 0;
  font-size: clamp(15.5px, 0.5vw + 13.8px, 21px);
  line-height: 1.45;
  min-height: 4.35em;
  max-width: 30ch;
  color: rgba(255, 255, 255, 0.92);
}

@media (max-width: 980px) { .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) {
  .tiles { grid-template-columns: 1fr; }
  .advantage h3 { min-height: 0; }
  .advantage p { min-height: 0; }
}

/* --- Contact: photograph left, form right --------------------------------- */
.contact {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(28px, 4vw, 72px);
  align-items: stretch;
}
/* Photograph left, words and form right. The copy used to be set in white over
   the foot of the photograph, where it read as an accident rather than as a
   caption; it now sits at the head of the reading column, and the photograph is
   left to be a photograph — full height of the row, no veil, because nothing is
   written on it any more. */
.contact-shot {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: clamp(360px, 46vw, 660px);
}
.contact-words p {
  font-family: var(--font-display);
  font-size: clamp(18px, 1.5vw, 22px);
  line-height: 1.45;
  max-width: 48ch;
}
.contact-words p + p { color: var(--ink-70); }

.contact-panel { display: grid; align-content: start; gap: clamp(24px, 2.8vw, 38px); }
.form { display: grid; gap: 22px; margin: 0; }
.field { display: grid; gap: 8px; margin: 0; }
.field label {
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-45);
}
.field input, .field textarea {
  font: inherit;
  font-family: var(--font-text);
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule);
  padding: 10px 2px;
  border-radius: 0;
  transition: border-color 0.3s var(--ease);
  width: 100%;
}
.field textarea { resize: vertical; min-height: 120px; }
.field input:hover, .field textarea:hover { border-bottom-color: var(--ink-45); }
.field input:focus, .field textarea:focus {
  outline: none;
  border-bottom-color: var(--gold);
  box-shadow: 0 1px 0 0 var(--gold);
}
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
/* The captcha, when a site key was given at build time. Left-aligned with the
   button under it rather than stretched across the column. */
.cf-turnstile { justify-self: start; }

/* The client's button: white, an outline a step lighter than the near-black it
   used to be filled with, and the word one size up. 14px holds on every screen —
   it is twelve tracked capitals, not a paragraph — so this one does not scale. */
.submit {
  justify-self: start;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--rule-mid);
  padding: 15px 40px;
  font-size: 14px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.3s var(--ease), color 0.3s var(--ease), border-color 0.3s var(--ease);
}
.submit:hover { background: var(--paper); border-color: var(--gold); color: var(--gold); }
/* The standing promise under the button, and then the answer from the server in
   the same place. Red is the one exception to "no second hue on this page": a
   refusal that is merely grey is read as decoration and the visitor leaves
   believing the enquiry went. */
.form-note {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-45);
}
.form-note:focus { outline: none; }
.form-note:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.form-note.is-live { color: var(--gold); }
.form-note.is-error { color: #b3352e; }

.details { margin: 0; padding: 0; list-style: none; display: grid; gap: 0; }
.details li {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: 16px;
  align-items: baseline;
  padding: 16px 0;
  border-top: 1px solid var(--rule-soft);
}
.details li span {
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-45);
}

@media (max-width: 860px) {
  .contact { grid-template-columns: 1fr; }
  .contact-shot { min-height: 300px; }
}

/* ==========================================================================
   Footer
   ========================================================================== */
.site-foot {
  border-top: 1px solid var(--rule);
  padding-block: clamp(34px, 4vw, 56px);
}
.site-foot .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 12px clamp(20px, 4vw, 60px);
}
.site-foot p { margin: 0; font-size: 13px; color: var(--ink-45); }
.foot-brand {
  font-family: var(--font-display);
  font-size: 15px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ink) !important;
}
.foot-legal { margin-left: auto !important; }
@media (max-width: 560px) { .foot-legal { margin-left: 0 !important; } }

/* ==========================================================================
   Motion — entrances are a courtesy, never a requirement
   ========================================================================== */
/* The class is added by site.js, never by the markup: with the script blocked
   the page is simply visible, which is the only acceptable failure mode. */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
  .reveal { opacity: 1 !important; transform: none !important; }
  .sector:hover .sector-shot img,
  .advantage:hover .shot--cover img { transform: none; }
}
