/* ==========================================================================
   Crawford Legal — Components
   ========================================================================== */

/* ==========================================================================
   Header
   ========================================================================== */
.c-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--z-header);
  height: var(--header-h);
  display: flex;
  align-items: center;
  background: transparent;
  transition:
    height var(--d-base) var(--e-out),
    background-color var(--d-base) var(--e-out),
    backdrop-filter var(--d-base) var(--e-out),
    border-color var(--d-base) var(--e-out);
  border-bottom: 1px solid transparent;
}

/* Scrolled: softly blurred, slimmer, still high contrast. */
.c-header.is-stuck {
  height: var(--header-h-slim);
  background: rgb(var(--rgb-black) / 0.72);
  backdrop-filter: blur(14px) saturate(1.2);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  border-bottom-color: var(--rule-on-dark);
}
/* No backdrop-filter support → solid, so contrast never degrades. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .c-header.is-stuck { background: rgb(var(--rgb-black) / 0.96); }
}

.c-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-6);
  width: 100%;
}

.c-header__logo {
  display: flex;
  align-items: center;
  min-height: 44px;      /* the mark is 20px tall; the target must not be */
  flex-shrink: 0;
  transition: opacity var(--d-fast) var(--e-out);
}
.c-header__logo img {
  width: clamp(10rem, 14vw, 13rem);
  height: auto;
}
.c-header__logo:hover { opacity: 0.78; }

/* ---------- Desktop nav ---------- */
.c-nav { display: none; }
@media (min-width: 64rem) {
  .c-nav {
    display: flex;
    align-items: center;
    gap: clamp(1.5rem, 2.4vw, 2.75rem);
  }
}

.c-nav__link {
  position: relative;
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--text-on-dark);
  padding-block: var(--sp-2);
  transition: color var(--d-fast) var(--e-out);
}
.c-nav__link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--c-orange);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform var(--d-base) var(--e-out);
}
.c-nav__link:hover::after,
.c-nav__link:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left center;
}
.c-nav__link:hover { color: var(--c-orange); }

/* Scroll-spy active state. Uses an underline + colour + aria-current —
   never colour alone. */
.c-nav__link[aria-current="true"] { color: var(--c-orange); }
.c-nav__link[aria-current="true"]::after {
  transform: scaleX(1);
  transform-origin: left center;
}

/* ---------- Menu toggle (mobile) ---------- */
.c-menu-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  color: var(--text-on-dark);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  padding: var(--sp-2);
  margin-right: calc(var(--sp-2) * -1);
}
@media (min-width: 64rem) { .c-menu-toggle { display: none; } }

.c-menu-toggle__bars {
  position: relative;
  width: 26px;
  height: 12px;
  flex-shrink: 0;
}
.c-menu-toggle__bars span {
  position: absolute;
  left: 0;
  width: 100%;
  height: 1.5px;
  background: currentColor;
  transition: transform var(--d-base) var(--e-out), opacity var(--d-fast) var(--e-out);
}
.c-menu-toggle__bars span:nth-child(1) { top: 0; }
.c-menu-toggle__bars span:nth-child(2) { bottom: 0; }

.c-menu-toggle[aria-expanded="true"] .c-menu-toggle__bars span:nth-child(1) {
  transform: translateY(5.25px) rotate(45deg);
}
.c-menu-toggle[aria-expanded="true"] .c-menu-toggle__bars span:nth-child(2) {
  transform: translateY(-5.25px) rotate(-45deg);
}

/* ==========================================================================
   Mobile menu — full-screen editorial panel
   ========================================================================== */
.c-mobile-menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  background: var(--c-black);
  display: flex;
  flex-direction: column;
  padding-top: var(--header-h);
  visibility: hidden;
  opacity: 0;
  transition:
    opacity var(--d-base) var(--e-out),
    visibility 0s linear var(--d-base);
}
.c-mobile-menu.is-open {
  visibility: visible;
  opacity: 1;
  transition:
    opacity var(--d-base) var(--e-out),
    visibility 0s linear 0s;
}
@media (min-width: 64rem) { .c-mobile-menu { display: none; } }

.c-mobile-menu__inner {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--sp-7);
  overflow-y: auto;
  padding-block: var(--sp-7);
}

.c-mobile-menu__list { display: flex; flex-direction: column; }

.c-mobile-menu__item { overflow: hidden; }

.c-mobile-menu__link {
  display: flex;
  align-items: baseline;
  gap: var(--sp-4);
  padding-block: var(--sp-4);
  border-bottom: 1px solid var(--rule-on-dark);
  font-family: var(--font-serif);
  font-size: clamp(2rem, 9vw, 3rem);
  line-height: 1.1;
  letter-spacing: var(--ls-heading);
  color: var(--text-on-dark);
  transform: translate3d(0, 110%, 0);
  transition:
    transform var(--d-slow) var(--e-editorial),
    color var(--d-fast) var(--e-out);
  transition-delay: var(--item-delay, 0ms);
}
.is-open .c-mobile-menu__link { transform: translate3d(0, 0, 0); }
.c-mobile-menu__link:hover,
.c-mobile-menu__link:focus-visible { color: var(--c-orange); }

.c-mobile-menu__index {
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  color: var(--c-orange);
  flex-shrink: 0;
}

.c-mobile-menu__foot {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  color: var(--text-on-dark-muted);
  font-size: var(--fs-small);
  opacity: 0;
  transition: opacity var(--d-slow) var(--e-out) 380ms;
}
.is-open .c-mobile-menu__foot { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .c-mobile-menu__link { transform: none; transition-delay: 0ms; }
  .c-mobile-menu__foot { transition-delay: 0ms; }
}

/* ==========================================================================
   Hero
   ========================================================================== */
.c-hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  padding-block: calc(var(--header-h) + var(--sp-7)) var(--sp-9);
  overflow: hidden;
  background: var(--c-black);
}

.c-hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.c-hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Portrait: hold the warm light and the curve in frame. */
  object-position: 72% 42%;
  /* Parallax + entry scale, driven by --hero-shift (JS) */
  transform: scale(var(--hero-scale, 1.08)) translate3d(0, var(--hero-shift, 0px), 0);
  transition: transform var(--d-hero) var(--e-editorial);
  will-change: transform;
}
.c-hero.is-ready .c-hero__media img { --hero-scale: 1; }
@media (min-width: 64rem) {
  .c-hero__media img { object-position: 62% center; }
}

/* Legibility scrim.
   Mobile first: a vertical scrim only where the text sits, so the architecture
   stays visible. (A left-weighted diagonal is wrong on a narrow portrait
   viewport — nearly the whole frame falls in its darkest band and the image
   reads as black.) */
.c-hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    to top,
    rgb(var(--rgb-black) / 0.92) 0%,
    rgb(var(--rgb-black) / 0.78) 28%,
    rgb(var(--rgb-black) / 0.30) 58%,
    rgb(var(--rgb-black) / 0.12) 100%
  );
}

/* Portrait phones: the content stack (title, kicker, button, awards) fills most
   of the frame, so there is no dark zone left to sit the text in — the title
   lands on the lit concrete. Measured on a 430px viewport before this rule:
   title 1.48:1 against a required 3, kicker 1.00:1 against a required 4.5 (the
   brand orange is almost exactly the luminance of the sunlit concrete, so it
   vanishes). No colour choice fixes that; only the ground can move.

   So on a phone the image comes down hard. It still reads as texture and warmth,
   which is the job it is doing here — and a phone is the device most likely to
   be read in daylight. Legibility wins. */
@media (max-width: 63.999rem) {
  .c-hero__scrim {
    background: linear-gradient(
      to top,
      rgb(var(--rgb-black) / 0.94) 0%,
      rgb(var(--rgb-black) / 0.90) 52%,
      rgb(var(--rgb-black) / 0.82) 78%,
      rgb(var(--rgb-black) / 0.62) 100%
    );
  }
}

/* Wide: the headline sits left, so weight the scrim left and let the right
   side of the frame open up. */
@media (min-width: 64rem) {
  .c-hero__scrim {
    background:
      linear-gradient(100deg, rgb(var(--rgb-black) / 0.94) 0%, rgb(var(--rgb-black) / 0.72) 34%, rgb(var(--rgb-black) / 0.18) 62%, rgb(var(--rgb-black) / 0.05) 100%),
      linear-gradient(to top, rgb(var(--rgb-black) / 0.85) 0%, rgb(var(--rgb-black) / 0) 52%);
  }
}

/* Slow warm light drift — the "alive" cue. Pure opacity/transform. */
.c-hero__glow {
  position: absolute;
  z-index: 1;
  right: -10%;
  bottom: -20%;
  width: 70vw;
  height: 70vw;
  max-width: 900px;
  max-height: 900px;
  pointer-events: none;
  background: radial-gradient(circle at center, rgb(var(--rgb-orange) / 0.30) 0%, rgb(var(--rgb-orange) / 0.10) 42%, rgb(var(--rgb-orange) / 0) 68%);
  animation: hero-drift 18s var(--e-in-out) infinite alternate;
}
@keyframes hero-drift {
  from { transform: translate3d(0, 0, 0) scale(1); opacity: 0.7; }
  to   { transform: translate3d(-4%, -6%, 0) scale(1.14); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .c-hero__glow { animation: none; }
  .c-hero__media img { transform: none !important; }
}

.c-hero__inner { position: relative; z-index: var(--z-raised); width: 100%; }
.c-hero__content { max-width: 56rem; }

/* ---------- Awards, bottom-right of the hero ----------
   Set as TYPE, not the badge artwork. The Doyle's marks are black text on a
   transparent ground — measured 1.11:1 against this hero, i.e. an orange laurel
   around invisible words. Making them legible here would mean recolouring an
   awarding body's mark a second time, purely to sit on our photograph.

   The hero is bottom-aligned and its scrim is bottom-weighted (0.92 black at the
   foot), so this corner is the strongest ground on the image for light text.

   Both 2026 rankings, deliberately: leading on construction alone framed the firm
   as a construction practice before the reader knew what it does. */
@media (min-width: 64rem) {
  .c-hero__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    gap: var(--sp-7);
  }
}
.c-hero__awards { margin-top: var(--sp-7); }
@media (min-width: 64rem) {
  .c-hero__awards { margin-top: 0; text-align: right; }
}
.c-hero__awards-src {
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-orange);
  margin-bottom: var(--sp-3);
}
.c-hero__awards-list { list-style: none; display: grid; gap: var(--sp-2); }
.c-hero__awards-list li {
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-on-dark-muted);
}
/* The year belongs to the line, not the header: the construction ranking is
   2026 but the TMT one is 2025, and a shared "2025/2026" header would read as
   First Tier in both years. It was Recommended in 2025. */
.c-hero__awards-yr {
  color: var(--text-on-dark-muted);
  font-variant-numeric: tabular-nums;
}
.c-hero__awards-yr::before { content: "· "; }
.c-hero__awards-list b {
  font-weight: var(--fw-medium);
  color: var(--text-on-dark);
}

.c-hero__title { margin-bottom: var(--sp-5); }
.c-hero__title .c-anim-text__line:nth-child(2) { color: var(--c-orange); }

.c-hero__lead {
  color: var(--text-on-dark);
  max-width: 34ch;
  margin-bottom: var(--sp-7);
}

/* Scroll cue */
.c-hero__cue {
  position: absolute;
  right: 0;
  bottom: var(--sp-2);
  z-index: var(--z-raised);
  display: none;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-on-dark-muted);
}
@media (min-width: 64rem) { .c-hero__cue { display: flex; } }
.c-hero__cue-track {
  position: relative;
  width: 1px;
  height: 54px;
  background: var(--rule-on-dark);
  overflow: hidden;
}
.c-hero__cue-track::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--c-orange);
  transform-origin: top center;
  animation: cue-run 2.4s var(--e-in-out) infinite;
}
@keyframes cue-run {
  0%   { transform: translateY(-100%); }
  60%  { transform: translateY(100%); }
  100% { transform: translateY(100%); }
}
@media (prefers-reduced-motion: reduce) {
  .c-hero__cue-track::after { animation: none; transform: none; opacity: 0.5; }
}

/* ==========================================================================
   Button / arrow link
   ========================================================================== */
.c-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-orange);
  padding-block: var(--sp-3);
  border-bottom: 1px solid var(--rule-accent);
  transition: color var(--d-fast) var(--e-out), border-color var(--d-fast) var(--e-out);
}
.c-btn:hover, .c-btn:focus-visible {
  color: var(--c-orange-lift);
  border-bottom-color: var(--c-orange-lift);
}
.c-btn__arrow {
  width: 1.5rem;
  height: 1px;
  position: relative;
  background: currentColor;
  transition: width var(--d-base) var(--e-out);
  flex-shrink: 0;
}
.c-btn__arrow::after {
  content: "";
  position: absolute;
  right: 0; top: 50%;
  width: 6px; height: 6px;
  border-top: 1px solid currentColor;
  border-right: 1px solid currentColor;
  transform: translateY(-50%) rotate(45deg);
  transform-origin: center;
}
.c-btn:hover .c-btn__arrow,
.c-btn:focus-visible .c-btn__arrow { width: 2.25rem; }

/* Solid variant — used on the orange CTA band. */
.c-btn--solid {
  background: var(--c-black);
  color: var(--c-orange);
  border: 1px solid var(--c-black);
  border-radius: var(--r-pill);
  padding: var(--sp-4) var(--sp-6);
  transition: background-color var(--d-base) var(--e-out), color var(--d-base) var(--e-out);
}
.c-btn--solid:hover, .c-btn--solid:focus-visible {
  background: var(--c-charcoal);
  color: var(--c-orange-lift);
  border-color: var(--c-charcoal);
}

.t-light .c-btn, .t-light-2 .c-btn {
  color: var(--accent-on-light);
  border-bottom-color: rgb(var(--rgb-burnt) / 0.45);
}
.t-light .c-btn:hover, .t-light-2 .c-btn:hover,
.t-light .c-btn:focus-visible, .t-light-2 .c-btn:focus-visible {
  color: var(--c-burnt-deep);
  border-bottom-color: var(--c-burnt-deep);
}

/* ==========================================================================
   Services — numbered editorial rows, image-led on hover/expand
   ========================================================================== */
.c-services__list { border-top: 1px solid var(--rule-on-light); }

.c-service {
  border-bottom: 1px solid var(--rule-on-light);
  position: relative;
}

/* The row header is a real <button> controlling a panel. */
.c-service__head {
  display: grid;
  grid-template-columns: 1.75rem 1fr auto;
  align-items: baseline;
  gap: var(--sp-3) var(--sp-4);
  width: 100%;
  padding-block: var(--sp-5);
  text-align: left;
  color: var(--text-on-light);
  transition: color var(--d-base) var(--e-out);
}
@media (min-width: 48rem) {
  .c-service__head { grid-template-columns: 2.5rem 1fr auto; gap: var(--sp-5); }
}

/* Title + always-visible one-line summary share the middle column, so all five
   rows stay legible and on-screen together without opening anything. */
.c-service__titlewrap {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-width: 0;
}
.c-service__summary {
  font-family: var(--font-sans);
  font-size: var(--fs-small);
  line-height: 1.45;
  font-weight: var(--fw-regular);
  color: var(--text-on-light-muted);
  max-width: 52ch;
}

/* Warm wash that sweeps in behind the row on hover/open. */
.c-service::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgb(var(--rgb-orange) / 0.09) 0%, rgb(var(--rgb-orange) / 0) 72%);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--d-slow) var(--e-editorial);
  pointer-events: none;
}
.c-service:hover::before,
.c-service:focus-within::before,
.c-service.is-open::before { transform: scaleX(1); }

.c-service__index {
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  color: var(--accent-on-light);
  font-variant-numeric: tabular-nums;
}

.c-service__title {
  font-family: var(--font-serif);
  /* The button sits inside an <h3>, which is bold by UA default — without this
     the title renders in a heavy weight that fights the editorial serif used
     for every other heading on the page. */
  font-weight: var(--fw-regular);
  font-size: clamp(1.375rem, 0.95rem + 1.5vw, 2.125rem);
  line-height: 1.1;
  letter-spacing: var(--ls-heading);
  transition: transform var(--d-slow) var(--e-editorial);
}
/* Nudge on hover only. Keeping the shift while open would leave the title 8px
   out of line with the panel copy sitting directly beneath it — and an open row
   already reads as active from the wash and the minus icon. */
@media (min-width: 48rem) {
  .c-service:not(.is-open):hover .c-service__titlewrap { transform: translateX(8px); }
}
.c-service__titlewrap { transition: transform var(--d-slow) var(--e-editorial); }

/* Plus/minus indicator */
.c-service__icon {
  position: relative;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: var(--accent-on-light);
}
.c-service__icon::before,
.c-service__icon::after {
  content: "";
  position: absolute;
  top: 50%; left: 0;
  width: 100%;
  height: 1.5px;
  background: currentColor;
  transition: transform var(--d-base) var(--e-out);
}
.c-service__icon::after { transform: rotate(90deg); }
.c-service.is-open .c-service__icon::after { transform: rotate(0deg); }

/* Panel: the grid-rows 0fr→1fr trick animates height without the children
   needing a measured pixel height.
   Collapsed state is scoped to .js — without JS every panel stays open and
   the whole services section is readable as plain content. */
.c-service__panel {
  display: grid;
  grid-template-rows: 1fr;
}
.js .c-service__panel {
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--d-slow) var(--e-editorial);
}
.js .c-service.is-open .c-service__panel { grid-template-rows: 1fr; }
.c-service__panel-inner { overflow: hidden; }

/* A 0fr grid row still clips rather than removes: without this the collapsed
   copy stays in the accessibility tree and its links stay tabbable inside a
   zero-height box. `visibility: hidden` removes both, and delaying it until
   the collapse finishes means the content is still visible while animating
   out. (The `hidden` attribute can't do this job — the panel's own
   `display: grid` beats the UA `[hidden] { display: none }` rule.) */
.js .c-service__panel-inner {
  visibility: hidden;
  transition: visibility 0s linear var(--d-slow);
}
.js .c-service.is-open .c-service__panel-inner {
  visibility: visible;
  transition-delay: 0s;
}

.c-service__body {
  display: grid;
  gap: var(--sp-6);
  padding-bottom: var(--sp-8);
  /* Indent to the title's column, not the row's left edge — otherwise the panel
     copy hangs 72px left of the heading it belongs to. Mirrors the head grid:
     index column + gap. */
  padding-left: calc(1.75rem + var(--sp-4));
}
@media (min-width: 48rem) {
  .c-service__body { padding-left: calc(2.5rem + var(--sp-5)); }
}
.js .c-service__body {
  opacity: 0;
  transform: translate3d(0, 12px, 0);
  transition:
    opacity var(--d-base) var(--e-out),
    transform var(--d-base) var(--e-out);
}
.js .c-service.is-open .c-service__body {
  opacity: 1;
  transform: none;
  transition-delay: 140ms;
}
@media (min-width: 64rem) {
  .c-service__body {
    grid-template-columns: 1.05fr 0.95fr;
    gap: var(--sp-8);
    align-items: start;
  }
}
@media (prefers-reduced-motion: reduce) {
  .js .c-service__panel { transition: none; }
  .js .c-service__body { opacity: 1; transform: none; transition: none; transition-delay: 0ms; }
}

.c-service__media {
  aspect-ratio: 4 / 3;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--c-charcoal-2);
  order: -1;
}
@media (min-width: 64rem) { .c-service__media { order: 0; aspect-ratio: 5 / 4; } }
.c-service__media img { width: 100%; height: 100%; object-fit: cover; }

.c-service__desc { color: var(--text-on-light-muted); margin-bottom: var(--sp-6); }

.c-service__sub {
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-on-light);
  margin-bottom: var(--sp-4);
}

.c-service__points {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-bottom: var(--sp-6);
}
.c-service__points li {
  font-size: var(--fs-small);
  line-height: 1.35;
  color: var(--text-on-light-muted);
  border: 1px solid var(--rule-on-light);
  border-radius: var(--r-pill);
  padding: var(--sp-2) var(--sp-4);
  background: var(--bg-light-2);
}

/* These were authored for the light services section. That section is gone —
   they now live only inside dark dialogs, where the light-theme defaults left
   "Key contact:" at 1.13:1 (literally invisible) and every name at 3.18:1.
   Default to DARK, and override for any light context they get reused in. */
.c-service__people {
  font-size: var(--fs-small);
  color: var(--text-on-dark-muted);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-3);
}
.c-service__people strong {
  color: var(--text-on-dark);
  font-weight: var(--fw-medium);
}
.t-light .c-service__people, .t-light-2 .c-service__people { color: var(--text-on-light-muted); }
.t-light .c-service__people strong, .t-light-2 .c-service__people strong { color: var(--text-on-light); }

/* A person's name is a route into their profile (and their email) from every
   service they run — not just from the People grid. */
.c-person-link {
  font-size: var(--fs-small);
  color: var(--accent-on-dark);   /* dialogs are dark; burnt was 3.18:1 there */
  padding-bottom: 2px;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size var(--d-base) var(--e-out), color var(--d-fast) var(--e-out);
}
.c-person-link:hover,
.c-person-link:focus-visible {
  background-size: 100% 1px;
  color: var(--c-orange-lift);
}
.t-light .c-person-link, .t-light-2 .c-person-link { color: var(--accent-on-light); }
.t-light .c-person-link:hover, .t-light-2 .c-person-link:hover { color: var(--c-burnt-deep); }

/* ==========================================================================
   Editorial split (Approach)
   ========================================================================== */
.c-split {
  display: grid;
  gap: 0;
  align-items: stretch;
}
/* 50/50, not 0.92/1.08. The text column's left padding grows with the viewport
   (it has to, to stay aligned with every other section's heading), so a column
   narrower than half leaves the copy squeezed into ~450px at 2560 while the
   image sprawls across 1382px. Half keeps a workable measure at every width. */
@media (min-width: 64rem) {
  .c-split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

.c-split__text {
  padding: var(--sp-section-y) var(--gutter);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
@media (min-width: 64rem) {
  .c-split__text {
    padding-block: var(--sp-section);
    padding-left: max(var(--gutter), calc((100vw - var(--max-w)) / 2 + var(--gutter)));
    padding-right: clamp(2rem, 5vw, 5rem);
  }
}

.c-split__media {
  position: relative;
  overflow: hidden;
  min-height: 58vw;
}
@media (min-width: 64rem) { .c-split__media { min-height: 100%; } }
.c-split__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
@media (prefers-reduced-motion: reduce) {
  .c-split__media img { transform: none !important; }
}

/* Warm edge so the image marries into the dark panel. */
.c-split__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--c-black) 0%, rgb(var(--rgb-black) / 0.35) 22%, rgb(var(--rgb-black) / 0) 55%);
  pointer-events: none;
  display: none;
}
@media (min-width: 64rem) { .c-split__media::after { display: block; } }

.c-approach__points {
  display: grid;
  gap: var(--sp-5);
  margin-top: var(--sp-7);
  counter-reset: approach;
}
/* On the band these run 2x2 rather than 4x1 — four full-width rows would make
   the band taller than the viewport, and a band that outgrows the viewport
   can't be pinned (its bottom becomes unreachable). See .c-stack-rows. */
.c-approach__points--split { margin-top: 0; }
@media (min-width: 64rem) {
  .c-approach__points--split {
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-6) var(--sp-7);
  }
}
.c-approach__point {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-4);
  align-items: baseline;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--rule-on-dark);
}
.c-approach__point::before {
  counter-increment: approach;
  content: counter(approach, decimal-leading-zero);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  color: var(--c-orange);
  font-variant-numeric: tabular-nums;
}
.c-approach__point h3 {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  color: var(--text-on-dark);
  margin-bottom: var(--sp-1);
}
.c-approach__point p {
  font-size: var(--fs-small);
  color: var(--text-on-dark-muted);
  line-height: 1.55;
}

/* ==========================================================================
   Experience — filterable editorial matter list
   ========================================================================== */
.c-exp__bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-bottom: var(--sp-7);
}

.c-filter {
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--text-on-dark-muted);
  border: 1px solid var(--rule-on-dark);
  border-radius: var(--r-pill);
  padding: var(--sp-2) var(--sp-5);
  transition:
    color var(--d-fast) var(--e-out),
    border-color var(--d-fast) var(--e-out),
    background-color var(--d-fast) var(--e-out);
}
.c-filter:hover { color: var(--text-on-dark); border-color: var(--c-concrete); }
/* Active = filled + border + aria-pressed, not colour alone. */
.c-filter[aria-pressed="true"] {
  background: var(--c-orange);
  border-color: var(--c-orange);
  color: var(--c-black);
  font-weight: var(--fw-semibold);
}

/* Two columns from lg: 57 matters in one column is a scroll marathon. */
.c-exp__list {
  display: grid;
  gap: 0 var(--sp-8);
  align-content: start;
}
@media (min-width: 64rem) {
  .c-exp__list { grid-template-columns: 1fr 1fr; }
}

.c-matter {
  padding-block: var(--sp-4);
  border-top: 1px solid var(--rule-on-dark);
}
.c-matter[hidden] { display: none; }

.c-matter__meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-2);
}
.c-matter__cat {
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-orange);
}
.c-matter__desc {
  font-family: var(--font-serif);
  font-size: 1.0625rem;
  line-height: 1.45;
  color: var(--text-on-dark);
  text-wrap: pretty;
}
.c-matter__value {
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--text-on-dark);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  flex-shrink: 0;
}

/* ---- Experience on a light ground ----
   The section moved from near-black to warm white (the approved concept put
   "Recent Matters" on a light ground, and four dark sections in a row had no
   separation). These components were authored for dark, so they need the light
   half of every colour pair. Brand orange is 2.15:1 on warm white — the burnt
   variant carries the accent here instead. */
.t-light .c-matter,
.t-light-2 .c-matter { border-top-color: var(--rule-on-light); }

.t-light .c-matter__cat,
.t-light-2 .c-matter__cat { color: var(--accent-on-light); }

.t-light .c-matter__desc,
.t-light-2 .c-matter__desc { color: var(--text-on-light); }

.t-light .c-matter__value,
.t-light-2 .c-matter__value { color: var(--text-on-light); }

.t-light .c-exp__note,
.t-light-2 .c-exp__note { color: var(--text-on-light-muted); }

.t-light .c-filter,
.t-light-2 .c-filter {
  color: var(--text-on-light-muted);
  border-color: var(--rule-on-light);
}
.t-light .c-filter:hover,
.t-light-2 .c-filter:hover { color: var(--text-on-light); border-color: var(--c-concrete); }
/* Active pill keeps the brand orange as a FILL with near-black type (8.9:1) —
   the one place full-strength orange is correct on a light ground. */
.t-light .c-filter[aria-pressed="true"],
.t-light-2 .c-filter[aria-pressed="true"] {
  background: var(--c-orange);
  border-color: var(--c-orange);
  color: var(--c-black);
}

.t-light .c-exp__more,
.t-light-2 .c-exp__more {
  color: var(--accent-on-light);
  border-color: var(--rule-on-light);
}
.t-light .c-exp__more:hover,
.t-light-2 .c-exp__more:hover {
  color: var(--c-burnt-deep);
  border-color: var(--c-burnt-deep);
}

/* Show-more: the list starts capped so the section is skimmable. */
.c-exp__more {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-6);
  padding: var(--sp-3) var(--sp-5);
  border: 1px solid var(--rule-on-dark);
  border-radius: var(--r-pill);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-orange);
  transition: border-color var(--d-fast) var(--e-out), color var(--d-fast) var(--e-out);
}
.c-exp__more:hover { border-color: var(--rule-accent); color: var(--c-orange-lift); }
.c-exp__more[hidden] { display: none; }

.c-exp__note {
  margin-top: var(--sp-6);
  font-size: var(--fs-small);
  color: var(--text-on-dark-muted);
  max-width: var(--measure);
}

/* ==========================================================================
   People
   ========================================================================== */
.c-people__grid {
  display: grid;
  gap: var(--sp-6) var(--sp-5);
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 48rem) { .c-people__grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 64rem) { .c-people__grid { grid-template-columns: repeat(4, 1fr); } }

.c-person { position: relative; }

.c-person__media {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--c-charcoal-3);
  border-radius: var(--r-md);
  margin-bottom: var(--sp-4);
}
/* Mono → full colour. The previous version cross-faded a flat orange wash over
   the greyscale, which just muddied the portrait to sepia and read as a weak
   tint rather than a deliberate state change. Now the photograph simply comes
   to life: colour returns, it brightens, and a warm light-leak rises from the
   bottom edge under an orange rule. */
.c-person__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.08) brightness(0.88);
  transform: scale(1.03);
  transition:
    transform var(--d-slower) var(--e-editorial),
    filter var(--d-slow) var(--e-out);
}
.c-person:hover .c-person__media img,
.c-person:focus-within .c-person__media img {
  transform: scale(1.08);
  filter: grayscale(0) contrast(1.02) brightness(1.04) saturate(1.05);
}

/* Warm light-leak, confined to the lower third so the face stays true. */
.c-person__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
    rgb(var(--rgb-orange) / 0.55) 0%,
    rgb(var(--rgb-orange) / 0.16) 22%,
    rgb(var(--rgb-orange) / 0) 42%);
  opacity: 0;
  transition: opacity var(--d-slow) var(--e-out);
  pointer-events: none;
  mix-blend-mode: soft-light;
}
.c-person:hover .c-person__media::after,
.c-person:focus-within .c-person__media::after { opacity: 1; }

/* Orange rule that draws itself along the bottom edge — the decisive cue. */
.c-person__media::before {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  height: 3px;
  background: var(--c-orange);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--d-slow) var(--e-editorial);
}
.c-person:hover .c-person__media::before,
.c-person:focus-within .c-person__media::before { transform: scaleX(1); }

.c-person__name {
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  line-height: 1.2;
  letter-spacing: var(--ls-heading);
  margin-bottom: var(--sp-1);
}
/* Whole-card link target */
.c-person__link::after { content: ""; position: absolute; inset: 0; border-radius: var(--r-md); }
.c-person__link { color: inherit; }

.c-person__role {
  font-size: var(--fs-small);
  color: var(--text-on-dark-muted);
  margin-bottom: var(--sp-3);
}

.c-person__focus {
  font-size: var(--fs-small);
  color: var(--c-orange);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  opacity: 0;
  transform: translate3d(0, 6px, 0);
  transition:
    opacity var(--d-base) var(--e-out),
    transform var(--d-base) var(--e-out);
}
.c-person:hover .c-person__focus,
.c-person:focus-within .c-person__focus { opacity: 1; transform: none; }
/* Touch/no-hover: always show, never hide info behind hover. */
@media (hover: none) {
  .c-person__focus { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .c-person__focus { opacity: 1; transform: none; }
  .c-person__media img { transform: none; }
  .c-person:hover .c-person__media img { transform: none; }
}

/* ==========================================================================
   Person dialog
   ========================================================================== */
.c-dialog {
  border: 0;
  padding: 0;
  max-width: min(64rem, 100vw - 2rem);
  width: 100%;
  max-height: min(88vh, 60rem);
  background: var(--c-charcoal-2);
  color: var(--text-on-dark);
  border-radius: var(--r-md);
  overflow: hidden;
  box-shadow: var(--shadow-lift);
}
/* Flex, not block: a max-height alone never gives the grid a definite height,
   so its 1fr row sized to content and the bio overflowed a clipped box with
   nothing to scroll. A flex container DOES push its max-height down into the
   item (shrink), which finally gives the grid a real height to divide up.
   Scoped to [open] so the UA's `dialog:not([open]) { display: none }` still
   wins — otherwise every dialog would render on the page. */
.c-dialog[open] {
  display: flex;
  flex-direction: column;
}
/* The dialog is focused on open; a ring around the whole modal reads as a
   glitch. Focus is still obvious — it moves inside, and every control keeps
   its own ring. */
.c-dialog:focus { outline: none; }
.c-dialog::backdrop {
  background: rgb(var(--rgb-black) / 0.82);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.c-dialog[open] { animation: dialog-in var(--d-base) var(--e-out); }
@keyframes dialog-in {
  from { opacity: 0; transform: translate3d(0, 14px, 0); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .c-dialog[open] { animation: none; }
}

.c-dialog__grid {
  display: grid;
  /* Shrink to the dialog's max-height (flex), then hand that definite height to
     the row. minmax(0, 1fr) — NOT the default auto row, which sizes to its
     tallest item and would let the body grow past the dialog again. */
  flex: 1 1 auto;
  min-height: 0;
  grid-template-rows: minmax(0, 1fr);
}
@media (min-width: 48rem) {
  .c-dialog__grid { grid-template-columns: 15rem 1fr; }
}

.c-dialog__media {
  display: none;
  background: var(--c-charcoal-3);
}
@media (min-width: 48rem) { .c-dialog__media { display: block; } }
.c-dialog__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Narrow, full-height column: anchor above centre so the crop keeps the
     face rather than sliding down to the chest. */
  object-position: center 22%;
}

/* ---------- The portrait on a phone ----------
   It was display:none below 48rem, so every profile was faceless on the device
   most people read it on — and "the people you'll actually work with" is the
   entire point of that band. Below the tablet breakpoint the side column can't
   work, so the portrait becomes a banner in a row of its own.

   Both rules are gated on :has(.c-dialog__media) deliberately. The row template
   must NOT be applied globally: the matters dialog uses this same grid with no
   media, and in an `auto` first row its body sizes to content and stops
   scrolling — that is the exact bug the minmax(0,1fr) row exists to prevent.
   Gating also degrades safely: without :has() support neither rule applies, the
   portrait stays hidden, and nothing overlaps. */
@media (max-width: 47.999rem) {
  .c-dialog__grid:has(.c-dialog__media) { grid-template-rows: auto minmax(0, 1fr); }
  .c-dialog__grid:has(.c-dialog__media) .c-dialog__media {
    display: block;
    height: clamp(9rem, 24vh, 14rem);
  }
  /* A wide crop cuts lower on the frame than a tall one, so lift the anchor. */
  .c-dialog__grid:has(.c-dialog__media) .c-dialog__media img { object-position: center 18%; }
}

.c-dialog__body {
  padding: clamp(1.5rem, 3vw, 2.75rem);
  overflow-y: auto;
  /* Grid/flex items default to min-height:auto, which refuses to shrink below
     content height — so overflow-y had nothing to scroll and the bio was
     silently clipped on short viewports. This is the line that makes it work. */
  min-height: 0;
  overscroll-behavior: contain;   /* don't chain the scroll to the page behind */
}

.c-dialog__close {
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-4);
  z-index: 2;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgb(var(--rgb-black) / 0.6);
  color: var(--text-on-dark);
  transition: background-color var(--d-fast) var(--e-out), color var(--d-fast) var(--e-out);
}
.c-dialog__close:hover { background: var(--c-orange); color: var(--c-black); }

.c-dialog__role {
  color: var(--c-orange);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  margin-bottom: var(--sp-3);
}
/* Name left, address right. The email is the point of a profile — it belongs
   beside the name, not stranded at the foot of a long bio. */
.c-dialog__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-4) var(--sp-6);
  flex-wrap: wrap;
  margin-bottom: var(--sp-5);
  /* The close button is absolutely positioned in this corner and overhangs the
     body's padding. Keep the email out of its column. */
  padding-right: var(--sp-5);
}
/* Two classes, deliberately: .c-arrow sets `align-self: flex-start` and is
   declared later in this file, so a single-class selector loses to it and the
   email rides up into the close button. Measured: 13px of overlap. */
.c-dialog__head .c-dialog__email {
  align-self: flex-end;
  flex: none;
  white-space: nowrap;
  border-bottom: 1px solid rgb(var(--rgb-orange) / 0.4);
}
.c-dialog__name { margin-bottom: 0; }
.c-dialog__bio > p + p { margin-top: var(--sp-4); }
.c-dialog__bio p { color: var(--text-on-dark-muted); }

.c-dialog__cols {
  display: grid;
  gap: var(--sp-6);
  margin-top: var(--sp-6);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--rule-on-dark);
}
@media (min-width: 40rem) { .c-dialog__cols { grid-template-columns: 1fr 1fr; } }

.c-dialog__cols h4 {
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-on-dark);
  margin-bottom: var(--sp-4);
}
.c-dialog__cols li {
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-on-dark-muted);
  padding-left: var(--sp-4);
  position: relative;
}
.c-dialog__cols li + li { margin-top: var(--sp-3); }
.c-dialog__cols li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.62em;
  width: 5px; height: 1px;
  background: var(--c-orange);
}

/* ==========================================================================
   Recognition — heading left, real Doyle's Guide badges right-aligned
   ========================================================================== */
.c-recognition__head {
  display: grid;
  gap: var(--sp-6);
  align-items: end;
  margin-bottom: var(--sp-8);
}
@media (min-width: 64rem) {
  .c-recognition__head {
    grid-template-columns: auto 1fr;
    gap: var(--sp-8);
  }
}
.c-recognition__head .u-label { color: var(--accent-on-light); margin-bottom: var(--sp-4); }

.c-badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
}
@media (min-width: 64rem) {
  /* Right-aligned against the heading, per the title-row treatment. */
  .c-badges { justify-content: flex-end; }
}

/* The badges are third-party marks (gold laurel, pink wordmark) and are not
   ours to restyle. Holding them small, desaturated and low-contrast until
   hover keeps them credible rather than shouty, and stops them competing with
   the brand orange. They carry dark text, so they only ever sit on light. */
/* No opacity or saturate hacks. Those existed only to mute a pink wordmark and
   a gold laurel that fought the palette — the artwork is now recoloured into
   brand tokens at source (img/accolades/tinted/), so it can stand at full
   strength. Leaving the old filter on would desaturate the tint we just built. */
.c-badge img {
  height: clamp(3.5rem, 2.8rem + 2.2vw, 5rem);
  width: auto;
  transition: transform var(--d-base) var(--e-out);
}
.c-badge img:hover { transform: translateY(-3px); }
@media (prefers-reduced-motion: reduce) {
  .c-badge img:hover { transform: none; }
}

/* ==========================================================================
   Accolades strip
   ========================================================================== */
.c-accolades {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: 1fr;
}
@media (min-width: 48rem) { .c-accolades { grid-template-columns: repeat(3, 1fr); gap: var(--sp-6); } }

.c-accolade {
  padding-top: var(--sp-5);
  border-top: 1px solid var(--rule-on-light);
}
.c-accolade__rank {
  font-family: var(--font-serif);
  font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.125rem);
  line-height: 1.15;
  letter-spacing: var(--ls-heading);
  color: var(--text-on-light);
  margin-bottom: var(--sp-3);
}
.c-accolade__for {
  font-size: var(--fs-small);
  color: var(--text-on-light-muted);
  line-height: 1.5;
}

/* ==========================================================================
   Industries
   ========================================================================== */
.c-industries__grid {
  display: grid;
  gap: var(--sp-8);
  align-items: start;
}
@media (min-width: 64rem) {
  .c-industries__grid { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr); gap: var(--sp-9); }
}
.c-industries__intro .u-label { color: var(--accent-on-dark); margin-bottom: var(--sp-4); }
.c-industries__intro .u-h2 { margin-bottom: var(--sp-5); }

/* A numbered editorial list, not a tag cloud — these are real sectors and
   deserve the same weight as the practices. */
.c-industries {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--rule-on-dark);
}
@media (min-width: 40rem) {
  .c-industries { grid-template-columns: 1fr 1fr; column-gap: var(--sp-7); }
}
.c-industry {
  display: flex;
  align-items: baseline;
  gap: var(--sp-4);
  padding-block: var(--sp-4);
  border-bottom: 1px solid var(--rule-on-dark);
  font-family: var(--font-serif);
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.3125rem);
  line-height: 1.25;
  letter-spacing: var(--ls-heading);
  color: var(--text-on-dark);
  transition: color var(--d-fast) var(--e-out);
}
.c-industry__n {
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  color: var(--c-orange);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}


/* The charcoal band sits closer to its rules than black does, so lift them a
   little to keep the same apparent weight as the other dark sections. */
.t-dark-2 .c-industry,
.t-dark-2 .c-industries { border-color: rgb(var(--rgb-ivory) / 0.22); }

/* ==========================================================================
   CTA band
   ========================================================================== */
.c-cta {
  position: relative;
  overflow: hidden;
  background: var(--bg-cta);
  background-image: linear-gradient(112deg,
    var(--c-orange) 0%, var(--c-orange) 42%,
    var(--c-orange-deep) 78%, var(--c-orange-deeper) 100%);
}

/* Architectural linework — decorative, aria-hidden. */
.c-cta__lines {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.5;
  color: var(--c-black);
}
.c-cta__inner { position: relative; z-index: var(--z-raised); }

.c-cta__grid {
  display: grid;
  gap: var(--sp-6);
  align-items: end;
}
@media (min-width: 64rem) {
  .c-cta__grid { grid-template-columns: 1.4fr 1fr auto; gap: var(--sp-8); }
}
.c-cta__title { color: var(--text-on-cta); }
.c-cta__text { color: var(--text-on-cta-muted); max-width: 34ch; }

/* ==========================================================================
   Footer
   ========================================================================== */
.c-footer { background: var(--c-black); }

.c-footer__top {
  display: grid;
  gap: var(--sp-8);
  padding-block: var(--sp-section-y);
}
@media (min-width: 64rem) {
  .c-footer__top { grid-template-columns: 1.5fr repeat(3, minmax(0, 1fr)); gap: var(--sp-7); }
}

.c-footer__logo img { width: 13rem; margin-bottom: var(--sp-5); }
.c-footer__tag {
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  letter-spacing: var(--ls-heading);
  color: var(--text-on-dark);
  margin-bottom: var(--sp-5);
}

.c-footer address {
  font-style: normal;
  font-size: var(--fs-small);
  color: var(--text-on-dark-muted);
  line-height: 1.7;
}

.c-footer__ch {
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-on-dark);
  margin-bottom: var(--sp-4);
}
.c-footer__list li + li { margin-top: var(--sp-3); }
.c-footer__list a {
  font-size: var(--fs-small);
  color: var(--text-on-dark-muted);
  transition: color var(--d-fast) var(--e-out);
}
.c-footer__list a:hover, .c-footer__list a:focus-visible { color: var(--c-orange); }

.c-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4) var(--sp-6);
  align-items: center;
  justify-content: space-between;
  padding-block: var(--sp-5);
  border-top: 1px solid var(--rule-on-dark);
  font-size: var(--fs-small);
  color: var(--text-on-dark-muted);
}
.c-footer__legal { display: flex; flex-wrap: wrap; gap: var(--sp-5); }
.c-footer__legal a { transition: color var(--d-fast) var(--e-out); }
.c-footer__legal a:hover { color: var(--c-orange); }

/* Scroll progress — a hairline, not a gimmick. */
.c-progress {
  position: fixed;
  top: 0; left: 0;
  z-index: calc(var(--z-header) + 1);
  height: 2px;
  width: 100%;
  background: var(--c-orange);
  transform: scaleX(var(--progress, 0));
  transform-origin: left center;
  pointer-events: none;
}


/* ==========================================================================
   BAND LAYER
   The reference's grammar: a narrow text panel on the left, media running to
   the right edge. Repeated down the page so the eye always knows where to
   look, with the media doing the talking. Every band is one screen-ish tall —
   dense and cinematic rather than a long scroll.
   ========================================================================== */

.c-band {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
}
@media (min-width: 64rem) {
  .c-band {
    /* 26% panel / 74% media — the reference's proportion. */
    grid-template-columns: minmax(16rem, 26%) minmax(0, 1fr);
    min-height: var(--h-band);
  }
}

.c-band__panel {
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--sp-5);
  /* --sp-8 is a flat 4rem. On a phone the panel stacks ABOVE the media, so that
     4rem of padding-bottom becomes a 64px void between the last line of copy and
     the images — which is what strands "View all 57 matters" from the cards it
     belongs to. Scale it with the viewport: 32px on a 430px phone, the full 64px
     from ~1280px up (where the desktop rule takes over anyway). */
  padding: clamp(2rem, 5vw, var(--sp-8)) var(--gutter);
}
@media (min-width: 64rem) {
  .c-band__panel { padding: var(--sp-8) var(--sp-7) var(--sp-8) var(--gutter); }
}

.c-band__title {
  font-family: var(--font-serif);
  font-weight: var(--fw-regular);
  font-size: var(--fs-band);
  line-height: 1.06;
  letter-spacing: var(--ls-heading);
  text-wrap: balance;
}
.c-band__text {
  font-size: var(--fs-small);
  line-height: 1.6;
  max-width: 34ch;
}
.t-dark .c-band__text, .t-dark-2 .c-band__text { color: var(--text-on-dark-muted); }
.t-light .c-band__text, .t-light-2 .c-band__text { color: var(--text-on-light-muted); }

.c-band__media {
  position: relative;
  min-height: var(--h-band-media);
  /* Grid items default to min-width:auto and refuse to shrink below content.
     The rail/tiles/strip inside are horizontal scrollers — without this they
     size to ALL their children and stretch the whole band past the viewport
     instead of scrolling. Same trap as min-height on the dialog. */
  min-width: 0;
}

/* ---------- Section label with the reference's leading rule ---------- */
.c-eyebrow {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--accent-on-dark);
}
.t-light .c-eyebrow, .t-light-2 .c-eyebrow { color: var(--accent-on-light); }
.c-eyebrow::before {
  content: "";
  width: 2px;
  height: 1em;
  background: var(--c-orange);
  flex-shrink: 0;
}

/* ---------- Arrow link (orange, uppercase, moves on hover) ---------- */
.c-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  /* WCAG 2.2 2.5.8 wants 24x24 minimum. The label is 12px, so without this the
     whole control is a 19px-tall sliver. */
  min-height: 24px;
  padding-block: var(--sp-2);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--accent-on-dark);
  align-self: flex-start;
  transition: color var(--d-fast) var(--e-out);
}
.t-light .c-arrow, .t-light-2 .c-arrow { color: var(--accent-on-light); }
.c-arrow__line {
  position: relative;
  width: 1.5rem; height: 1px;
  background: currentColor;
  transition: width var(--d-base) var(--e-out);
}
.c-arrow__line::after {
  content: "";
  position: absolute;
  right: 0; top: 50%;
  width: 6px; height: 6px;
  border-top: 1px solid currentColor;
  border-right: 1px solid currentColor;
  transform: translateY(-50%) rotate(45deg);
}
.c-arrow:hover .c-arrow__line, .c-arrow:focus-visible .c-arrow__line { width: 2.5rem; }
.c-arrow:hover { color: var(--c-orange-lift); }
.t-light .c-arrow:hover, .t-light-2 .c-arrow:hover { color: var(--c-burnt-deep); }

/* ---------- Outlined button (hero + CTA) ---------- */
.c-btn--outline {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid rgb(var(--rgb-ivory) / 0.4);
  border-radius: var(--r-none);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-on-dark);
  background: transparent;
  transition: border-color var(--d-base) var(--e-out), background-color var(--d-base) var(--e-out), color var(--d-base) var(--e-out);
}
.c-btn--outline:hover, .c-btn--outline:focus-visible {
  border-color: var(--c-orange);
  background: var(--c-orange);
  color: var(--c-black);
}

/* ==========================================================================
   Services filmstrip — five tiles, five atmospheres, one glance
   ========================================================================== */
.c-tiles {
  min-width: 0;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 78%;
  gap: 1px;
  height: 100%;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  background: var(--rule-on-dark);
}
.c-tiles::-webkit-scrollbar { display: none; }
@media (min-width: 48rem) { .c-tiles { grid-auto-columns: 42%; } }
@media (min-width: 64rem) {
  /* All five visible at once — the whole point. */
  .c-tiles { grid-auto-columns: 1fr; overflow-x: visible; }
}

.c-tile {
  position: relative;
  display: block;
  overflow: hidden;
  scroll-snap-align: start;
  min-height: var(--h-band-media);
  background: var(--c-charcoal-2);
  isolation: isolate;
}
.c-tile img {
  transform: scale(1.04);
  transition: transform var(--d-slower) var(--e-editorial), filter var(--d-slow) var(--e-out);
  filter: saturate(0.9) brightness(0.82);
}
.c-tile:hover img, .c-tile:focus-visible img {
  transform: scale(1.12);
  filter: saturate(1.05) brightness(1);
}
/* Scrim: the label sits bottom-left over the photograph and must stay legible
   whatever the crop underneath is doing. */
.c-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
    rgb(var(--rgb-black) / 0.92) 0%,
    rgb(var(--rgb-black) / 0.65) 32%,
    rgb(var(--rgb-black) / 0.15) 62%,
    rgb(var(--rgb-black) / 0.35) 100%);
  transition: opacity var(--d-slow) var(--e-out);
}
.c-tile:hover::after { opacity: 0.82; }

.c-tile__body {
  position: relative;
  z-index: 2;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: var(--sp-3);
  padding: var(--sp-5);
}

/* ---------- Tiles on a phone ----------
   Declared here, AFTER .c-tile / .c-tile__name, on purpose. A media query adds
   no specificity, so an override placed above the base rule loses on source
   order and silently does nothing.

   The height was never the tile's own doing: .c-band__media carries
   min-height:--h-band-media (46vh), .c-tiles is height:100%, and the tile
   stretches to fill. On a 932px phone that chain produced a 429px image under an
   18px label — 24:1 picture-to-type. Release the container the way --list and
   --rail already do, then let the tile size itself and lift the label. */
@media (max-width: 63.999rem) {
  .c-band__media--tiles { min-height: 0; }
  .c-tile { min-height: clamp(14rem, 30vh, 19rem); }
}
.c-tile__n {
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  color: var(--c-orange);
  font-variant-numeric: tabular-nums;
}
.c-tile__name {
  font-family: var(--font-serif);
  font-weight: var(--fw-regular);
  font-size: clamp(1.125rem, 0.95rem + 0.6vw, 1.5rem);
  line-height: 1.12;
  letter-spacing: var(--ls-heading);
  color: var(--text-on-dark);
  text-wrap: balance;
}
/* Phone: the label has to hold its own against a full-width photograph, and the
   desktop clamp bottoms out at 1.125rem — an 18px name under a 280px image.
   Must sit AFTER the base .c-tile__name above: a media query adds no
   specificity, so higher up the file it would lose on source order. */
@media (max-width: 63.999rem) {
  .c-tile__name { font-size: clamp(1.3rem, 1.05rem + 1.6vw, 1.6rem); }
}

.c-tile__go {
  width: 1.25rem; height: 1px;
  background: var(--c-orange);
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform var(--d-base) var(--e-out);
}
.c-tile:hover .c-tile__go, .c-tile:focus-visible .c-tile__go { transform: scaleX(1); }

/* ==========================================================================
   Experience carousel — native scroll-snap, no library, keyboard works
   ========================================================================== */
.c-rail {
  min-width: 0;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 80%;
  gap: var(--sp-5);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scroll-padding: var(--sp-6);
  padding: var(--sp-7) var(--gutter) var(--sp-5) 0;
  scrollbar-width: none;
}
.c-rail::-webkit-scrollbar { display: none; }
@media (min-width: 48rem) { .c-rail { grid-auto-columns: 44%; } }
@media (min-width: 64rem) { .c-rail { grid-auto-columns: 31%; padding-left: 0; } }

.c-card {
  scroll-snap-align: start;
  background: var(--bg-light-2);
  border: 1px solid var(--rule-on-light);
  display: flex;
  flex-direction: column;
  transition: transform var(--d-base) var(--e-out), border-color var(--d-base) var(--e-out);
}
.c-card:hover { transform: translateY(-4px); border-color: var(--rule-accent); }
.c-card__media { position: relative; aspect-ratio: 3 / 2; overflow: hidden; background: var(--c-charcoal-2); }
/* .c-card__media img sizing now comes from .c-card__par img */
.c-card__body { padding: var(--sp-5); }
.c-card__value {
  display: block;
  font-family: var(--font-serif);
  font-weight: var(--fw-regular);
  font-size: clamp(1.75rem, 1.3rem + 1.4vw, 2.5rem);
  line-height: 1;
  color: var(--accent-on-light);
  font-variant-numeric: tabular-nums;
  margin-bottom: var(--sp-3);
}
.c-card__name {
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  color: var(--text-on-light);
  line-height: 1.3;
  margin-bottom: var(--sp-2);
}
.c-card__meta { font-size: var(--fs-small); color: var(--text-on-light-muted); }

/* Rail controls */
.c-rail__ctl {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  padding: 0 var(--gutter) var(--sp-6) 0;
}
@media (max-width: 63.999rem) { .c-rail__ctl { padding-left: var(--gutter); } }
.c-dots { display: flex; gap: var(--sp-2); }
.c-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--rule-on-light);
  transition: background-color var(--d-fast) var(--e-out), width var(--d-base) var(--e-out);
}
.c-dot[aria-current="true"] { background: var(--c-orange); width: 20px; border-radius: 3px; }
.t-dark .c-dot, .t-dark-2 .c-dot { background: var(--rule-on-dark); }

.c-rail__arrows { display: flex; gap: var(--sp-2); }
.c-rail__arrow {
  width: 44px; height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--rule-on-light);
  color: var(--text-on-light);
  transition: border-color var(--d-fast) var(--e-out), color var(--d-fast) var(--e-out), background-color var(--d-fast) var(--e-out);
}
.c-rail__arrow:hover:not(:disabled) { border-color: var(--c-orange); background: var(--c-orange); color: var(--c-black); }
.c-rail__arrow:disabled { opacity: 0.32; cursor: default; }

/* ==========================================================================
   People strip
   ========================================================================== */
.c-strip {
  min-width: 0;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 60%;
  gap: 1px;
  height: 100%;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  background: var(--rule-on-dark);
}
.c-strip::-webkit-scrollbar { display: none; }
@media (min-width: 48rem) { .c-strip { grid-auto-columns: 32%; } }
@media (min-width: 64rem) { .c-strip { grid-auto-columns: 22%; } }

.c-face {
  position: relative;
  scroll-snap-align: start;
  min-height: var(--h-band-media);
  overflow: hidden;
  background: var(--c-charcoal-2);
  display: block;
  text-align: left;
  width: 100%;
}
.c-face img {
  object-position: center 18%;
  filter: grayscale(1) brightness(0.72) contrast(1.1);
  transform: scale(1.03);
  transition: filter var(--d-slow) var(--e-out), transform var(--d-slower) var(--e-editorial);
}
.c-face:hover img, .c-face:focus-visible img {
  filter: grayscale(0) brightness(1) contrast(1.02);
  transform: scale(1.08);
}
.c-face::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgb(var(--rgb-black) / 0.9) 0%, rgb(var(--rgb-black) / 0.25) 45%, rgb(var(--rgb-black) / 0.1) 100%);
}
.c-face__body {
  position: relative;
  z-index: 2;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: var(--sp-5);
}
.c-face__name {
  font-family: var(--font-serif);
  font-weight: var(--fw-regular);
  font-size: clamp(1.0625rem, 0.95rem + 0.4vw, 1.25rem);
  line-height: 1.15;
  color: var(--text-on-dark);
}
.c-face__role {
  font-size: var(--fs-label);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--c-orange);
  margin-top: var(--sp-2);
}

/* ==========================================================================
   CTA band — photograph behind, statement left, action right
   ========================================================================== */
.c-cta2 {
  position: relative;
  overflow: hidden;
  min-height: var(--h-band);
  display: flex;
  align-items: center;
  background: var(--c-black);
}
.c-cta2 .c-cine { position: absolute; inset: 0; }
/* Unlike a pause (statement on one side), this band carries copy on BOTH sides —
   title left, paragraph and button right. A left-weighted scrim leaves the
   right-hand copy sitting on lit sky at ~2:1. Hold the whole width down. */
.c-cta2 .c-cine::after {
  background:
    linear-gradient(100deg,
      rgb(var(--rgb-black) / 0.90) 0%,
      rgb(var(--rgb-black) / 0.72) 42%,
      rgb(var(--rgb-black) / 0.68) 72%,
      rgb(var(--rgb-black) / 0.78) 100%),
    radial-gradient(90% 80% at 60% 95%, rgb(var(--rgb-orange) / 0.28) 0%, rgb(var(--rgb-orange) / 0) 60%);
}
.c-cta2__inner {
  position: relative;
  z-index: var(--z-raised);
  width: 100%;
  display: grid;
  gap: var(--sp-7);
  align-items: center;
  padding-block: var(--sp-8);
}
@media (min-width: 64rem) {
  .c-cta2__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 26rem); gap: var(--sp-9); }
}
.c-cta2__title {
  font-family: var(--font-serif);
  font-weight: var(--fw-regular);
  font-size: var(--fs-statement);
  line-height: 0.98;
  letter-spacing: var(--ls-display);
  color: var(--text-on-dark);
  max-width: 12ch;
}
/* Ivory, not muted stone: over a photograph the muted tone needs a scrim so
   heavy it kills the image. Ivory stays legible at a scrim that still lets the
   architecture read. */
.c-cta2__text { color: var(--text-on-dark); font-size: var(--fs-small); line-height: 1.6; margin-bottom: var(--sp-6); }

/* ==========================================================================
   Band variants + odds and ends
   ========================================================================== */

/* Hero: shorter than a full screen (the reference band rhythm), text bottom-left. */
.c-hero { min-height: var(--h-hero); }
.c-hero__kicker {
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  line-height: 1.9;
  color: var(--c-orange);
  margin-bottom: var(--sp-7);
}

/* Bands whose media is a list rather than imagery need the panel's air. */
.c-band__media--pad {
  display: flex;
  align-items: center;
  padding: var(--sp-8) var(--gutter);
}
@media (min-width: 64rem) {
  .c-band__media--pad { padding: var(--sp-8) var(--gutter) var(--sp-8) 0; }
}
.c-band--list .c-band__media, .c-band--rail .c-band__media { min-height: 0; }

/* The rail column stacks its scroller above its controls. */
.c-band--rail .c-band__media { display: flex; flex-direction: column; justify-content: center; }

/* Industries inside a band: two tight columns, no outer section grid. */
.c-band .c-industries { border-top: 1px solid var(--rule-on-dark); width: 100%; }

/* Badges inside a band. */
.c-band .c-badges { justify-content: flex-start; }

/* ==========================================================================
   Wide dialog — service + approach + matters detail
   ========================================================================== */
.c-dialog--wide { max-width: min(72rem, 100vw - 2rem); }
@media (min-width: 48rem) {
  .c-dialog__grid--wide { grid-template-columns: minmax(0, 34%) minmax(0, 66%); }
}
.c-dialog__hero { display: none; position: relative; background: var(--c-charcoal-3); overflow: hidden; }
@media (min-width: 48rem) { .c-dialog__hero { display: block; } }
.c-dialog__hero img { width: 100%; height: 100%; object-fit: cover; }

/* Matters dialog holds the full filterable list — single column. */
#dlg-matters .c-dialog__grid { grid-template-columns: minmax(0, 1fr); }
#dlg-matters .c-exp__list { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 48rem) { #dlg-matters .c-exp__list { grid-template-columns: 1fr 1fr; } }
/* The dialog is dark, so the matter list needs its dark colours back. */
#dlg-matters .c-matter { border-top-color: var(--rule-on-dark); }
#dlg-matters .c-matter__cat { color: var(--c-orange); }
#dlg-matters .c-matter__desc, #dlg-matters .c-matter__value { color: var(--text-on-dark); }
#dlg-matters .c-exp__note { color: var(--text-on-dark-muted); }
#dlg-matters .c-filter { color: var(--text-on-dark-muted); border-color: var(--rule-on-dark); }
#dlg-matters .c-filter[aria-pressed="true"] { background: var(--c-orange); border-color: var(--c-orange); color: var(--c-black); }
#dlg-matters .c-exp__more { color: var(--c-orange); border-color: var(--rule-on-dark); }
#dlg-matters .c-exp__bar { margin-bottom: var(--sp-6); }

/* Capability groups inside a dialog. */
.c-dialog .c-caps { margin-top: var(--sp-6); }
.c-dialog .c-cap__label {
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-orange);
  padding-bottom: var(--sp-3);
  margin-bottom: var(--sp-3);
  border-bottom: 1px solid var(--rule-on-dark);
}
.c-dialog .c-cap__list li {
  font-size: var(--fs-small);
  line-height: 1.45;
  color: var(--text-on-dark-muted);
  padding-left: var(--sp-4);
  position: relative;
}
.c-dialog .c-cap__list li + li { margin-top: var(--sp-3); }
.c-dialog .c-cap__list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.62em;
  width: 5px; height: 1px;
  background: var(--c-orange);
}
.c-caps { display: grid; gap: var(--sp-6); }
@media (min-width: 40rem) { .c-caps { grid-template-columns: 1fr 1fr; } }

/* ==========================================================================
   Footer — single bar, matching the reference
   ========================================================================== */
.c-footer__bar {
  display: grid;
  gap: var(--sp-5);
  align-items: center;
  padding-block: var(--sp-7);
  border-top: 1px solid var(--rule-on-dark);
}
@media (min-width: 64rem) {
  .c-footer__bar {
    grid-template-columns: auto auto 1fr auto auto;
    gap: var(--sp-7);
  }
}
.c-footer__logo img { width: 11rem; height: auto; }
.c-footer address {
  font-style: normal;
  font-size: var(--fs-small);
  color: var(--text-on-dark-muted);
  line-height: 1.7;
}
.c-footer__legal { display: flex; flex-wrap: wrap; gap: var(--sp-5); font-size: var(--fs-small); color: var(--text-on-dark-muted); }
.c-footer__legal a { transition: color var(--d-fast) var(--e-out); }
.c-footer__legal a:hover { color: var(--c-orange); }
.c-footer__copy { font-size: var(--fs-small); color: var(--text-on-dark-muted); white-space: nowrap; }

/* Badges must be READ, not just recognised as "an award". The wordmark and the
   year are the whole point, and at 4rem they are illegible. Size them off the
   column they sit in: nine across a 74% media band, wrapping to two rows. */
.c-band .c-badges {
  gap: clamp(var(--sp-4), 1.6vw, var(--sp-5));
  align-items: center;
}
/* The artwork is now recoloured into the brand palette at source
   (img/accolades/tinted/), so no CSS desaturation is needed — that was only
   ever muting the pink wordmark. Show them at full strength. */
.c-band .c-badge img {
  height: clamp(5.5rem, 4rem + 5.5vw, 9.5rem);
  opacity: 1;
  transition: transform var(--d-base) var(--e-out);
}
.c-band .c-badge img:hover { transform: translateY(-3px); }
@media (prefers-reduced-motion: reduce) { .c-band .c-badge img:hover { transform: none; } }

/* Footer phone/email qualify for WCAG 2.5.8's inline exception, but they are
   the primary action on a phone — give them a real target anyway. */
.c-footer address .u-link {
  display: inline-block;
  padding-block: 4px;
}

/* ==========================================================================
   No JavaScript
   The detail (services, approach, all 57 matters) now lives in <dialog>, which
   the UA hides until showModal(). Without JS nothing could open it, so that
   content would be unreachable — a real regression against the earlier builds.
   Render every dialog inline instead: unstyled-ish, stacked at the end of the
   page, but complete and readable. JS only ever *adds* behaviour.
   ========================================================================== */
.no-js dialog.c-dialog {
  display: block;
  position: static;
  max-width: 100%;
  width: 100%;
  max-height: none;
  border-radius: 0;
  box-shadow: none;
  border-top: 1px solid var(--rule-on-dark);
}
.no-js .c-dialog__grid { max-height: none; grid-template-rows: auto; }
.no-js .c-dialog__body { overflow: visible; max-height: none; }
.no-js .c-dialog__close { display: none; }
.no-js .c-dialog__hero { max-height: 22rem; }
/* The cap + filter bar are JS affordances; without JS show every matter. */
.no-js .c-exp__bar, .no-js .c-exp__more { display: none; }
.no-js .c-matter[hidden] { display: block; }

/* ==========================================================================
   Key-contact hover thumbnail
   A name is an abstraction; a face is a person. Show who you're about to open.
   ========================================================================== */
.c-person-link { position: relative; }
.c-person-link__thumb {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  width: 84px;
  height: 84px;
  object-fit: cover;
  object-position: center 18%;
  border-radius: var(--r-md);
  border: 1px solid var(--rule-accent);
  box-shadow: var(--shadow-lift);
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, 6px) scale(0.94);
  transform-origin: bottom center;
  transition:
    opacity var(--d-fast) var(--e-out),
    transform var(--d-base) var(--e-out);
  z-index: 5;
}
.c-person-link:hover .c-person-link__thumb,
.c-person-link:focus-visible .c-person-link__thumb {
  opacity: 1;
  transform: translate(-50%, 0) scale(1);
}
@media (prefers-reduced-motion: reduce) {
  .c-person-link__thumb { transform: translate(-50%, 0); }
  .c-person-link:hover .c-person-link__thumb { transform: translate(-50%, 0); }
}
/* Touch has no hover: a peek-on-hover that sticks would just cover the text. */
@media (hover: none) {
  .c-person-link__thumb { display: none; }
}

/* ==========================================================================
   Dialog prev/next — page through services or people without closing
   ========================================================================== */
.c-dialog__nav {
  position: relative;
  z-index: 3;
  display: flex;
  gap: 1px;
  background: var(--rule-on-dark);
  border-top: 1px solid var(--rule-on-dark);
}
.c-dialog__step {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  background: var(--c-charcoal-2);
  color: var(--text-on-dark);
  text-align: left;
  transition: background-color var(--d-fast) var(--e-out), color var(--d-fast) var(--e-out);
}
.c-dialog__step--next { justify-content: flex-end; text-align: right; }
.c-dialog__step:hover { background: var(--c-charcoal-3); color: var(--c-orange); }
.c-dialog__step-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.c-dialog__step--next .c-dialog__step-txt { align-items: flex-end; }
.c-dialog__step-lbl {
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-orange);
}
.c-dialog__step-txt { font-size: var(--fs-small); }
.c-dialog__step-ico { flex-shrink: 0; display: grid; place-items: center; color: var(--c-orange); }

/* The nav is a sibling of the scrolling grid, so the dialog stacks:
   [grid (scrolls)] [nav (pinned)]. */
.c-dialog[open] { display: flex; flex-direction: column; }
.no-js .c-dialog__nav { display: none; }

/* ==========================================================================
   Rail: image cards + stacked info boxes
   We will not have a photograph for every project, and a generic building
   beside a named project reads as a claim that the firm built it. So only
   matters with a confirmed image get an image card; the rest are info boxes,
   two per column, carrying exactly the same information minus the picture.
   ========================================================================== */
.c-rail { align-items: stretch; }
.c-rail > * { scroll-snap-align: start; }

/* Two info boxes occupy one rail column, matching an image card's footprint. */
.c-stack {
  display: grid;
  grid-template-rows: 1fr 1fr;
  gap: var(--sp-5);
  min-width: 0;
}
/* An odd final box must not stretch to fill a two-row column. */
.c-stack:has(> :only-child) { grid-template-rows: auto; align-content: start; }

.c-card--info {
  justify-content: center;
  background: transparent;
  border-color: var(--rule-on-light);
  border-left: 2px solid var(--c-orange);
}
.c-card--info:hover { transform: none; background: var(--bg-light-2); border-color: var(--rule-on-light); border-left-color: var(--c-orange); }
.c-card--info .c-card__body { padding: var(--sp-4) var(--sp-5); }
.c-card--info .c-card__value { font-size: clamp(1.5rem, 1.2rem + 1vw, 2rem); margin-bottom: var(--sp-2); }
.c-card--info .c-card__name { font-size: var(--fs-small); }
.c-card--info .c-card__meta { font-size: 0.8125rem; }

/* The image card's photo should not eat the whole column height once it has to
   share the rail with two-up stacks. */
.c-card--img .c-card__media { flex: 0 0 auto; }
.c-card--img .c-card__body { flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center; }

/* ==========================================================================
   Legal pages — Privacy Policy, Professional Standards Scheme
   Long-form statutory text. The job here is readability and nothing else:
   one measure, generous leading, clear numbering. No photography, no motion.
   ========================================================================== */
.c-legal { padding-block: var(--sp-section-y) var(--sp-section); }
.c-legal__head {
  padding-top: calc(var(--header-h) + var(--sp-8));
  padding-bottom: var(--sp-8);
  border-bottom: 1px solid var(--rule-on-dark);
  margin-bottom: var(--sp-8);
}
.c-legal__title { margin-top: var(--sp-4); max-width: 20ch; }
.c-legal__meta {
  margin-top: var(--sp-5);
  font-size: var(--fs-small);
  color: var(--text-on-dark-muted);
}

.c-legal__body { max-width: 46rem; }
.c-legal__body h2 {
  font-family: var(--font-serif);
  font-weight: var(--fw-regular);
  font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.75rem);
  line-height: 1.2;
  letter-spacing: var(--ls-heading);
  color: var(--text-on-dark);
  margin-top: var(--sp-8);
  margin-bottom: var(--sp-4);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--rule-on-dark);
  scroll-margin-top: calc(var(--header-h) + var(--sp-4));
}
.c-legal__body h2:first-child { margin-top: 0; border-top: 0; padding-top: 0; }
.c-legal__body p {
  color: var(--text-on-dark-muted);
  line-height: 1.7;
  margin-bottom: var(--sp-4);
  text-wrap: pretty;
}
.c-legal__body ul, .c-legal__body ol { margin: 0 0 var(--sp-4) 0; padding-left: var(--sp-5); }
.c-legal__body li {
  color: var(--text-on-dark-muted);
  line-height: 1.7;
  margin-bottom: var(--sp-3);
  padding-left: var(--sp-3);
}
.c-legal__body ul > li { list-style: none; position: relative; }
.c-legal__body ul > li::before {
  content: "";
  position: absolute;
  left: calc(var(--sp-5) * -1);
  top: 0.75em;
  width: 6px; height: 1px;
  background: var(--c-orange);
}
.c-legal__body ol { list-style: lower-alpha; }
.c-legal__body ol > li::marker { color: var(--c-orange); }
.c-legal__body b, .c-legal__body strong { color: var(--text-on-dark); font-weight: var(--fw-medium); }
.c-legal__body a { color: var(--accent-on-dark); text-decoration: underline; text-underline-offset: 3px; }
.c-legal__body a:hover { color: var(--c-orange-lift); }
.c-legal__body address {
  font-style: normal;
  color: var(--text-on-dark-muted);
  line-height: 1.7;
  padding-left: var(--sp-5);
  border-left: 2px solid var(--c-orange);
  margin-bottom: var(--sp-4);
}

/* Contents rail — 14 sections is a lot to scroll blind. */
.c-legal__grid { display: grid; gap: var(--sp-8); align-items: start; }
@media (min-width: 64rem) {
  .c-legal__grid { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); gap: var(--sp-9); }
  /* Single column only when there is genuinely nothing in the left column.
     The check must cover BOTH occupants — a contents list or a pull-quote rail —
     or the page that has a rail but no TOC collapses to one column and the rail
     spans the full width. */
  .c-legal__grid:not(:has(.c-legal__toc)):not(:has(.c-legal__rail)) {
    grid-template-columns: minmax(0, 1fr);
  }
}
.c-legal__toc { position: sticky; top: calc(var(--header-h) + var(--sp-5)); display: none; }
@media (min-width: 64rem) { .c-legal__toc { display: block; } }
.c-legal__toc-list { border-left: 1px solid var(--rule-on-dark); }
.c-legal__toc-list a {
  display: block;
  padding: var(--sp-2) 0 var(--sp-2) var(--sp-4);
  margin-left: -1px;
  border-left: 1px solid transparent;
  font-size: var(--fs-small);
  line-height: 1.35;
  color: var(--text-on-dark-muted);
  transition: color var(--d-fast) var(--e-out), border-color var(--d-fast) var(--e-out);
}
.c-legal__toc-list a:hover { color: var(--c-orange); border-left-color: var(--c-orange); }
.c-legal__back { margin-bottom: var(--sp-6); }
.c-legal__quote {
  margin: 0 0 var(--sp-4) 0;
  padding: var(--sp-5);
  border-left: 2px solid var(--c-orange);
  background: var(--c-charcoal-2);
  font-family: var(--font-serif);
  font-size: var(--fs-lead);
  line-height: 1.45;
  color: var(--text-on-dark);
}

/* ==========================================================================
   Image crop wrappers
   These carry the crop and nothing else. They once held a scroll-linked
   translate, which drifted each photograph against the label beside it — the
   two then read as unrelated things that happened to share a box. Depth between
   sections is done at row level instead (see `.c-stack-rows`), so a row moves
   as one piece or not at all.
   ========================================================================== */
.c-tile__par, .c-face__par, .c-card__par {
  display: block;
  position: absolute;
  inset: 0;
}
.c-tile__par img, .c-face__par img, .c-card__par img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Belt and braces for the :has() rule below, in case :has() is unavailable.
   Applied only to pages that really have an empty left column. */
@media (min-width: 64rem) {
  .c-legal__grid--solo { grid-template-columns: minmax(0, 1fr); }
}
/* The rail column is wider than a contents list needs. */
@media (min-width: 64rem) {
  .c-legal__grid:has(.c-legal__rail) { grid-template-columns: minmax(0, 20rem) minmax(0, 1fr); }
}
/* ==========================================================================
   Cinematic media — a photograph as the band's ground, not an item in its flow
   The wrapper crops; the inner layer fills it absolutely. Without these the
   image falls into normal flow and sits BESIDE the copy at its natural size,
   taking the scrim with it.
   ========================================================================== */
.c-cine {
  position: relative;
  overflow: hidden;
  background: var(--c-charcoal-2);
}
.c-cine__inner {
  position: absolute;
  inset: 0;
}
.c-cine__inner img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  animation: slow-zoom 28s var(--e-in-out) infinite alternate;
}
@keyframes slow-zoom {
  from { transform: scale(1.005); }
  to   { transform: scale(1.045); }
}
@media (prefers-reduced-motion: reduce) {
  .c-cine__inner img { animation: none; transform: none; }
}

/* Warm grade so every photograph sits in the same light. It belongs to the
   band, not the image, so it stays put. */
.c-cine::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(120% 90% at 80% 85%, rgb(var(--rgb-orange) / 0.18) 0%, rgb(var(--rgb-orange) / 0) 55%),
    linear-gradient(to top, rgb(var(--rgb-black) / 0.5) 0%, rgb(var(--rgb-black) / 0) 45%);
}

/* ==========================================================================
   Legal hero — a statement band with a photograph, per the reference
   ========================================================================== */
.c-legalhero {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  min-height: clamp(24rem, 58vh, 34rem);
  background: var(--c-black);
}
@media (min-width: 64rem) {
  .c-legalhero { grid-template-columns: minmax(0, 46%) minmax(0, 54%); }
}
.c-legalhero__panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--sp-4);
  padding: calc(var(--header-h) + var(--sp-8)) var(--gutter) var(--sp-8);
  min-width: 0;
}
@media (min-width: 64rem) {
  .c-legalhero__panel {
    padding-right: var(--sp-7);
    /* The panel is full-bleed but .l-shell is capped at --max-w and centred, so
       a bare gutter left this title 16px inside everything below it at 1440 —
       close enough to look like a mistake rather than a decision. Align to the
       shell's content edge, as .c-split__text does. */
    padding-left: max(var(--gutter), calc((100vw - var(--max-w)) / 2 + var(--gutter)));
  }
}
.c-legalhero__title {
  font-family: var(--font-serif);
  font-weight: var(--fw-regular);
  font-size: clamp(2rem, 1.1rem + 2.4vw, 3.25rem);
  line-height: 1.04;
  letter-spacing: var(--ls-heading);
  color: var(--text-on-dark);
  text-wrap: balance;
  margin-top: var(--sp-3);
}
.c-legalhero__rule { width: 2rem; height: 1px; background: var(--c-orange); margin: var(--sp-5) 0; }
.c-legalhero__sub { font-size: var(--fs-small); line-height: 1.6; color: var(--text-on-dark-muted); max-width: 34ch; }
.c-legalhero__media { position: relative; min-height: 16rem; overflow: hidden; background: var(--c-charcoal-2); }
.c-legalhero__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
@media (min-width: 64rem) { .c-legalhero__media { min-height: 0; } }

/* Facts strip — real numbers from the document, nothing invented. */
.c-facts {
  display: grid;
  gap: var(--sp-5);
  padding-block: var(--sp-7);
  border-bottom: 1px solid var(--rule-on-dark);
}
@media (min-width: 48rem) { .c-facts { grid-template-columns: repeat(4, 1fr); gap: var(--sp-6); } }
.c-fact { padding-top: var(--sp-4); border-top: 2px solid var(--c-orange); }
.c-fact__v {
  display: block;
  font-family: var(--font-serif);
  font-weight: var(--fw-regular);
  font-size: clamp(1.5rem, 1.1rem + 1.3vw, 2.125rem);
  line-height: 1.05;
  color: var(--text-on-dark);
  margin-bottom: var(--sp-3);
  font-variant-numeric: tabular-nums;
}
.c-fact__k {
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-orange);
}

/* Pull-quote rail — the reference's left column, minus its invented copy. */
/* Sticky ONLY in the two-column layout, where the rail has a column of its own
   to travel down. Below 64rem the grid collapses to one column, so a sticky rail
   pins at the top and the body copy scrolls straight underneath it — the
   pull-quote ends up printed over the text. Measured: rail frozen at top:120
   while the body ran from 402 to -598 behind it. */
@media (min-width: 64rem) {
  .c-legal__rail { position: sticky; top: calc(var(--header-h) + var(--sp-6)); }
}
.c-pullquote {
  font-family: var(--font-serif);
  font-weight: var(--fw-regular);
  font-size: clamp(1.375rem, 1.1rem + 1vw, 1.75rem);
  line-height: 1.25;
  letter-spacing: var(--ls-heading);
  color: var(--c-orange);
  padding-block: var(--sp-6);
  border-top: 1px solid var(--rule-accent);
  border-bottom: 1px solid var(--rule-accent);
  margin: 0;
}
.c-pullquote__cite {
  display: block;
  margin-top: var(--sp-5);
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-on-dark-muted);
  font-style: normal;
}
/* "$1.5 million" and "Professional Standards Act 2004 (SA)" are both facts but
   wildly different lengths; one type size makes the long ones shout. */
.c-fact--long .c-fact__v { font-size: clamp(1.0625rem, 0.95rem + 0.5vw, 1.25rem); line-height: 1.25; }

/* ==========================================================================
   Row stacking — each band slides over the one before it, whole
   Every band pins at the top of the viewport; the next band, being later in
   flow, scrolls up and covers it, then pins in turn. The ROW moves as one
   piece — panel and photograph together — so the page reads as a deck of
   sections being dealt rather than one long scroll.

   This replaces the earlier reveal-window, which held the photograph still
   while its own text panel scrolled past: the two halves of a single row
   moving independently made the copy feel unrelated to the image.

   Requirements, all of which matter:
   - every band needs an OPAQUE background, or the pinned band shows through;
   - bands are siblings of <main>, which is the containing block that lets them
     stack rather than each sticking inside its own wrapper;
   - source order does the layering (sticky is positioned, z-index auto, so
     later siblings paint over earlier) — no z-index bookkeeping.
   ========================================================================== */
@media (min-width: 64rem) and (min-height: 44rem) {
  .c-stack-rows > .c-band,
  .c-stack-rows > .c-cta2,
  .c-stack-rows > .c-hero {
    position: sticky;
    top: 0;
  }
  /* The last band must release so the footer isn't covered by it. */
  .c-stack-rows > :last-child { position: relative; }
}

/* A pinned band that is taller than the viewport would have its lower half
   unreachable, so stacking is gated on height above. Below that, and on
   mobile where bands stack vertically and get tall, they just flow. */
@media (prefers-reduced-motion: reduce) {
  .c-stack-rows > .c-band,
  .c-stack-rows > .c-cta2,
  .c-stack-rows > .c-hero { position: relative; top: auto; }
}
