/*
 * Metters — site styles.
 * Reproduces the original Oxygen build's output under semantic class names.
 */

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

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

body {
  text-wrap: pretty;
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-normal);
  line-height: var(--lh-body);
  color: var(--mw-dark-blue);
  background: var(--mw-white);
  -webkit-font-smoothing: antialiased;
}

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

a {
  color: var(--mw-blue);
  text-decoration: none;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
}

/*
 * The browser's own surfaces.
 *
 * Selection, caret, scrollbar and form controls are the parts of a page a
 * visitor uses without looking at, and the cheapest signal that the thing was
 * designed rather than assembled. They take the brand rather than the OS.
 */
::selection {
  background-color: var(--mw-blue);
  color: var(--mw-white);
}

:root {
  accent-color: var(--mw-blue);
  caret-color: var(--mw-blue);
  scrollbar-color: var(--mw-blue) var(--mw-grey-1);
  scrollbar-width: thin;
}

/* Dark grounds carry their own, or the track glows against them. */
.section--dark,
.section--on-dark,
.block--dark,
.service-body,
.site-footer { scrollbar-color: var(--mw-blue) var(--mw-dark-blue); }

a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--mw-blue);
  outline-offset: 3px;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-body);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  color: var(--mw-dark-blue);
  margin: 0 0 0.5em;
  text-wrap: balance;
}

/*
 * Heading sizes map onto the scale with a real drop between each. The page
 * title was 36 against a 30 section heading, a ratio of 1.2, which is close
 * enough that the title did not read as a title. It takes the display size now
 * and the levels below it step down cleanly: 54 / 36 / 30 / 24.
 */
h1 { font-size: var(--fs-display); }
h2 { font-size: var(--fs-h1); }
h3 { font-size: var(--fs-h3); }
h4 { font-size: var(--fs-body); }
h5 { font-size: var(--fs-body); }
h6 { font-size: var(--fs-body); }

p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

.screen-reader-text {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.screen-reader-text:focus {
  position: fixed !important;
  top: 10px;
  left: 10px;
  width: auto;
  height: auto;
  clip: auto;
  z-index: 300;
  padding: 12px 18px;
  background: var(--mw-white);
  color: var(--mw-dark-blue);
}

/* ---------- Layout primitives ---------- */

.section { position: relative; }

.section__inner {
  max-width: var(--container);
  margin-inline: auto;
  padding: var(--section-pad-y) var(--section-pad-x);
}

/*
 * The grid.
 *
 * Twelve tracks and one gutter, everywhere. Blocks never choose a column
 * count — they choose a span, which is why a three-up grid and a four-up
 * grid on the same page still line up with each other.
 */
.grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-cols), minmax(0, 1fr));
  gap: var(--gutter);
  width: 100%;
}

.grid > * { grid-column: span 12; }

.grid--2 > * { grid-column: span 6; }
.grid--3 > * { grid-column: span 4; }
.grid--4 > * { grid-column: span 3; }

/* A header that sits beside its items rather than above them. */
.grid__aside { grid-column: span 4; }
.grid__main  { grid-column: span 8; }

/* Text spans. Running text stops at a readable measure whatever it spans. */
.span-3  { grid-column: span 3; }
.span-4  { grid-column: span 4; }
.span-5  { grid-column: span 5; }
.span-6  { grid-column: span 6; }
.span-7  { grid-column: span 7; }
.span-8  { grid-column: span 8; }
.span-12 { grid-column: span 12; }

.measure { max-width: 70ch; }

.section--flush > .section__inner { padding-block: 0; }
.section--dark {
  background-color: var(--mw-dark-blue);
  --block-fg: var(--mw-white);
  --block-muted: var(--mw-grey-1);
}
.section--dark, .section--dark h1, .section--dark h2, .section--dark h3,
.section--dark h4, .section--dark h5, .section--dark h6 { color: var(--mw-white); }
.section--verydark { background-color: var(--mw-very-dark); color: var(--mw-white); }

/*
 * On the page's own dark, rather than a dark of its own.
 *
 * `--dark` paints #383846, which is the footer's ground. A section inside an
 * already-dark page wants no ground at all — only the light type tokens — or
 * it reads as a panel laid over the page instead of part of it.
 */
.section--on-dark {
  --block-fg: var(--mw-white);
  --block-muted: var(--mw-grey-1);
}

.section--on-dark, .section--on-dark h1, .section--on-dark h2, .section--on-dark h3,
.section--on-dark h4, .section--on-dark h5, .section--on-dark h6 { color: var(--mw-white); }

.image-band {
  width: 100%;
  height: 525px;
  background-position: 50% 50%;
  background-size: cover;
  background-repeat: no-repeat;
}

/* The original hides the header-clearance spacer on small screens. */
.header-spacer { height: 150px; }

/* ---------- Alert bar ---------- */

.alertbar {
  background-color: var(--mw-very-dark);
  color: var(--mw-white);
}

.alertbar__inner {
  max-width: var(--container);
  margin-inline: auto;
  padding: 10px var(--section-pad-x);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--gap-s);
  flex-wrap: wrap;
  text-align: center;
}

.alertbar__text {
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  color: var(--mw-blue);
}

.alertbar__link {
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  color: var(--mw-blue);
  text-decoration: underline;
}

/* ---------- Header ---------- */

/*
 * The header overlays the page rather than sitting in flow: transparent and
 * absolutely positioned over whatever begins the page.
 *
 * Past ~300px of scroll it pins to the top and swaps to a compact state — icon
 * mark and burger only. It stays fully transparent throughout; the dark
 * background in the original's stylesheet never actually takes effect.
 */
.site-header {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  background-color: transparent;
}

/*
 * A scrim, not a bar: the header sits over photography, so it needs enough
 * ground to stay legible without becoming a band. Tinted to match whichever
 * type colour the page is using — dark under white type, light under dark —
 * so each keeps its own contrast.
 */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 220px;
  pointer-events: none;
  background-image: linear-gradient(to bottom, rgba(42, 42, 53, 0.55), rgba(42, 42, 53, 0));
}

.site-header--light-page::before {
  background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.75), rgba(255, 255, 255, 0));
}

.site-header__inner { position: relative; }

/*
 * No photograph, no scrim.
 *
 * The scrim exists to keep the header legible over an image. A template that
 * opens with a header-spacer has nothing under the header but the page's own
 * ground, so the gradient is only a smudge across the top of it — and which
 * smudge you got depended on a light_page flag that has nothing to do with
 * whether there is an image there.
 */
body:has(.header-spacer) .site-header::before { display: none; }

.site-header.is-stuck::before { display: none; }

/*
 * Pinned, the navigation takes a ground of its own: the full width of the
 * window, the page's own dark, and no edge, because the band is the edge.
 *
 * The wordmark gives way to the icon mark here — the compact state the site
 * has always had. The mark you see is `.site-mark` below; the header's own
 * copy stays in the row to hold its space, so the navigation does not shift
 * as the band comes and goes.
 */
.site-header.is-stuck {
  position: fixed;
  z-index: 100;
  background-color: var(--mw-very-dark);
  transform: translateY(0);
  transition: transform var(--dur) var(--ease-out);
}

.site-header.is-stuck .site-header__inner { padding-block: var(--gap-s); }
.site-header.is-stuck .site-header__logo { visibility: hidden; }
.site-header.is-stuck .site-header__wordmark { display: none; }
.site-header.is-stuck .site-header__mark { display: block; }

/*
 * Out of the way going down, back on the way up. Someone scrolling down is
 * reading and does not need the navigation; someone scrolling back up is
 * looking for it.
 */
.site-header.is-stuck.is-away { transform: translateY(-100%); }

/* One frame with the transition off, so taking the pinned state does not animate. */
.site-header.is-instant { transition: none; }

/*
 * The mark stays.
 *
 * It sits outside the header because the header is what slides — a child
 * cannot escape its parent's transform. Same container geometry as the pinned
 * row and the same `.site-header__mark` rules, so it lands exactly over the
 * copy holding its space and the two cannot drift apart at any width.
 *
 * Above the band, so the navigation slides underneath it rather than past it.
 */
.site-mark {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 101;
  max-width: var(--container);
  margin-inline: auto;
  padding: var(--gap-s) var(--section-pad-x);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--dur) var(--ease-out),
    visibility var(--dur);
}

body:has(.site-header.is-stuck) .site-mark { opacity: 1; visibility: visible; }

/* Only the mark takes the click, not the full width of the container. */
.site-mark .site-header__logo { width: max-content; pointer-events: auto; }
.site-mark .site-header__mark { display: block; }

/* Pinned, the type sits on the practice's own dark whatever the page is. */
.site-header.is-stuck .nav__link,
.site-header--light-page.is-stuck .nav__link { color: var(--mw-white); }

.site-header--light-page.is-stuck .burger__line { background-color: var(--mw-blue); }

.site-header__inner {
  max-width: var(--container);
  margin-inline: auto;
  padding: 0 var(--section-pad-x);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gutter);
}

.site-header__logo { display: flex; align-items: center; }
.site-header__wordmark { width: 200px; padding-block: 30px; }
.site-header__mark { display: none; width: 100px; }

.burger {
  appearance: none;
  background: none;
  border: 0;
  padding: 10px 0;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 7px;
  align-items: flex-end;
}

.burger__line {
  display: block;
  height: 3px;
  width: 40px;
  background-color: var(--mw-blue);
  transition: background-color var(--dur-fast) var(--ease);
}

/* ---------- Main menu + mega panel ---------- */

/*
 * The header overlays whatever begins the page, so the nav takes its colour
 * from the same light_page signal as the wordmark: dark type over a light
 * ground, white over a dark one.
 */
.site-nav { margin-left: auto; margin-right: 24px; }

.nav {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: var(--unit);
}

.nav__item { position: static; }

.nav__link {
  appearance: none;
  background: none;
  border: 0;
  padding: 6px 0;
  font: inherit;
  font-size: var(--fs-small);
  color: var(--mw-white);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--gap-xs);
  border-bottom: 1px solid transparent;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.site-header--light-page .nav__link { color: var(--mw-dark-blue); }
.nav__link.is-current { color: var(--mw-blue); border-bottom-color: var(--mw-blue); }


.nav__chev { width: 14px; height: 14px; transition: transform var(--dur) var(--ease-in-out); }
.nav__item--mega.is-open .nav__chev { transform: rotate(180deg); }

/*
 * The mega panel.
 *
 * It arrives rather than appearing: a short fall out of transparency, from
 * behind the header it belongs to. `visibility` rather than `display` so the
 * movement has something to move, stepped at the end of the transition when
 * closing so it does not stay clickable on its way out.
 */
.mega {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background-color: var(--mw-very-dark);
  color: var(--mw-white);
  z-index: 30;

  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease),
    visibility 0s linear var(--dur);
}

.nav__item--mega.is-open .mega {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition:
    opacity var(--dur) var(--ease-out),
    transform var(--dur) var(--ease-out),
    visibility 0s;
}

/* Its contents follow it in, a beat behind, so the panel leads. */
.mega__routes,
.mega__all {
  opacity: 0;
  transform: translateY(6px);
  transition:
    opacity var(--dur) var(--ease-out) 60ms,
    transform var(--dur) var(--ease-out) 60ms;
}

.nav__item--mega.is-open .mega__routes,
.nav__item--mega.is-open .mega__all { opacity: 1; transform: none; }

.mega__inner {
  max-width: var(--container);
  margin-inline: auto;
  padding: var(--space-2) var(--section-pad-x);
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: var(--gutter);
}

.mega__label {
  color: var(--mw-blue);
  font-weight: var(--fw-semibold);
  margin-bottom: 18px;
}

.mega__routes { display: grid; gap: var(--gap-xs); align-content: start; }

.mega__route {
  display: block;
  padding: 14px 0;
  border-top: 1px solid rgba(255, 255, 255, 0.16);
  color: var(--mw-white);
}

.mega__route-title {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-s);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
}

.mega__route-text {
  display: block;
  font-size: var(--fs-small);
  color: var(--mw-grey-1);
  margin-top: 4px;
  max-width: 46ch;
}

.mega__all { align-content: start; }

.mega__list {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  columns: 2;
  column-gap: var(--unit);
}

.mega__list li { break-inside: avoid; padding: 6px 0; }
.mega__list a { color: var(--mw-white); font-size: var(--fs-small); }

.mega__all-link { color: var(--mw-blue); }

/* The burger is the only route into the menu below the nav breakpoint. */
@media (max-width: 991px) {
  .site-nav { display: none; }
}

@media (min-width: 992px) {
  .burger { display: none; }
}

/*
 * Taps resolve immediately.
 *
 * The viewport allows zoom, which it should, so iOS has to decide whether each
 * tap is the start of a double-tap-to-zoom before it dispatches a click. On the
 * route cards, the project cards and the filter chips that was costing a tap.
 * `manipulation` keeps pinch-zoom and drops double-tap zoom on these elements
 * only, so the click fires on the first touch.
 */
a,
button,
label,
summary,
[role="button"],
input[type="submit"] { touch-action: manipulation; }

/* ---------- Off-canvas menu ---------- */

/*
 * Laid out as a drawing sheet rather than a centred list: everything ranges
 * left off one edge, groups are introduced by small tracked labels, hairlines
 * do the dividing, and the practice's details sit at the foot as a title block.
 *
 * It carries the same model as the desktop mega panel — routes first, then the
 * capabilities behind them — so both teach the same thing.
 */
.offcanvas {
  position: fixed;
  inset: 0;
  z-index: 200;
  background-color: var(--mw-very-dark);
  color: var(--mw-white);
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  overflow-y: auto;
  overscroll-behavior: contain;

  /*
   * Inert when shut, the way the mega panel already is.
   *
   * Translating it off-screen was not enough. It stayed `visible` and
   * pointer-active — a fixed, scrollable container parked against the right
   * edge — so iOS gave the first touch anywhere on the page to it as a
   * possible scroll gesture and swallowed the tap. One lost tap per page
   * load, which is what was reported. It also left twenty links tabbable
   * inside a panel marked `aria-hidden`.
   *
   * Visibility is delayed on the way out so the panel is still drawn while it
   * slides away, and flips immediately on the way in.
   */
  visibility: hidden;
  pointer-events: none;
  transition:
    transform var(--dur-slow) var(--ease-out),
    visibility 0s linear var(--dur-slow);
}

.offcanvas.is-open {
  transform: translateX(0);
  visibility: visible;
  pointer-events: auto;
  transition:
    transform var(--dur-slow) var(--ease-out),
    visibility 0s linear 0s;
}

.offcanvas__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gutter);
  padding: 20px var(--section-pad-x);
  border-bottom: 1px solid rgba(255, 255, 255, 0.16);
  flex-shrink: 0;
}

/* Sized to the header mark it mirrors, including its step down below 480. */
.offcanvas__logo img { width: 100px; }

.offcanvas__close {
  appearance: none;
  background: none;
  border: 0;
  color: var(--mw-white);
  line-height: 1;
  cursor: pointer;
  padding: 4px 0 4px 12px;
  display: flex;
  align-items: center;
}

.offcanvas__close-mark { width: 24px; height: 24px; }
.offcanvas__close:active { transform: scale(0.97); }

.offcanvas__sheet {
  padding: 0 var(--section-pad-x) var(--space-2);
  display: grid;
  gap: var(--unit);
  align-content: start;
}

.sheet__block { padding-top: 32px; }

/* The label is the structural device: it names the group and sets the column. */
.sheet__label {
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--mw-blue);
  margin: 0 0 14px;
  font-weight: var(--fw-semibold);
}

/*
 * One column. These were two, to take a third off the height of the sheet,
 * but a two-column index asks the reader to scan across as well as down —
 * and on the screen where this is the whole navigation, a single stack of
 * full-width rows is the easier thing to thumb through.
 */
.sheet__routes,
.sheet__list {
  list-style: none;
  margin: 0;
  padding: 0;
  text-align: left;
  display: grid;
  grid-template-columns: 1fr;
}

/* Routes carry the scale contrast — they're the choice the page is asking for. */
.sheet__routes li { border-top: 1px solid rgba(255, 255, 255, 0.16); }

.sheet__routes a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-m);
  padding: 16px 0;
  color: var(--mw-white);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
}

.sheet__list li { border-top: 1px solid rgba(255, 255, 255, 0.08); }

.sheet__list a {
  display: block;
  padding: 11px 0;
  color: var(--mw-white);
  font-size: var(--fs-small);
}

/* Title block: the sheet's own identification, at the foot. */
.sheet__titleblock {
  padding-top: 28px;
  border-top: 2px solid var(--mw-blue);
}

.sheet__meta {
  font-size: var(--fs-small);
  color: var(--mw-grey-1);
  display: grid;
  gap: var(--gap-xs);
}

.sheet__meta p { margin: 0; }
.sheet__meta a { color: var(--mw-grey-1); }

body.menu-open { overflow: hidden; }

/* ---------- Footer ---------- */

/*
 * Footer.
 *
 * Three groups on the shared grid, sized to what they hold rather than cut
 * into four equal quarters. Each carries the same tracked label the off-canvas
 * sheet uses, so the two navigations teach one model.
 *
 * It keeps --mw-dark-blue, which is the one place on the site that colour is
 * used. That is what separates the footer from the page above it.
 */
.site-footer {
  background-color: var(--mw-dark-blue);
  color: var(--mw-white);
  font-size: var(--fs-small);
}

.site-footer a { color: var(--mw-white); }

.site-footer__inner {
  max-width: var(--container);
  margin-inline: auto;
  padding: var(--space-3) var(--section-pad-x) var(--space-1);
}

.site-footer__grid { align-items: start; }

/*
 * The name sits straight on the address — they are one block of identity, so
 * the row gap is set per element rather than by one `gap` between all four
 * children (mark, name, address, socials).
 */
.site-footer__identity { display: grid; row-gap: 0; align-content: start; }
.site-footer__wordmark { width: 200px; height: auto; }

/* Carries the full name now the mark above it has no strapline. */
.site-footer__name { margin: var(--space-1) 0 0; font-weight: var(--fw-bold); }

.site-footer__identity .socials { margin-top: var(--space-1); }

.site-footer__address { font-style: normal; display: grid; gap: var(--gap-s); }
.site-footer__address p { margin: 0; }

.socials { display: flex; flex-direction: row; gap: var(--gap-s); align-items: center; }

.socials a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 1px solid var(--mw-blue-20);
  border-radius: 50%;
  color: var(--mw-white);
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.socials svg { width: 16px; height: 16px; fill: currentColor; }

.site-footer__block { display: grid; gap: var(--gap-m); align-content: start; }

/* The same label the off-canvas sheet uses, under the same hairline. */
.site-footer__label {
  margin: 0;
  padding-top: var(--gap-s);
  border-top: 1px solid var(--mw-blue);
  color: var(--mw-blue);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.site-footer__menu {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--gap-s);
}

/* Ten services read as an index in two columns, not a column of ten. */
.site-footer__menu--split {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--gutter);
}

/*
 * The closing row: what the practice is accredited by, and the small print.
 * One line, one rule, where there used to be two bands.
 */
.site-footer__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-1) var(--space-2);
  margin-top: var(--space-2);
  padding-top: var(--space-1);
  border-top: 1px solid var(--mw-blue-20);
}

.accreditations { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); }
.accreditations img { height: 44px; width: auto; }

.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-s) var(--gap-m);
  font-size: var(--fs-label);
  color: var(--mw-grey-1);
}

.site-footer__legal a { color: var(--mw-grey-1); }
.entry-content img { border-radius: 0; }

/*
 * Plain pages: the policies, the questionnaire, the resources pages.
 *
 * These render the editor's own content with no blocks to set the rhythm, so
 * every heading arrived with margin-top: 0 and landed on the paragraph above
 * it — a 35px heading 18px clear of the previous line, and sections 0px apart.
 * A heading belongs to what comes after it, so the space goes above it.
 *
 * The text runs the width of the container, as it did before: these pages
 * were set that way deliberately and a narrower measure was not wanted.
 *
 * Scoped to the default template so the blocks, the team intro and the hero
 * standfirst — all of which also use .entry-content — keep their own spacing.
 */
.page-template-default .entry-title { margin-bottom: var(--space-1); }

.page-template-default .entry-content h2 { margin-top: var(--space-2); }

.page-template-default .entry-content h3,
.page-template-default .entry-content h4 { margin-top: var(--space-1); }

/* Nothing pushes the top of the page down twice. */
.page-template-default .entry-content > :first-child,
.page-template-default .entry-content > :first-child > :first-child,
.page-template-default .entry-content > :first-child > :first-child > :first-child { margin-top: 0; }

/* ---------- Galleries ---------- */

.gallery {
  column-count: 2;
  column-gap: var(--gutter);
}

.gallery--spaced { padding-bottom: var(--space-2); }

/* A first gallery runs one image per row, full width, as the original did. */
.gallery--single { column-count: 1; }

.gallery__item {
  margin: 0 0 20px;
  break-inside: avoid;
  page-break-inside: avoid;
}

.gallery__img { width: 100%; height: auto; }

.gallery__caption {
  font-size: var(--fs-small);
  color: var(--mw-grey-9);
  padding-top: 6px;
}

/*
 * Heading and text beside a picture. Source order puts the words first, so
 * "text right" is a row reversal rather than a second markup path — the reading
 * order stays words-then-picture however it is arranged.
 */
.block--left-column__pair--reversed > .prose { order: 2; }
.block--left-column__pair--reversed > .block--left-column__media { order: 1; }

.block--left-column__media img {
  width: 100%;
  height: auto;
  display: block;
  aspect-ratio: var(--card-ratio);
  object-fit: cover;
}

/* ---------- Single project ---------- */

.project__hero {
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
  height: 90vh;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
}

.project__hero-inner {
  max-width: var(--container);
  margin-inline: auto;
  width: 100%;
  padding: var(--section-pad-y) var(--section-pad-x);
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
}

/* Landscape, about 1.7 to 1, so 260 rather than the 200 a square mark took. */
.project__award { width: 260px; height: auto; }
.project__award-mobile { display: none; }

/*
 * The drop from the hero to the title. It was a flat 200px carried over
 * from the original, which put nearly 300px between the photograph and the
 * title once the section's own padding was added. On the rhythm now, and
 * about half what it was.
 */
.project__spacer { height: var(--space-2); }

/*
 * Original grid: two equal columns with a 40px column gap and 20px row gap.
 * Title sits left, body right, credit returns to the left on the next row.
 */
.project__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(200px, 1fr));
  column-gap: var(--gutter);
  row-gap: var(--gutter);
  align-items: stretch;
  text-align: left;
}

.project__location { margin: 0; }
.project__title { margin-bottom: 0.3em; }

.project__credit {
  grid-column: 1;
  display: flex;
  flex-direction: row;
  gap: var(--gap-xs);
  font-size: var(--fs-small);
  margin: 0;
}

.project__wide {
  height: 700px;
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
}

.section--flush-top > .section__inner { padding-top: 0; }

.project__before-text { margin-top: 12px; }

/* ---------- Single team member ---------- */

.team-member__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(200px, 1fr));
  column-gap: var(--gutter);
  row-gap: var(--gutter);
  align-items: stretch;
  text-align: left;
}

.team-member__name { margin-bottom: 0.3em; }
.team-member__quals { margin: 0; }

.team-member__position {
  color: var(--mw-dark-blue);
  font-weight: var(--fw-semibold);
  margin: 0;
}

.team-member__portrait { margin-top: 20px; }

/* ---------- Single news post ---------- */

.post-single__hero {
  min-height: 80vh;
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
}

/*
 * An article runs across the page for its title and then narrows to read. The
 * rail carries the two things someone checks before trusting a page about
 * planning rules — when it was written and who by — and holds them beside the
 * opening rather than burying them under it.
 */
.post-single__title { margin-top: 0; margin-bottom: var(--space-2); }

.post-single__body { align-items: start; }

.post-single__rail {
  position: sticky;
  top: var(--space-4);
  padding-top: var(--gap-s);
  border-top: 2px solid var(--mw-blue);
}

.article-meta { display: grid; gap: var(--space-1); }
.article-meta__row { display: grid; gap: 2px; }

.article-meta__label {
  margin: 0;
  color: var(--mw-blue);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.article-meta__value { margin: 0; font-size: var(--fs-small); }

.article-meta__person {
  display: flex;
  align-items: center;
  gap: var(--gap-s);
  color: inherit;
  margin-top: var(--gap-xs);
}

.article-meta__photo {
  display: block;
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  border-radius: 50%;
  overflow: hidden;
}

.article-meta__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

.article-meta__name { display: block; font-weight: var(--fw-semibold); font-size: var(--fs-small); }

.article-meta__role { display: block; font-size: var(--fs-label); color: var(--mw-grey-9); }

/*
 * The reading column: wide enough for an image, capped for running text.
 *
 * 70ch measures 781px in this face and comes out at 67 characters a line —
 * `ch` is the advance of the zero, which is wider than the average letter, so
 * the number is not the character count. Measured, not assumed. The old
 * full-width layout ran about 106.
 */
.post-single__main .entry-content > p,
.post-single__main .entry-content > ul,
.post-single__main .entry-content > ol,
.post-single__main .entry-content > h2,
.post-single__main .entry-content > h3,
.post-single__main .entry-content > blockquote { max-width: 70ch; }

.post-single__credit {
  display: flex;
  flex-direction: row;
  gap: var(--gap-xs);
  font-size: var(--fs-small);
  margin-top: 20px;
}

/* ---------- Card grid (news index) ---------- */

.card-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(200px, 1fr));
  column-gap: var(--gutter);
  row-gap: var(--gutter);
  align-items: stretch;
  margin-bottom: var(--space-2);
}

.card__link {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--gap-s);
  color: inherit;
}

/*
 * Card media: one fixed-ratio box per card. The image lives in its own layer so
 * it can zoom inside the box without resizing the card, and the overlay sits on
 * top carrying the practice mark. Rebuilt from the original's leftover
 * structure, whose hover rules had been emptied at some point — the 70px mark,
 * the centring and the 0.3s ease-in-out timing are its.
 */
.card__media {
  display: block;
  position: relative;
  width: 100%;
  aspect-ratio: var(--card-ratio);
  overflow: hidden;
  background-color: var(--mw-dark-blue);
}

.card__image {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
  transition: transform var(--dur-slow) var(--ease-out);
}

.card__overlay {
  position: absolute;
  inset: 0;
  background-color: rgba(42, 42, 53, 0.55);
  background-image: url("../../../../uploads/2026/03/MW_ROUND_WHITEREV.svg");
  background-size: 70px 70px;
  background-position: 50% 50%;
  background-repeat: no-repeat;
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}

/*
 * Movement on hover is gated to real pointers. A touch device has no hover
 * state to leave, so an ungated zoom latches on tap and stays there.
 *
 * Colour changes were once left ungated on the reasoning that on touch they
 * read as a tap acknowledgement. They are gated now too, so a tap cannot latch
 * a hover state that a touch screen has no way to leave. See the block at the
 * foot of this file.
 *
 * Note this was not the cause of the double-tap that was reported: that was
 * the off-canvas panel staying pointer-active while shut.
 */
/*
 * Focus gets the scrim and the mark, not the zoom. Safari matches
 * :focus-visible on a link after a tap, and a scale on the image moved the
 * card under the finger between touchstart and touchend — the hit test then
 * lands somewhere else and the click is dropped. Opacity changes nothing
 * geometric, so the affordance stays and the tap survives.
 */
.card__link:focus-visible .card__overlay { opacity: 1; }

@media (hover: hover) and (pointer: fine) {
  .card__link:hover .card__image { transform: scale(var(--card-zoom)); }
  .card__link:hover .card__overlay { opacity: 1; }
}

/*
 * Card titles carry their own size rather than inheriting from their tag.
 * The heading level belongs to the outline and changes with the page around
 * it; the size belongs to the component and must not.
 */
.card__title,
.service-card__title,
.team-card__name {
  font-size: var(--fs-h3);
  line-height: var(--lh-heading);
}

.card__title { text-align: left; margin: 0; }

/*
 * Card type reads from whatever ground it is on. A literal here is what made
 * an excerpt render #383846 on a #2a2a35 block — invisible — and patching it
 * per-section only moved the bug to the next context that sets its own ground.
 */
.card__excerpt {
  color: var(--block-muted, var(--mw-dark-blue));
  text-align: left;
  margin: 0;
}

.card__more {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-xs);
  color: var(--block-heading, var(--mw-blue));
  font-weight: var(--fw-semibold);
}

.card__arrow { width: 20px; height: 20px; }

.news-archive__title { margin-bottom: 0; }
.news-archive__lede { margin-bottom: var(--space-2); }

/*
 * News pagination.
 *
 * `paginate_links` emits bare `.page-numbers`, so until now a page number was
 * a 12px digit in a 5px-wide box — under even the 24px a pointer target is
 * meant to be, let alone a comfortable one. Each one is a chip now, built from
 * the same parts as the projects filter so the two read as one family: the
 * same border, radius, size and the blue fill for the state you are in.
 */
.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-s);
  margin-top: var(--space-2);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
}

.pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 6px var(--gap-m);
  border: 1px solid var(--mw-grey-5);
  border-radius: var(--radius-button);
  color: var(--mw-dark-blue);
  transition:
    background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease);
}

/*
 * The page you are on. Filled like a chosen filter chip, but in the dark blue
 * rather than the light one: white on --mw-blue is 2.38:1, which the chips get
 * away with because a chip is a word you can also see is pressed, and a page
 * number is nothing but the digit. White on --mw-dark-blue is 11.5:1.
 */
.pagination .page-numbers.current {
  background-color: var(--mw-dark-blue);
  border-color: var(--mw-dark-blue);
  color: var(--mw-white);
}

/* An ellipsis is a label, not a target. */
.pagination .page-numbers.dots {
  border-color: transparent;
  color: var(--mw-grey-9);
  min-width: 0;
  padding-inline: 0;
}

/* ---------- Front page ---------- */

/*
 * An arrow link is not a button — no ground, no border. It gets fit-content for
 * the same reason the button does.
 */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-xs);
  width: fit-content;
  max-width: 100%;
  font-weight: var(--fw-semibold);
  transition: color var(--dur-fast) var(--ease);
}

.arrow {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  transition: transform var(--dur-fast) var(--ease);
}

/* The one signature movement on the site: the arrow leads, by 3px. */
.link-arrow:focus-visible .arrow,
.button:focus-visible .arrow,
.card__link:focus-visible .card__arrow,
.service-card__link:focus-visible .arrow { transform: translateX(var(--nudge)); }

@media (hover: hover) and (pointer: fine) {
  .link-arrow:hover .arrow,
  .button:hover .arrow,
  .card__link:hover .card__arrow,
  .service-card__link:hover .arrow { transform: translateX(var(--nudge)); }
}

.home-hero {
  width: 100%;
  height: 100vh;
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

/*
 * The photograph runs full-bleed; the dark plate over it does not — it spans the
 * page container, so the title starts on the same line as everything below it.
 * The wrapper carries no padding of its own: the plate's own 20px is what sets
 * the title in from the container edge.
 */
.home-hero__inner {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
}

.home-hero__plate {
  width: 100%;
  background-color: var(--mw-dark-blue);
  padding: 20px 20px 30px;
}

/*
 * The same pair as a service page's opening block: title at display size on
 * `--lh-heading`, standfirst at h3. It used to carry the practice's name on a
 * looser line, which was fine for two words and loose for a sentence.
 */
/*
 * The practice's name above the heading, not in it: same size and weight as
 * the H1 below, in the brand blue against the H1's white. The heading keeps
 * what the practice does and where, which is what a search reads.
 */
.home-hero__name {
  margin: 0;
  color: var(--mw-blue);
  font-size: var(--fs-display);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
}

.home-hero__title {
  font-size: var(--fs-display);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  text-wrap: balance;
  color: var(--mw-white);
  padding-bottom: 10px;
  margin: 0;
}

.home-hero__sub {
  font-size: var(--fs-h3);
  font-weight: var(--fw-normal);
  line-height: var(--lh-body);
  color: var(--mw-white);
  max-width: 62ch;
  margin: 0;
}
.home-hero__sub > :first-child { margin-top: 0; }
.home-hero__sub > :last-child { margin-bottom: 0; }

/*
 * Where to start introduces itself with a label and a heading, and nothing
 * above them. The 2px rule that used to run across both this and the Welcome
 * section has gone: Welcome now opens on its own heading instead of a labelled
 * rule, which left one line on the page ruling one thing, and a rule that
 * separates nothing is just a line.
 */
/* The eyebrow sits tight above the heading it labels — the same gap the lead
   hero uses, not a section's worth of space. */
.home-routes__head { row-gap: var(--gap-m); }

/* The label spans the container, with the heading beneath it on the same left
   edge — the arrangement the rule used to sit across. */
.home-routes__rule { grid-column: 1 / -1; }

/* Ranged left. Eight columns keeps the measure readable. */
.home-routes__copy { grid-column: 1 / span 8; }

.home-routes__label {
  display: block;
  margin: 0;
  color: var(--mw-blue);
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
}

/*
 * Mark above tagline, centred, and the tagline balanced over two lines.
 *
 * It spans the full grid rather than the copy's eight columns, so it centres on
 * the section rather than on the column above it. The measure is what makes the
 * two lines: the line runs to 531px unbroken, so capping it forces the wrap and
 * `text-wrap: balance` evens the two halves instead of leaving a long line and
 * a short one.
 *
 * The space below is padding, not margin: the section's own padding-bottom is
 * zero on the team page, and a margin there collapses out and shows as a band
 * of the wrong colour.
 */
.home-intro__strap {
  grid-column: 1 / -1;
  margin-bottom: 0;
  padding-bottom: var(--space-3);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--gap-m);
}

.home-intro__tagline {
  text-transform: uppercase;
  margin: 0;
  max-width: 30ch;
  text-wrap: balance;
}

.home-intro__mark { width: 40px; flex-shrink: 0; }

/*
 * On the team page the strap followed the copy with nothing between them, so
 * the mark sat straight under the last line. It takes the same space above as
 * below, which puts it in a band of its own rather than at the foot of the
 * paragraph. The services page strap has its own modifier and is unaffected.
 */
.team-intro__strap { padding-top: var(--space-3); }

.home-featured-label { background-color: var(--mw-dark-blue); }
.home-featured-label > .section__inner { padding-bottom: var(--space-2); position: relative; }

/*
 * Set to the width of the band rather than to a size.
 *
 * "RECENT PROJECTS" measures 9.017em across in the light weight, so dividing
 * the space available by that gives the size that spans it — capped by the
 * container, and tracking the viewport below it. The divisor carries about 1%
 * of headroom so a slow or failed webfont cannot push the line past the edge;
 * it wraps rather than overflowing if the fallback is wider.
 *
 * Re-measure the divisor if the words or the weight change.
 */
.home-featured-label__title {
  --mw-label-ratio: 9.1;
  margin: 0;
  font-size: min(
    calc((var(--container) - (2 * var(--section-pad-x))) / var(--mw-label-ratio)),
    calc((100vw - (2 * var(--section-pad-x))) / var(--mw-label-ratio))
  );
  line-height: 0.9;
  font-weight: var(--fw-light);
  text-transform: uppercase;
  color: var(--mw-white);
}

/* The heading has moved up into the band, so the link holds this row alone. */
.home-projects__head > .link-arrow { margin-left: auto; }

.home-featured-label__fade {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 200px;
  background-image: linear-gradient(rgba(56, 56, 70, 0), var(--mw-dark-blue));
  pointer-events: none;
}

/*
 * The featured band sits inside the page container, matching the original —
 * only the heroes run full-bleed.
 */
.home-featured {
  display: flex;
  flex-direction: row;
  width: 100%;
}

.home-featured--overlap {
  margin-top: -90px;
  position: relative;
  z-index: 5;
  box-shadow: 0 -40px 20px -20px rgba(42, 42, 53, 0.75);
}

.home-featured__media {
  width: 60%;
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
}

.home-featured__panel {
  width: 40%;
  background-color: var(--mw-dark-blue);
  color: var(--mw-white);
  min-height: 500px;
  padding: var(--gutter) var(--space-2);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.home-featured__panel h2 { color: var(--mw-white); }
.home-featured__eyebrow { color: var(--mw-blue); }

/*
 * Three routes.
 *
 * The head borrows the intro band's device — a fixed 200px column under a blue
 * rule — so the label, the heading and the first card all range off the same
 * left edge as everything else on the page.
 */
/* Butted against the dark bands above and below, the run reads as one. */
.home-routes.section--dark + .section--dark > .section__inner { padding-top: 0; }

.home-routes__head { margin-bottom: var(--space-2); }

.home-routes__title {
  font-size: var(--fs-h1);
  font-weight: var(--fw-bold);
  margin: 0 0 12px;
}

.home-routes__lede { margin: 0; }

.card-grid--routes {
  grid-template-columns: repeat(3, minmax(200px, 1fr));
  column-gap: var(--gutter);
  row-gap: var(--gutter);
  margin-bottom: 0;
}

/*
 * The route card carries its own column now that it is not wrapped in one
 * anchor — the layout that lived on `.card__link` moves here.
 */
.route-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--gap-s);
  color: inherit;
}

.route-card__media { display: block; width: 100%; }
.route-card__title { font-size: var(--fs-h3); }
.route-card__title a { color: inherit; }

/*
 * Route highlights.
 *
 * The specifics behind a route — the long-tail work people actually search
 * for. Hairlines between rather than bullets: the list is a set of facts of
 * equal weight, and a rule separates without implying sequence.
 */
.route-card__points {
  display: grid;
  list-style: none;
  padding: 0;
  margin: 0;
  /*
   * The card link is a flex column ranged to flex-start, so its children
   * shrink-wrap on the cross axis. Without this the rules stop at the longest
   * line rather than crossing the card, which reads as a ragged edge.
   */
  width: 100%;
  border-top: 1px solid var(--mw-grey-1);
  margin-top: var(--gap-xs);
}

.route-card__point {
  border-bottom: 1px solid var(--mw-grey-1);
  font-size: var(--fs-small);
  color: var(--mw-grey-9);
}

/*
 * The padding sits on the link where there is one, so the whole row is the
 * tap target rather than just the words.
 */
.route-card__point > a,
.route-card__point { padding: var(--gap-s) 0; }
.route-card__point > a { display: block; padding-inline: 0; color: inherit; }
.route-card__point:has(> a) { padding: 0; }

/*
 * On the dark ground the whole card inverts: the hairlines take a tint of the
 * blue the site rules with, and the type comes up to white.
 */
.section--dark .route-card__points { border-top-color: var(--mw-blue-20); }
.section--dark .route-card__point {
  border-bottom-color: var(--mw-blue-20);
  color: var(--mw-grey-1);
}


.section--dark .home-routes__label { color: var(--mw-blue); }
.section--dark .home-routes__lede { color: var(--mw-grey-1); }

.home-projects > .section__inner { padding-top: var(--space-2); }

.home-projects__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gutter);
  flex-wrap: wrap;
  margin-bottom: 20px;
}

.home-projects__label { font-size: var(--fs-h1); font-weight: var(--fw-bold); margin: 0; }


.home-services-intro > .section__inner {
  padding-bottom: 0;
  display: flex;
  flex-direction: row;
  align-items: flex-end;
  gap: var(--gutter);
}

.home-services-intro__copy { width: 33%; }

.home-services-intro__title {
  color: var(--mw-blue);
  font-weight: var(--fw-bold);
  margin-bottom: var(--gutter);
}

.home-services-intro__media { flex-grow: 1; }

.home-services > .section__inner { padding-top: var(--space-1); }

.card-grid--services {
  grid-template-columns: repeat(3, minmax(200px, 1fr));
  column-gap: var(--gutter);
  row-gap: var(--space-1);
  margin-bottom: 0;
}

/*
 * Service cards take the Grid block's ruled treatment: a hairline above each
 * item rather than a panel around it. It is the lightest way to separate a set
 * of equals, and it puts every card's top edge on the same line — which is the
 * whole argument for a grid, drawn.
 */
.service-card {
  padding-top: var(--gap-s);
  border-top: 1px solid var(--mw-blue);
}

.service-card__link {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--gap-xs);
  height: 100%;
  color: inherit;
}

.service-card__title { text-align: left; margin: 0; }
.service-card__excerpt { color: var(--block-muted, var(--mw-dark-blue)); margin: 0; }

/* The arrow drops to the foot so it sits on one line across the row. */
.service-card__link .arrow { margin-top: auto; }


.home-news { background-color: var(--mw-blue-20); }

.home-news__label {
  color: var(--mw-blue);
  font-weight: var(--fw-bold);
  margin: 0 0 var(--gutter);
}

.home-news__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(200px, 1fr));
  column-gap: var(--gutter);
  row-gap: var(--gutter);
  align-items: start;
}

.news-item { display: flex; flex-direction: row; gap: var(--gap-m); }
.news-item__media { flex-shrink: 0; }
.news-item__media img { width: 200px; object-fit: cover; aspect-ratio: var(--card-ratio); }
.news-item__title { margin: 0 0 6px; }
.news-item__title a { color: inherit; }
.news-item__excerpt { margin: 0 0 8px; }

/* ---------- Service page blocks ---------- */

/*
 * Blocks carry their own ground via a light/dark selector. Colours are driven
 * through local custom properties so every child inherits the right pairing
 * without each one needing its own light and dark rule.
 */
.block {
  background-color: var(--block-bg);
  color: var(--block-fg);
}

.block--dark {
  --block-bg: var(--mw-very-dark);
  --block-fg: var(--mw-white);
  --block-heading: var(--mw-blue);
  --block-muted: var(--mw-grey-1);
}

.block--light {
  --block-bg: var(--mw-white);
  --block-fg: var(--mw-dark-blue);
  --block-heading: var(--mw-mid-blue);
  --block-muted: var(--mw-grey-9);
}

.block h1, .block h2, .block h3, .block h4 { color: var(--block-fg); }
.block__heading {
  color: var(--block-heading);
  font-size: var(--fs-h1);
  line-height: var(--lh-heading);
  text-wrap: balance;
}

/*
 * A section statement.
 *
 * The one place a section heading is set at display size. It stays an h2 —
 * the level describes the outline, the class describes the emphasis — and it
 * is for a section that opens a whole territory, not a subsection. Used
 * sparingly: two on the home page, and nowhere else.
 */
.section-statement {
  font-size: var(--fs-display);
  line-height: var(--lh-heading);
  text-wrap: balance;
}
.block__body { color: var(--block-fg); }
.block__body a { color: var(--block-heading, var(--mw-blue)); }

.block--section-title > .section__inner { padding-bottom: var(--space-3); }

.block__head {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: var(--gap-s);
  text-align: left;
}

/* The page title. Sentence case — a title does not need to shout to lead. */
.block__title {
  font-size: var(--fs-display);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  text-wrap: balance;
}

/* Intro sits in the first two of three columns. */
.block__intro-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(200px, 1fr));
  column-gap: var(--gutter);
  row-gap: var(--gutter);
  width: 100%;
}

.block__intro-grid > :last-child { grid-column: span 2; }
.block__intro { font-size: var(--fs-h3); }

.block--text > .section__inner,
.block--services-offering > .section__inner,
.block--simple-text > .section__inner { padding-block: var(--space-1); }

.block--left-column > .section__inner { padding-top: var(--space-3); }

.block__two-col {
  display: grid;
  grid-template-columns: repeat(2, minmax(200px, 1fr));
  column-gap: var(--gutter);
  row-gap: var(--gutter);
  width: 100%;
  align-items: stretch;
}

.block--full-image {
  height: 800px;
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
}

/*
 * Services offered: three across, each item a panel a shade lighter than the
 * ground it sits on so the list reads as a set of cards.
 */
/* The services list is a `.points` grid now; see the item treatments below. */

/*
 * Points.
 *
 * The grid itself is `.grid` — the column count is a span, set by the block's
 * Columns option. What is left here is the item, and the three ways of
 * separating one item from the next.
 */
.points { text-align: left; }

.points__item { display: grid; gap: var(--gap-xs); align-content: start; }

/* Panel: a shade lighter than the ground, so the set reads as cards. */
.points__item--panel { padding: var(--gap-s); background-color: var(--mw-dark-blue); }
.block--light .points__item--panel { background-color: var(--mw-grey-1); }

/* Ruled: a hairline above each item — the lightest way to separate them. */
/*
 * Two rule weights, and the difference is what they do.
 *
 * A hairline separates a set of equals — the grids, the nav lists, the
 * highlight rows. A 2px rule marks the head of a title block, and there is
 * one of those per section. Repeating a marker's weight across twelve cards
 * is what made the grid shout.
 */
.points__item--ruled { padding-top: var(--gap-s); border-top: 1px solid var(--mw-blue); }

.points__title {
  color: var(--mw-blue);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  margin-bottom: 0;
}

.block .points__title { color: var(--block-heading, var(--mw-blue)); }

.points__text > :first-child { margin-top: 0; }
.points__text > :last-child { margin-bottom: 0; }

/* A grid's heading, whether it sits above the items or beside them. */
.grid__head { display: grid; gap: var(--gap-s); align-content: start; margin-bottom: var(--space-1); }
.grid__aside .grid__head { margin-bottom: 0; }
.block__lede { color: var(--block-fg); }

/* Prose arrangements. */
.prose { display: grid; gap: var(--gap-m); align-content: start; }
.block__body--lede { font-size: var(--fs-h3); line-height: 1.45; }

/* Quote arrangements. */
.quote--ruled {
  border-left: 1px solid var(--mw-blue);
  padding-left: var(--gutter);
  max-width: 46ch;
}

/*
 * Steps.
 *
 * An ordered list, and marked up as one, because the order is the content:
 * step one precedes step two. The label carries the sequence in words, so no
 * number is drawn — a reader who sees "Step one · Free" does not also need a
 * numeral beside it.
 *
 * Each step is a hairline box rather than a filled panel, which is the same
 * device the grids use, at the scale of a whole card.
 */
.steps {
  list-style: none;
  margin: 0;
  padding: 0;
}

.step {
  grid-column: span var(--step-span, 6);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--gap-m);
  padding: var(--space-1);
  border: 1px solid var(--mw-blue-20);
}

.step__label {
  margin: 0;
  color: var(--block-heading, var(--mw-blue));
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.step__title {
  margin: 0;
  font-size: var(--fs-h3);
  line-height: var(--lh-heading);
  color: var(--block-fg, var(--mw-dark-blue));
}

.step__body {
  margin: 0;
  color: var(--block-muted, var(--mw-dark-blue));
  max-width: 46ch;
}

.step__body > :first-child { margin-top: 0; }
.step__body > :last-child { margin-bottom: 0; }

/* The button drops to the foot so a pair line up however long the copy runs. */
.step .button { margin-top: auto; }

/* Figure: a contained image that can carry a caption and a credit. */
.figure { margin: 0; display: grid; gap: var(--gap-s); }
.figure__image { display: block; width: 100%; height: auto; }

.figure__caption {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--gap-s) var(--gutter);
  font-size: var(--fs-small);
  color: var(--block-muted);
}

.figure__credit { color: var(--block-heading, var(--mw-blue)); }

/* Selected projects reuse the card, so the hover and the ratio can't drift. */
.block--selected-projects .card-grid { margin-bottom: 0; }

/* Media band, split. */
.media-split { display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; width: 100%; }

.media-split__photo {
  min-height: 360px;
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
}

.media-split__copy {
  padding: var(--space-2) var(--space-2);
  display: grid;
  gap: var(--gap-m);
  align-content: center;
}

.block__label {
  color: var(--mw-blue);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  margin: 0;
}

/*
 * The button.
 *
 * One rectangle, 3px corners, and a rollover that inverts it. Everything that
 * reads as a button uses this — the service-page call to action, the projects
 * filter, the Gravity Forms submit — so they cannot drift apart again.
 *
 * `width: fit-content` rather than an alignment property, because a button is
 * usually a flex or grid child: `inline-flex` gets blockified to `flex` there
 * and then stretched by the default `stretch` alignment, which is why buttons
 * were running the full width of a block in some places and not others.
 * fit-content shrink-wraps without overriding how the parent aligns it.
 */
.button,
.gform_wrapper .gform_footer input[type="submit"],
.gform_wrapper .gform_footer button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--gap-s);
  width: fit-content;
  max-width: 100%;
  padding: var(--gap-s) var(--gutter);
  background-color: var(--mw-white);
  border: 1px solid var(--mw-blue);
  border-radius: var(--radius-button);
  color: var(--mw-blue);
  font-family: inherit;
  font-size: var(--fs-body);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-heading);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease);
}
.button:focus-visible,
.gform_wrapper .gform_footer input[type="submit"]:focus-visible,
.gform_wrapper .gform_footer button:focus-visible {
  background-color: var(--mw-blue);
  border-color: var(--mw-blue);
  color: var(--mw-white);
}


/* A press is the one place a control moves. One pixel is enough to feel it. */
.button:active,
.gform_wrapper .gform_footer input[type="submit"]:active,
.gform_wrapper .gform_footer button:active { transform: scale(0.97); }

/*
 * Solid: the same rectangle filled. For the primary of two actions sitting
 * together — it inverts to the outline on hover, so the pair swap emphasis
 * rather than one of them doing something the other cannot.
 */
.button--solid {
  background-color: var(--mw-blue);
  border-color: var(--mw-blue);
  color: var(--mw-white);
}
.button--solid:focus-visible {
  background-color: var(--mw-white);
  color: var(--mw-blue);
}


/* Ghost: same rectangle, no ground. For a control beside content, not below it. */
.button--ghost { background-color: transparent; color: inherit; }
.button--ghost:focus-visible { background-color: var(--mw-blue); color: var(--mw-white); }


/* Full width is opted into, never inherited from a parent's alignment. */
.button--full { width: 100%; }

/* On a dark ground the ground is the thing that changes. */
.block--dark .button--ghost,
.section--dark .button--ghost { color: var(--mw-white); }

.quote { margin: 0; max-width: 62ch; }
.quote__body { font-size: var(--fs-h3); color: var(--block-fg); }
.quote__cite { display: block; margin-top: 12px; font-style: normal; color: var(--block-heading, var(--mw-blue)); }

.block__form { margin-top: 20px; }
/*
 * Accent and secondary text inside a block take the block's own ground into
 * account. `--mw-blue` reads on the dark but comes to 2.4:1 on white, and a
 * hardcoded white came to 1:1 — text the same colour as the paper. The two
 * block variables already carry the right value for each ground; they were
 * declared and then not used.
 */
.points__text { color: var(--block-muted, var(--mw-white)); }

/* ---------- Meet the team ---------- */

.team-index > .section__inner { padding-top: var(--space-3); padding-bottom: 0; }

.team-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(200px, 1fr));
  gap: var(--gutter);
  align-items: stretch;
  margin-bottom: var(--space-3);
}

.team-card__photo { display: block; }
.team-card__photo img { aspect-ratio: var(--card-ratio); object-fit: cover; width: 100%; }
.team-card__name { margin: 10px 0 4px; }
.team-card__name a { color: inherit; }
.team-card__quals { margin: 0; }
.team-card__position { font-weight: var(--fw-semibold); margin: 0; }

.founder__row {
  display: flex;
  flex-direction: row;
  gap: var(--gutter);
  width: 100%;
  padding-top: 20px;
  border-top: 1px solid var(--mw-dark-blue);
  text-align: left;
}

/* Same reason as .team-intro__media above. */
.founder__media { flex: 0 0 32%; min-width: 0; }
.founder__media img { aspect-ratio: var(--card-ratio); object-fit: cover; width: 100%; }
.founder__copy { flex-grow: 1; }
.founder__name { margin-bottom: 0.2em; }
.founder__role { font-weight: var(--fw-semibold); }

.team-intro > .section__inner { padding-bottom: 0; }

/*
 * The original sized this band with a very large bottom padding rather than a
 * height; reproduced so the crop matches at every breakpoint.
 */
.team-photo {
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
  padding-top: var(--space-3);
  padding-bottom: 974px;
}

/* ---------- Social (link in bio) ---------- */

/*
 * A plain dark ground. It used to be a photograph under an 85% wash of the
 * dark blue, which is most of the way to a flat colour anyway, and a
 * link-in-bio page is better off with nothing competing with the card.
 */
.social-page {
  min-height: 100vh;
  background-color: var(--mw-dark-blue);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--section-pad-y) var(--section-pad-x);
}

/*
 * The consent banner is fixed to the foot of the viewport and lands on the
 * card: one link covered at 1440, three on a phone. With no footer the page is
 * exactly one screen, so there is nothing to scroll and those links cannot be
 * reached until the banner is answered. While it is showing — the plugin
 * toggles the hidden attribute rather than removing the element — the page
 * carries enough room below the card to scroll clear of it.
 */
body:has([data-vul-banner]:not([hidden])) .social-page {
  padding-bottom: calc(var(--section-pad-y) + 340px);
}

.social-card {
  width: 60%;
  background-color: var(--mw-white);
  padding: 20px;
  border-radius: 16px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* The mark is landscape now, not a 100px circle; height follows the width. */
.social-card__logo { width: 140px; height: auto; }
.social-card__title { margin-top: 10px; }
.social-card__intro { text-align: center; }

.social-links {
  list-style: none;
  margin: 20px 0 0;
  padding: 0;
  width: 100%;
}

.social-links__item { margin-bottom: 8px; }

.social-links__link {
  display: block;
  width: 100%;
  border: 1px solid var(--mw-blue);
  border-radius: 8px;
  padding: 8px;
  text-align: center;
  color: var(--mw-dark-blue);
  transition: background-color var(--dur-fast) var(--ease);
}

.social-card__footer {
  width: 100%;
  background-color: var(--mw-blue);
  padding: 20px;
  border-radius: 8px;
  text-align: center;
  text-transform: uppercase;
  font-size: var(--fs-small);
  margin-top: 8px;
}

.social-card__footer p { margin: 0; }

/* ---------- Contact ---------- */

.contact__cols {
  display: flex;
  flex-direction: row;
  gap: var(--gutter);
  align-items: flex-start;
}

.contact__details { width: 50%; padding-top: 0; }
.contact__form { width: 50%; }

.contact__label {
  color: var(--mw-blue);
  font-weight: var(--fw-semibold);
  margin-bottom: 0.2em;
}

.form-notice {
  border-left: 1px solid var(--mw-blue);
  background: var(--mw-blue-10);
  padding: 12px 16px;
}

/* ---------- Split hero (projects + services hub) ---------- */

.split-hero {
  display: grid;
  grid-template-columns: repeat(2, minmax(200px, 1fr));
  column-gap: 0;
  row-gap: var(--gutter);
  align-items: stretch;
  text-align: left;
}

/*
 * The panel runs full-bleed to the left edge, but its copy aligns to the page
 * container. That falls out of the geometry rather than needing a second
 * container: the panel is half the viewport, and the copy is pushed off its
 * right edge by 120 + 520 = 640 — exactly half the 1280 container — so the
 * copy's left edge tracks the container edge at any width above it.
 *
 * It only works in a column flex. In a row, align-items pushes the copy to the
 * bottom instead of the right and it falls back to the viewport edge.
 */
.split-hero__panel {
  background-color: var(--mw-dark-blue);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-end;
  padding-bottom: calc(var(--unit) * 6);
}

.split-hero__copy {
  max-width: 520px;
  margin-top: 230px;
  margin-right: 120px;
  padding-left: 20px;
}

.split-hero__title { color: var(--mw-blue); }
.split-hero__copy .entry-content { color: var(--mw-white); }
.split-hero__cta { color: var(--mw-white); margin-top: 20px; }

.split-hero__media {
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
  display: flex;
  justify-content: flex-end;
  flex-direction: column;
}

.split-hero__media--bottom { background-position: 50% 100%; }

.split-hero__fade {
  display: block;
  width: 100%;
  height: 100px;
  background-image: linear-gradient(rgba(56, 56, 70, 0), var(--mw-dark-blue));
}

/* ---------- Services hub ---------- */

.services-strap > .section__inner { padding-block: 0; }
.services-strap__inner { padding-top: var(--space-2); margin-bottom: 0; }

/*
 * The original sized this band with padding rather than a height, and pinned
 * the video with background-attachment: fixed.
 */
.video-band {
  position: relative;
  overflow: hidden;
  padding-top: 301px;
  padding-bottom: 394px;
  background-color: var(--mw-dark-blue);
}

.video-band__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.video-band__overlay { position: absolute; inset: 0; }

/* ---------- Projects index ---------- */

.projects-recent > .section__inner { padding-top: var(--space-1); }
.card-grid--raised { margin-top: calc(var(--space-3) * -1); position: relative; z-index: 2; }
.card-grid--all { row-gap: var(--space-2); margin-top: var(--space-1); }

/*
 * Projects index.
 *
 * The index is a tool as much as a page, so the filter gets room to be one:
 * the heading, the control, and the grid each sit a clear interval apart
 * rather than stacking up against each other.
 */
.projects-all > .section__inner { padding-top: var(--space-3); }

.projects-all__label {
  font-size: var(--fs-h1);
  font-weight: var(--fw-bold);
  margin-bottom: var(--space-1);
}

/*
 * The filter.
 *
 * No panel and no ground of its own — the grey it used to sit on appeared
 * nowhere else on the site. It is a row of controls on the page, separated
 * from the grid by a hairline in the blue the rest of the site rules with.
 */
.project-filter {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-m) var(--gutter);
  margin-bottom: var(--space-2);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--mw-blue-20);
}

.project-filter__search { position: relative; display: flex; }

.project-filter__search input {
  font: inherit;
  font-size: var(--fs-small);
  width: 220px;
  max-width: 100%;
  padding: 7px var(--gap-m);
  border: 1px solid var(--mw-grey-5);
  border-radius: var(--radius-button);
  background-color: transparent;
  transition: border-color var(--dur-fast) var(--ease);
}

.project-filter__search input:focus-visible {
  border-color: var(--mw-blue);
  outline: 2px solid var(--mw-blue-20);
  outline-offset: 1px;
}

.project-filter__tags {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--gap-s);
  margin: 0;
  padding: 0;
  border: 0;
}

/*
 * A tag is a chip. The checkbox itself is moved out of sight rather than
 * removed, so the label is still a real control and the keyboard behaviour
 * is the browser's — the chip is only what the state looks like.
 */
.project-filter__tag {
  display: inline-flex;
  align-items: center;
  /* The visually-hidden checkbox is absolute; keep it scoped to this chip. */
  position: relative;
  padding: 6px var(--gap-m);
  border: 1px solid var(--mw-grey-5);
  border-radius: var(--radius-button);
  color: var(--mw-dark-blue);
  font-size: var(--fs-small);
  line-height: var(--lh-heading);
  cursor: pointer;
  user-select: none;
  transition:
    background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease);
}

.project-filter__tag input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.project-filter__tag:has(input:checked) {
  background-color: var(--mw-blue);
  border-color: var(--mw-blue);
  color: var(--mw-white);
}

.project-filter__tag:has(input:focus-visible) {
  outline: 2px solid var(--mw-blue-20);
  outline-offset: 2px;
}

/* The count and its reset sit together, pushed to the end of the row. */
.project-filter__status {
  display: flex;
  align-items: center;
  gap: var(--gap-m);
  margin-left: auto;
}

.project-filter__count {
  font-size: var(--fs-small);
  color: var(--mw-grey-9);
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.project-filter__clear {
  appearance: none;
  background: none;
  border: 0;
  color: var(--mw-blue);
  font: inherit;
  font-size: var(--fs-small);
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
}

.project-filter__clear[hidden] { display: none; }

.project-filter__empty { margin-top: var(--space-2); }

/*
 * Filtering.
 *
 * A card fades and settles rather than vanishing. It is taken out of layout
 * only after it has faded, so the grid reflows behind a card that has already
 * gone rather than snapping under one that is still there.
 */
.card-grid--all .card {
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

.card-grid--all .card.is-out {
  opacity: 0;
  transform: scale(0.98);
  pointer-events: none;
}

/* ---------- Service page shell ---------- */

.service-hero {
  height: 90vh;
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
}

/*
 * The video covers the still rather than replacing it, so the image is what
 * shows before it plays and if it never does.
 *
 * Nothing else in the hero needs lifting over it: the mark and the scroll cue
 * position themselves and carry their own z-index, both above this one. A
 * blanket `.service-hero > :not(.service-hero__video)` rule to do the lifting
 * outranks `.scroll-cue` on specificity and resets it to `position: relative`,
 * which drops the cue out of the bottom of the hero and into the flow at the
 * top of it.
 */
/* An accreditation mark, centred on the hero as the original had it. */
.service-hero__mark {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: clamp(140px, 14vw, 200px);
  height: auto;
  z-index: 1;
}

.service-hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  pointer-events: none;
}


.service-body { background-color: var(--mw-very-dark); }

/*
 * Connected project card.
 *
 * A near-opaque white plate on the photograph carrying the project's own
 * thumbnail, so it reads as a card rather than text floating on an image.
 * The wrapper does the containing: the plate ranges off the same left edge
 * as every other element on the page instead of centring in the band.
 */
.project-highlight {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--section-pad-x);
  padding-bottom: var(--gutter);
}

.project-highlight__link {
  display: inline-flex;
  flex-direction: row;
  align-items: stretch;
  gap: var(--gap-m);
  padding: 10px;
  background-color: rgba(255, 255, 255, 0.9);
  color: var(--mw-very-dark);
  text-align: left;
}

.project-highlight__media {
  display: block;
  flex-shrink: 0;
  width: 100px;
  height: 100px;
  background-size: cover;
  background-position: 50% 50%;
  background-repeat: no-repeat;
}

.project-highlight__text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 130px;
  padding-right: 10px;
}

.project-highlight__label {
  display: block;
  font-size: var(--fs-label);
  color: var(--mw-very-dark);
}

.project-highlight__title {
  display: block;
  font-size: var(--fs-body);
  font-weight: var(--fw-bold);
  line-height: 1.2;
  color: var(--mw-very-dark);
}
.project-highlight__link:focus-visible .project-highlight__title { color: var(--mw-blue); }


.block--full-image {
  display: flex;
  flex-direction: row;
  align-items: flex-end;
  justify-content: center;
}

.block--full-image--short { height: 450px; }

.project-highlight--centre { text-align: center; }
.project-highlight--left { text-align: left; }

/*
 * Connected team member.
 *
 * The portrait is a fixed 200px circle: the source images are ordinary
 * landscape photographs, so the frame has to do the cropping.
 */
/*
 * The people connected to a service. The faces component does the portraits;
 * what is left here is the band they sit in.
 */
.team-feature {
  background-color: var(--mw-very-dark);
  color: var(--mw-white);
  --block-muted: var(--mw-grey-1);
}

.team-feature > .section__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.team-feature__intro {
  color: var(--mw-blue);
  font-size: var(--fs-h3);
  text-align: center;
  margin: 0 0 var(--space-1);
}

.ask-experts { background-color: var(--mw-very-dark); }
.ask-experts > .section__inner { padding-top: var(--space-1); }

.ask-experts__panel {
  width: 100%;
  background-color: var(--mw-dark-blue);
  padding: var(--space-2);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.ask-experts__title { color: var(--mw-white); }
.ask-experts__sub { color: var(--mw-blue); margin-bottom: 20px; }

.ask-experts__link {
  color: var(--mw-blue);
  background-color: var(--mw-white);
  border: 1px solid var(--mw-blue);
  padding: 10px 20px;
  gap: var(--gap-s);
}

/* ---------- Ask the Experts: the discovery-call landing page ---------- */

/*
 * The offer and the form share the first screen. Everything about this page is
 * arranged around that: the photograph is a ground rather than a subject, the
 * scrim exists to make type legible over it, and the form is the only white
 * thing on the screen so it reads as the thing to do.
 */
.lead-hero {
  position: relative;
  background-color: var(--mw-very-dark);
  background-size: cover;
  background-position: 50% 40%;
  background-repeat: no-repeat;
  color: var(--mw-white);
  padding-top: var(--space-4);
}

.lead-hero__scrim {
  position: absolute;
  inset: 0;
  background-image: linear-gradient(
    100deg,
    rgba(42, 42, 53, 0.94) 0%,
    rgba(42, 42, 53, 0.88) 46%,
    rgba(42, 42, 53, 0.72) 100%
  );
}

.lead-hero > .section__inner { position: relative; }
.lead-hero__grid { align-items: start; }
.lead-hero__copy { display: flex; flex-direction: column; gap: var(--gap-m); }

.lead-hero__eyebrow {
  margin: 0;
  color: var(--mw-blue);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.lead-hero__title { margin: 0; color: var(--mw-white); text-wrap: balance; }

.lead-hero__lede {
  margin: 0;
  font-size: var(--fs-h3);
  line-height: 1.45;
  color: var(--mw-grey-1);
}

.lead-hero__points { margin-top: var(--gap-s); }

.lead-hero__points-head {
  margin: 0 0 var(--gap-s);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--mw-blue);
}

/*
 * Hairline rows rather than bullets — the same device the route cards use, so
 * a list of facts looks the same wherever it appears on the site.
 */
.lead-points {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  border-top: 1px solid var(--mw-blue-20);
  max-width: 52ch;
}

.lead-points li {
  padding: var(--gap-s) 0;
  border-bottom: 1px solid var(--mw-blue-20);
  color: var(--mw-grey-1);
}

/* The form: the one white plate on a dark screen. */
.lead-form {
  background-color: var(--mw-white);
  color: var(--mw-dark-blue);
  padding: var(--space-1);
  border-radius: var(--radius-button);
}

.lead-form__title {
  margin: 0 0 var(--gap-m);
  font-size: var(--fs-h3);
  line-height: var(--lh-heading);
  color: var(--mw-dark-blue);
}

.lead-form__note {
  margin: var(--gap-m) 0 0;
  font-size: var(--fs-small);
  color: var(--mw-grey-9);
}

/*
 * The form sits in five columns, not twelve, so the half-width fields it is
 * configured with leave 218px inputs side by side. Everything runs full width
 * in here — the name field keeps its own first/last split, which is the one
 * place two across still reads.
 */
.lead-form .gform_wrapper.gravity-theme .gform_fields .gfield { grid-column: 1 / -1; }

.lead-form .gform_wrapper input[type="text"],
.lead-form .gform_wrapper input[type="email"],
.lead-form .gform_wrapper input[type="tel"],
.lead-form .gform_wrapper textarea { width: 100%; }

.lead-form .gform_wrapper .ginput_complex { display: flex; gap: var(--gap-s); }
.lead-form .gform_wrapper .ginput_complex > span { flex: 1 1 0; }

.lead-form .gform_wrapper .gform_footer { margin-bottom: 0; }

/*
 * Faces.
 *
 * A small practice's advantage is that there are faces. Used on the discovery
 * call page for the whole team and on a service page for whoever leads it —
 * one component, so the hover and the crop cannot drift between them.
 *
 * A row centres and sizes itself from --face-size; the grid distributes across
 * the measure. One face on a service page gets the bigger frame, because then
 * it is a portrait rather than one of a set.
 */
.faces {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-1) var(--gutter);
}

.faces--grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--gutter);
}

.face { width: var(--face-size, 150px); }
.faces--grid .face { width: auto; }

.face a {
  display: grid;
  gap: var(--gap-xs);
  justify-items: center;
  text-align: center;
  color: inherit;
}

.face__photo {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: 50%;
  margin-bottom: var(--gap-xs);
}

.face__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--dur-slow) var(--ease-out);
}

.face a:focus-visible .face__photo img { transform: scale(var(--card-zoom)); }

@media (hover: hover) and (pointer: fine) {
  .face a:hover .face__photo img { transform: scale(var(--card-zoom)); }
}

.face__name { font-weight: var(--fw-semibold); }
.face a:focus-visible .face__name { color: var(--mw-blue); }


.face__role {
  font-size: var(--fs-small);
  color: var(--block-muted, var(--mw-grey-9));
}

/*
 * The About section: photograph beside the copy. The picture is a fixed half
 * so a large upload cannot argue with it — the same trap that blew the team
 * page's media column out to three thousand pixels.
 */
.lead-about__media img {
  width: 100%;
  height: auto;
  display: block;
  aspect-ratio: var(--card-ratio);
  object-fit: cover;
}

.lead-proof__back { margin: var(--space-1) 0 0; }

@media (max-width: 991px) {
  .lead-hero__copy, .lead-form { grid-column: span 12; }
  .faces--grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 479px) {
  .faces--grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---------- Site CTA band ---------- */

.cta-band {
  background-color: var(--mw-blue-15);
  width: 100%;
  padding: var(--space-2) var(--gutter);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.cta-band__title { text-align: center; margin-bottom: 0.3em; }
.cta-band__sub { margin-bottom: 0.8em; }

/* ---------- Post closing CTA ---------- */

.post-cta {
  background-color: var(--mw-blue-20);
  padding: 20px;
  margin: 1.5rem 0;
  text-align: center;
}

.post-cta__title { text-align: center; margin-bottom: 0.3em; }

.post-cta__sub {
  color: var(--mw-blue);
  text-align: center;
  margin-bottom: 0.8em;
}

.post-cta__link {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-xs);
  font-weight: var(--fw-semibold);
}

.post-cta__arrow { width: 20px; height: 20px; }

/* ---------- Answer-engine blocks ---------- */
/* Ported from the original build's code blocks; rules unchanged. */

/*
 * Answer-engine blocks.
 *
 * These arrived from the original build carrying their own palette — five
 * hardcoded hexes that appeared nowhere else on the site, which is why they
 * read as imported rather than designed. They take the site's tokens now.
 *
 * The FAQ is a hairline above each question, the same device the grids and the
 * route cards use. A `<details>` keeps the keyboard behaviour and the
 * open/closed state for free; the chevron only says which way it is.
 */
.aeo-tldr:first-child { margin-top: 0; }

.aeo-tldr {
  margin: var(--space-2) 0;
  padding-top: var(--gap-s);
  border-top: 2px solid var(--mw-blue);
  max-width: 70ch;
}

.aeo-tldr__label {
  margin: 0 0 var(--gap-xs);
  color: var(--mw-blue);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.aeo-tldr__body { font-size: var(--fs-h3); line-height: 1.45; }
.aeo-tldr__body > :first-child { margin-top: 0; }
.aeo-tldr__body > :last-child { margin-bottom: 0; }

.aeo-faq { margin: var(--space-3) 0 0; }

.aeo-faq__title {
  margin: 0 0 var(--space-1);
  font-size: var(--fs-h1);
  line-height: var(--lh-heading);
}

.aeo-faq__list { display: grid; }

.aeo-faq__item { border-top: 1px solid var(--mw-blue); }
.aeo-faq__item:last-child { border-bottom: 1px solid var(--mw-blue); }

.aeo-faq__q {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gutter);
  padding: var(--gap-m) 0;
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-heading);
  color: var(--block-fg, var(--mw-dark-blue));
  cursor: pointer;
  list-style: none;
  transition: color var(--dur-fast) var(--ease);
}

.aeo-faq__q::-webkit-details-marker { display: none; }

.aeo-faq__mark {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: var(--mw-blue);
  transition: transform var(--dur) var(--ease-in-out);
}

.aeo-faq__item[open] .aeo-faq__mark { transform: rotate(180deg); }

.aeo-faq__a {
  padding-bottom: var(--gap-m);
  max-width: 70ch;
  color: var(--block-muted, var(--mw-very-dark));
}

.aeo-faq__a > :first-child { margin-top: 0; }
.aeo-faq__a > :last-child { margin-bottom: 0; }

/* On a dark ground the rules drop to the tint, as everywhere else. */
.section--dark .aeo-faq__item,
.section--dark .aeo-faq__item:last-child,
.section--on-dark .aeo-faq__item,
.section--on-dark .aeo-faq__item:last-child { border-color: var(--mw-blue-20); }

/* ---------- Responsive ---------- */

@media (max-width: 1280px) {
  .team-photo { padding-bottom: 618px; }
  .split-hero__copy { margin-right: var(--space-2); }
}

@media (max-width: 991px) {
  /* Identity takes the full width, the two menus share the row beneath it. */
  .site-footer__identity { grid-column: span 12; }
  .site-footer__block { grid-column: span 6; }

  .project__spacer { display: none; }
  .project__wide { height: 500px; }
  .project__award { width: 100px; }

  .home-featured { flex-direction: column; }
  .home-featured--overlap { margin-top: calc(var(--space-3) * -1); }
  .home-featured__media { width: 100%; height: 350px; }
  /*
   * Stacked, the panel is full width and its dark ground reaches the edge of
   * the container, so it has to carry its own inset — there is nothing else
   * holding the copy off that edge. It had none at all here, and a flat 20px
   * below 767, which was a cliff either side of the boundary.
   *
   * One expression down the whole range instead: never tighter than the
   * page's own gutter, never looser than a standard block inset.
   */
  .home-featured__panel {
    width: 100%;
    min-height: 200px;
    padding: var(--space-2) clamp(var(--section-pad-x), 5vw, var(--space-2));
  }

  .home-services-intro > .section__inner { flex-direction: column-reverse; }
  .home-services-intro__copy { width: 100%; }

  .card-grid--services,
  .team-grid { grid-template-columns: repeat(2, minmax(200px, 1fr)); }

  /* Four across becomes two; three stays three until the next breakpoint. */
  .grid--4 > * { grid-column: span 6; }
  .step { grid-column: span 6; }
  .grid__aside, .grid__main { grid-column: span 12; }

  .media-split { grid-template-columns: 1fr; }

  .post-single__rail { position: static; }

  /* Three routes in two columns strands one on its own row. */
  .card-grid--routes { column-gap: var(--gutter); }

  .contact__cols { flex-direction: column; }
  .social-card { width: 100%; }
  .contact__details,
  .contact__form { width: 100%; }

  .team-photo { padding-bottom: 426px; }

  .home-featured-label__fade { height: 140px; }
  .news-item { flex-direction: column; }
  .news-item__media img { width: 100%; }

  .block__intro-grid,
  .block__two-col,
  .team-grid { grid-template-columns: repeat(1, minmax(200px, 1fr)); }

  /*
   * `.points` is a `.grid`, so it stacks by span and not by redeclaring its
   * tracks. It used to be in the group above, which left each item spanning
   * twelve tracks of a one-column grid — eleven phantom gutters, so every
   * item measured 200 + 11x24 = 464px and ran off the side of every phone.
   */
  .points > * { grid-column: span 12; }

  .founder__row,
  .team-intro__row { flex-direction: column; }
  .team-photo { padding-bottom: 244px; }
  .split-hero { grid-template-columns: 1fr; row-gap: 0; }
  .split-hero__panel { padding-bottom: var(--space-2); align-items: flex-start; }
  .split-hero__copy { margin-top: var(--space-4); margin-right: 20px; }
  .split-hero__media { height: 600px; }
  .block__intro-grid > :last-child { grid-column: auto; }
}

@media (max-width: 767px) {
  :root { --section-pad-y: 50px; }

  /*
   * The image band keeps a landscape shape on a phone.
   *
   * It is 800px tall at every width, so at 375 it became a portrait box holding
   * landscape photographs and `cover` threw away about three quarters of them.
   * Shaped to the viewport instead, the same picture loses about a quarter.
   */
  .block--full-image,
  .block--full-image--short {
    height: auto;
    aspect-ratio: 4 / 3;
  }

  .header-spacer { display: none; }
  .image-band { height: 300px; }

  /*
   * The hero photograph scales to the width of the phone instead of being
   * cropped to a central slice. `cover` in a 375x600 box rendered the
   * 2560x1707 original at 900x600 and put only 42% of its width on screen —
   * the building was off both edges. Scaled to width it is whole, and the
   * padding reserves its own 1707/2560 height so the plate flows beneath the
   * picture rather than over it.
   */
  .home-hero {
    height: auto;
    background-size: 100% auto;
    background-position: 50% 0;
    padding-top: 66.68%;
  }

  /* Compact enough that the plate does not outweigh the picture above it. */
  .home-hero__name,
  .home-hero__title { font-size: var(--fs-h1); }
  .home-hero__sub { font-size: var(--fs-body); }

  /* Below 767 the wordmark gives way to the icon mark. */
  .site-header__wordmark { display: none; }
  .site-header__mark { display: block; padding-block: 20px; }
  .site-footer__block { grid-column: span 12; }
  .site-footer__menu--split { grid-template-columns: 1fr; }
  .site-footer__foot { justify-content: flex-start; }

  .gallery { column-count: 1; }

  .card-grid,
  .team-member__grid,
  .home-news__grid,
  .card-grid--services,
  .card-grid--routes,
  .project__grid { grid-template-columns: repeat(1, minmax(200px, 1fr)); column-gap: var(--gutter); }

  /* Everything is one column below this width. */
  .grid--2 > *, .grid--3 > *, .grid--4 > * { grid-column: span 12; }
  .step { grid-column: span 12; }
  .span-3, .span-4, .span-5, .span-6, .span-7, .span-8 { grid-column: span 12; }
  .media-split__copy { padding: var(--space-2) var(--section-pad-x); }

  .post-single__rail { padding-bottom: var(--space-1); }

  .article-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--space-1) var(--space-2);
  }

  /* The rule column stacks above the copy rather than shrinking. */

  .home-featured--overlap { margin-top: calc(var(--space-2) * -1); }
  .home-featured__media { height: 300px; }
  .home-featured-label__fade { height: 100px; }
  .news-item { flex-direction: column-reverse; }
  .project__credit { grid-column: auto; }
  .project__wide { height: 300px; }

  /* The badge moves out of the hero and overlaps the copy block instead. */
  .project__hero .project__award { display: none; }

  .project__award-mobile {
    display: flex;
    margin-top: calc(var(--space-4) * -1);
    position: relative;
    z-index: 10;
  }

  .project__award-mobile img { width: 200px; }
}

@media (max-width: 479px) {

  .project__wide { height: 200px; }

  .site-header__mark { width: 50px; }
  .offcanvas__logo img { width: 50px; }

  .home-featured--overlap { margin-top: -50px; }
  .home-featured__media { height: 250px; }
  .team-photo { padding-bottom: 210px; }
}

/*
 * Arrival.
 *
 * One movement, used once per thing: a short rise out of transparency as it
 * comes into view. Nothing is hidden by the stylesheet — the class that hides
 * an element is added by script, and only to elements below the first screen,
 * so the page at rest is fully visible and a reader with no JavaScript never
 * loses a word.
 *
 * Grid children take a small stagger so a row reads left to right rather than
 * arriving as a slab. It caps at four, past which a stagger stops reading as
 * sequence and starts reading as lag.
 */
.reveal {
  opacity: 0;
  transform: translateY(var(--rise));
  transition:
    opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}

.reveal.is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/*
 * Scroll cue.
 *
 * The original's disc and bounce, reproduced: 40px, blue, a dark chevron, and
 * a two-second loop travelling 20px then 10px. The one change is that it stops
 * once the reader scrolls — it exists to say "there is more below", and a cue
 * that keeps insisting after the point is taken is just movement.
 */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: var(--space-2);
  z-index: 2;
  width: 40px;
  height: 40px;
  margin-left: -20px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 50%;
  background-color: var(--mw-blue);
  color: var(--mw-very-dark);
  cursor: pointer;
  animation: mw-cue-bounce 2s var(--ease) infinite;
  transition: transform var(--dur-fast) var(--ease), opacity var(--dur) var(--ease);
}

.scroll-cue__chevron { width: 26px; height: 26px; }

.scroll-cue:focus-visible { transform: scale(1.05); animation-play-state: paused; }
.scroll-cue:active { transform: scale(0.97); }

@media (hover: hover) and (pointer: fine) {
  .scroll-cue:hover { transform: scale(1.05); animation-play-state: paused; }
}

/* Its job is done; it leaves rather than lingering. */
.scroll-cue.is-done {
  opacity: 0;
  pointer-events: none;
  animation-play-state: paused;
}

@keyframes mw-cue-bounce {
  0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
  40% { transform: translateY(-20px); }
  60% { transform: translateY(-10px); }
}

.home-hero,
.service-hero { position: relative; }

@media print {
  .reveal,
  .reveal.is-in { opacity: 1 !important; transform: none !important; }
}

/*
 * Reduced motion.
 *
 * Gentler, not nothing. Colour and opacity still change, because those carry
 * meaning — a button still answers a pointer, a panel still fades in. What
 * goes is movement: nothing travels, scales or rotates, and nothing loops.
 */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition-property: opacity, color, background-color, border-color !important;
    transition-duration: var(--dur-fast) !important;
    scroll-behavior: auto !important;
  }

  /* Anything held off its resting place by a transform comes home. */
  .reveal,
  .reveal.is-in,
  .card__link:hover .card__image,
  .card__link:focus-visible .card__image,
  .face a:hover .face__photo img,
  .scroll-cue,
  .scroll-cue:hover,
  .mega,
  .mega__routes,
  .mega__all,
  .card-grid--all .card.is-out,
  .step,
  .button:active {
    transform: none !important;
  }

  .reveal,
  .reveal.is-in { opacity: 1 !important; }

  /* The drawer still opens; it just does not slide. */
  .offcanvas { transition: none !important; }
}

/*
 * Hover states, for devices that hover.
 *
 * A touch screen has no way to leave a hover state, so an ungated :hover can
 * latch after a tap and stay. Behind this query a phone never enters the
 * state and a mouse is unaffected.
 *
 * This was first applied while chasing a double-tap fault. It was not the
 * cause — that was the off-canvas panel staying pointer-active while shut —
 * and the gating is kept on its own merits.
 *
 * Only the :hover halves moved. Where a rule also matched :focus-visible or
 * .is-current, those selectors stayed where they were — keyboard focus and
 * the current-page mark must work on a touch device too.
 */
@media (hover: hover) and (pointer: fine) {
  a:hover { color: rgba(113, 174, 223, 0.85); }
  .nav__link:hover { color: var(--mw-blue); border-bottom-color: var(--mw-blue); }
  .mega__route:hover { color: var(--mw-white); }
  .mega__route:hover .mega__route-title { color: var(--mw-blue); }
  .mega__list a:hover { color: var(--mw-blue); }
  .offcanvas__close:hover { color: var(--mw-blue); }
  .sheet__routes a:hover { color: var(--mw-blue); }
  .sheet__list a:hover { color: var(--mw-blue); }
  .sheet__meta a:hover { color: var(--mw-blue); }
  .site-footer a:hover { color: var(--mw-blue); }
  .socials a:hover { color: var(--mw-blue); border-color: var(--mw-blue); }
  .site-footer__legal a:hover { color: var(--mw-blue); }
  .article-meta__person:hover .article-meta__name { color: var(--mw-blue); }
  .card__link:hover .card__title { color: var(--mw-blue); }
  .route-card__title a:hover,
  .route-card__point > a:hover { color: var(--mw-blue); }
  .service-card__link:hover .service-card__title { color: var(--mw-blue); }
  .news-item__title a:hover { color: var(--mw-blue); }
  .button:hover,
    .gform_wrapper .gform_footer input[type="submit"]:hover,
    .gform_wrapper .gform_footer button:hover {
    background-color: var(--mw-blue);
    border-color: var(--mw-blue);
    color: var(--mw-white);
  }
  .button--solid:hover {
    background-color: var(--mw-white);
    color: var(--mw-blue);
  }
  .button--ghost:hover { background-color: var(--mw-blue); color: var(--mw-white); }
  .team-card__name a:hover { color: var(--mw-blue); }
  .social-links__link:hover { background-color: var(--mw-blue-15); color: var(--mw-dark-blue); }
  .split-hero__cta:hover { color: var(--mw-blue); }
  .project-filter__tag:hover { border-color: var(--mw-blue); }
  .pagination a.page-numbers:hover { border-color: var(--mw-blue); color: var(--mw-blue); }
  .project-highlight__link:hover .project-highlight__title { color: var(--mw-blue); }
  .face a:hover .face__name { color: var(--mw-blue); }
  .aeo-faq__q:hover { color: var(--mw-blue); }
}
