/* --- Fonts ---------------------------------------------------
   Self-hosted woff2, Latin subset, five faces and no more — see
   performance.md. All three families are SIL OFL; the licence file
   ships alongside in assets/fonts/. No font CDN, no preconnect:
   there is nothing to connect to. */
@font-face {
  font-family: "Jost"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("../fonts/jost-400.1d41ff98.woff2") format("woff2");
}
@font-face {
  font-family: "Jost"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("../fonts/jost-700.eb3fb4c3.woff2") format("woff2");
}
@font-face {
  font-family: "Barlow Condensed"; font-style: italic; font-weight: 700; font-display: swap;
  src: url("../fonts/barlow-condensed-700i.e15f66d2.woff2") format("woff2");
}
@font-face {
  font-family: "Barlow Condensed"; font-style: italic; font-weight: 800; font-display: swap;
  src: url("../fonts/barlow-condensed-800i.03d2a3e8.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("../fonts/jetbrains-mono-400.4eab87b2.woff2") format("woff2");
}

/* ============================================================
   MAC Scaffolding — design system
   Implements element-system.md (1b, 1f, 1i, 1j, 1k, 1l, 1n, 1o)
   Motif: -18deg shear. Square corners. British spelling.
   ============================================================ */

/* --- Tokens -------------------------------------------------
   #53a4db and #0b0d10 are given by the brand. The rest of the
   ramp is derived here: every neutral sits on the same ~213deg
   hue as the blue, so the greys read as part of the system
   rather than as generic greys. Contrast values noted are
   measured against #fff or --ink-900 as marked.
   ----------------------------------------------------------- */
:root {
  --mac-blue:      #53a4db;  /* brand. 7.14:1 with ink-900 on top   */
  --mac-blue-600:  #3d8fc9;  /* hover fill                          */
  --mac-blue-700:  #2f74a6;  /* eyebrow + text link on white 5.04:1 */

  --ink-050: #f4f6f8;
  --ink-100: #e5e9ee;   /* hairlines                                */
  --ink-200: #ccd3db;   /* borders, stat separators                 */
  --ink-300: #a8b2bd;   /* body copy on ink-900        9.05:1       */
  /* The counterpart to --ink-400 on ink. --ink-400 measures 4.16:1
     against ink-900 and fails, so micro type on dark bands needs its
     own value; this is the same ~213deg hue, 5.41:1 on ink-900. It
     fails on white (3.60:1) exactly as ink-400 fails on ink — the
     pairing stays fixed per background. */
  --ink-350: #7e8894;   /* micro type on ink-900       5.41:1       */
  --ink-400: #6b7581;   /* micro type on white         4.68:1       */
  --ink-500: #4d5761;   /* secondary body on white     7.36:1       */
  --ink-600: #39424b;
  --ink-700: #262d34;
  --ink-800: #161b21;
  --ink-900: #0b0d10;   /* brand                                    */

  --bg-muted: var(--ink-050);
  --border:   var(--ink-200);

  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px; --s-5: 24px;
  --s-6: 32px; --s-7: 48px; --s-8: 64px; --s-9: 96px; --s-10: 128px;

  --dur-fast: 140ms;
  --dur-base: 220ms;
  --ease-out: cubic-bezier(.2, .7, .3, 1);
  /* Scroll reveals run on their own, slower curve. Hover and press
     stay on --dur-base: interface feedback has to feel immediate,
     it is only the arriving-into-view motion that wants time. */
  --dur-reveal: 660ms;
  --ease-reveal: cubic-bezier(.16, .68, .32, 1);
  --shadow-2: 0 10px 30px -12px rgba(11, 13, 16, .34);

  --shear: -18deg;
  --unshear: 18deg;

  --wrap: 1200px;
  --gut: clamp(20px, 5vw, 56px);

  --font-display: "Barlow Condensed", "Arial Narrow", system-ui, sans-serif;
  --font-body:    "Jost", "Century Gothic", "Avenir Next", system-ui,
                  -apple-system, "Segoe UI", sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* --- Base --------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { border-radius: 0; }

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

body {
  margin: 0;
  background: #fff;
  color: var(--ink-900);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.6;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

/* width/height attributes are present on images to reserve space and
   avoid layout shift; height:auto keeps the aspect ratio intact. */
img { max-width: 100%; display: block; height: auto; }
/* Production images ship as <picture> AVIF + JPEG. display:contents keeps
   the wrapper out of layout, so height/flex rules land on the img itself. */
picture { display: contents; }
a { color: inherit; }

::selection { background: var(--mac-blue); color: var(--ink-900); }

:focus-visible {
  outline: 3px solid var(--mac-blue);
  outline-offset: 3px;
}
.band--dark :focus-visible,
.site-foot :focus-visible { outline-color: var(--mac-blue); }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ink-900); color: #fff; padding: 14px 22px;
  font-family: var(--font-display); font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; text-decoration: none;
}
.skip:focus { left: 0; }

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

/* Section rhythm lives on .band only, so nothing else fights it. */
.band { padding-block: clamp(64px, 9vw, 118px); }
.band--tight { padding-block: clamp(44px, 6vw, 76px); }
.band--dark  { background: var(--ink-900); color: #fff; }
.band--muted { background: var(--ink-050); }

/* --- Type --------------------------------------------------- */
.display {
  font-family: var(--font-display);
  font-weight: 800;
  font-style: italic;
  text-transform: uppercase;
  line-height: .92;
  letter-spacing: .002em;
  margin: 0;
}

.eyebrow {
  font-family: var(--font-body);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .14em;
  font-size: 13px;
  color: var(--mac-blue-700);
  margin: 0 0 10px;
}
.band--dark .eyebrow { color: var(--mac-blue); }

.micro {
  font-family: var(--font-body);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .12em;
  font-size: 12px;
  color: var(--ink-400);
}

.mono {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-400);
}

.lede  { font-size: clamp(18px, 1.5vw, 21px); line-height: 1.55; color: var(--ink-600); margin: 0 0 var(--s-5); }
.body  { color: var(--ink-500); margin: 0 0 var(--s-4); }
.body:last-child { margin-bottom: 0; }
.band--dark .lede { color: var(--ink-200); }
.band--dark .body { color: var(--ink-300); }

/* --- Speed-dash mark (from the logo) ------------------------ */
.dashes { display: flex; flex-direction: column; gap: 5px; width: 62px; }
.dashes i { display: block; height: 7px; background: var(--mac-blue); transform: skewX(var(--shear)); }
.dashes i:nth-child(2) { width: 74%; }

/* --- 1f  Section heading ------------------------------------ */
.head-1f .display { font-size: clamp(40px, 6.2vw, 60px); }
.slash-rule { display: flex; gap: 6px; margin-top: var(--s-4); }
.slash-rule span { display: block; height: 8px; transform: skewX(var(--shear)); }
.slash-rule span:first-child { width: 64px; background: var(--ink-900); }
.slash-rule span:last-child  { width: 20px; background: var(--mac-blue); }
.band--dark .slash-rule span:first-child { background: #fff; }

/* --- 1i  Buttons -------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: 48px; padding: 0 26px;
  font-family: var(--font-display); font-weight: 700; font-size: 17px;
  text-transform: uppercase; letter-spacing: .05em; text-decoration: none;
  border: 0; cursor: pointer; white-space: nowrap;
  transition: background var(--dur-base) var(--ease-out),
              color var(--dur-base) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}
/* 1i.1 primary — ink label on brand blue is 7.14:1.
   White on #53a4db is 2.73:1 and fails AA, so the label is ink. */
.btn--primary { background: var(--mac-blue); color: var(--ink-900); }
.btn--primary:hover { background: var(--mac-blue-600); }
.btn--primary:active { background: var(--mac-blue-600); transform: scale(.98); }

/* 1i.2 ghost */
.btn--ghost { background: transparent; border: 2px solid var(--ink-900); color: var(--ink-900); }
.btn--ghost:hover { background: var(--bg-muted); }
.btn--ghost:active { transform: scale(.98); }
.btn--ghost-light { background: transparent; border: 2px solid #fff; color: #fff; }
.btn--ghost-light:hover { background: rgba(255,255,255,.1); }

/* 1i.3 sheared phone CTA retired — the phone is Contact-page-only, so
   this CTA is placed on no page (element-system.md keeps its geometry
   on record in case a future spec update reinstates it). */

/* 1i.4 text link */
.tlink {
  display: inline-block;
  font-family: var(--font-body); font-weight: 700; font-size: 15px;
  text-transform: uppercase; letter-spacing: .08em;
  color: var(--mac-blue-700); text-decoration: none;
  border-bottom: 2px solid var(--mac-blue); padding-bottom: 3px;
  transition: color var(--dur-fast) var(--ease-out);
}
.tlink:hover { color: var(--ink-900); }
/* 44px hit area without moving the underline: the pseudo-element is the
   target, the type is unchanged (CAP-13). */
.tlink { position: relative; }
.tlink::before { content: ""; position: absolute; inset: -12px -8px; }
.band--dark .tlink { color: #fff; }
.band--dark .tlink:hover { color: var(--mac-blue); }

/* --- Header ------------------------------------------------- */
/* In flow, not pinned: the bar scrolls away with the page, so there is
   no scrolled state to blur, shrink or shadow into.

   `relative` rather than static, and the z-index with it: at <=1080px
   the nav panel is absolutely positioned at top:100% and resolves
   against its nearest positioned ancestor. .head-in is an unpositioned
   flex row, so a static header would send the panel out to the initial
   containing block — full document width, offset from the document top
   instead of from the bar. The z-index keeps the open panel over the
   hero beneath it. */
.site-head {
  position: relative; z-index: 90;
  background: #fff;
}
/* 104px at rest, so the wordmark can be the tallest thing in the bar.
   The bar is not merged into the hero — options B–E were costed in
   mockup/header-hero.html and every one of them buys a reversed logo,
   a reversed burger and per-template top clearance. This buys none. */
.head-in { display: flex; align-items: center; gap: var(--s-5); height: 104px; }

/* Vector lockup reconstructed from .input/SVG/Asset 57.svg. The
   light-background variant; the footer carries the reversed one. */
.brand { display: flex; align-items: center; min-height: 44px; text-decoration: none; margin-right: auto; }
/* The lockup is a wide one — 136x46, so nearly 3:1 — which means its
   height reads as width, and 74px flat from 370px up put a 219px
   wordmark across 58% of a 375px viewport. It dominated the phone
   bar and sat heavier than the 13.5px nav on desktop.

   48px at 375 and 62px from 1200 up: 38% of the viewport on a phone
   and 60% of the bar's height on desktop, against 58% and 71%. The
   ramp between them is `41.6px + 1.7vw`, so the two ends are joined
   by one line rather than a breakpoint, and the height is what
   scales — a flex-shrunk <img> with no object-fit squashes rather
   than scales, which is why width is left `auto`.

   The old rule needed a 58px floor to keep the lockup off the
   burger below 370px. At these sizes that pressure is gone: 320px
   now leaves 80px of clear air between the two, so the floor is
   only a sanity stop. */
.brand img { height: clamp(44px, calc(41.6px + 1.7vw), 62px); width: auto; }

.nav { display: flex; align-items: center; gap: clamp(14px, 1.7vw, 26px); }
.nav a {
  font-family: var(--font-body); font-weight: 700; font-size: 13.5px;
  text-transform: uppercase; letter-spacing: .09em;
  color: var(--ink-600); text-decoration: none; padding: 6px 0;
  position: relative; transition: color var(--dur-fast) var(--ease-out);
}
.nav a::after {
  content: ""; position: absolute; left: 0; right: 100%; bottom: 0; height: 3px;
  background: var(--mac-blue); transform: skewX(var(--shear));
  transition: right var(--dur-base) var(--ease-out);
}
.nav a:hover { color: var(--ink-900); }
.nav a:hover::after { right: 0; }
.nav a[aria-current="page"] { color: var(--ink-900); }
.nav a[aria-current="page"]::after { right: 0; }

.nav-toggle {
  display: none; width: 46px; height: 46px; background: var(--ink-900);
  border: 0; cursor: pointer; padding: 0; place-items: center;
  /* The three bars are auto grid rows, and align-content defaults to
     `normal` — which is `stretch` for grid, so the rows would share
     the button's 46px between them and the 3px margins below would
     never govern the gap. Packing them centres the mark instead. */
  align-content: center;
}
.nav-toggle i {
  display: block; width: 20px; height: 3px; background: #fff;
  transform: skewX(var(--shear)); margin: 3px auto;
  transition: transform var(--dur-base) var(--ease-out),
              opacity var(--dur-base) var(--ease-out);
}
/* Burger to close mark. The rotation composes with the shear rather
   than replacing it — dropping skewX would straighten the motif at
   exactly the moment the mark is largest. 9px is the bar pitch
   (3px bar + 3px margin either side), so the outer two meet at the
   centre line the middle bar vacates. */
.nav-toggle[aria-expanded="true"] i:nth-child(1) { transform: translateY(9px) rotate(45deg) skewX(var(--shear)); }
.nav-toggle[aria-expanded="true"] i:nth-child(2) { opacity: 0; transform: skewX(var(--shear)) scaleX(.2); }
.nav-toggle[aria-expanded="true"] i:nth-child(3) { transform: translateY(-9px) rotate(-45deg) skewX(var(--shear)); }

/* --- Hero --------------------------------------------------- */
.hero { position: relative; min-height: min(88svh, 760px); display: flex; align-items: flex-end; overflow: hidden; }

/* Parallax drift. --par is both the travel distance and the extra
   height the media is given above the hero, so the top edge can never
   pull away and expose a gap. 0 by default; only motion-safe users
   get the movement. */
.hero { --par: 0px; }
@media (prefers-reduced-motion: no-preference) {
  .hero { --par: clamp(58px, 8vw, 112px); }
}
.hero__media {
  position: absolute; left: 0; right: 0; bottom: 0;
  top: calc(var(--par) * -1);
  will-change: transform;
}
.hero__media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 42%; }
.hero__scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgba(11,13,16,.30) 0%, rgba(11,13,16,0) 26%, rgba(11,13,16,.72) 100%),
    linear-gradient(96deg, rgba(11,13,16,.55) 0%, rgba(11,13,16,0) 58%);
}
.hero__in { position: relative; width: 100%; padding-block: clamp(40px, 7vw, 78px) clamp(34px, 5vw, 60px); }
.hero .dashes { margin-bottom: clamp(16px, 2vw, 22px); }
.hero__h1 {
  font-size: clamp(44px, 8.6vw, 104px);
  color: #fff;
  max-width: 15ch;
  margin: 0 0 clamp(20px, 3vw, 30px);
  text-shadow: 0 2px 24px rgba(11,13,16,.4);
}
.hero__h1 .ln { display: block; position: relative; overflow: hidden; padding-block: .04em; }
.hero__h1 .ln--sub {
  font-family: var(--font-body); font-style: normal; font-weight: 700;
  font-size: clamp(13px, 1.35vw, 17px); letter-spacing: .18em;
  line-height: 1.5; margin-top: clamp(10px, 1.4vw, 16px);
  color: rgba(255,255,255,.9); text-shadow: none;
}
.hero__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4); }
.hero__foot {
  position: absolute; right: var(--gut); bottom: clamp(34px, 5vw, 60px);
  text-align: right; color: rgba(255,255,255,.78);
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
}

/* Signature: each headline line is revealed by a -18deg blue
   wipe, the way a board gets laid onto a lift. One orchestrated
   moment; everything below is quiet. */
.hero__h1 .ln > span { display: inline-block; }
.js .hero__h1 .ln > span { opacity: 0; }
.js .hero__h1 .ln::after {
  content: ""; position: absolute; inset: -12% -40%;
  background: var(--mac-blue); transform: skewX(var(--shear)) translateX(-150%);
}
.js .hero .dashes i { transform: skewX(var(--shear)) scaleX(0); transform-origin: left; }
.js .hero__actions, .js .hero__foot { opacity: 0; }

.is-ready .hero__h1 .ln::after { animation: wipe 760ms var(--ease-out) forwards; }
.is-ready .hero__h1 .ln > span { animation: lineIn 760ms var(--ease-out) forwards; }
.is-ready .hero__h1 .ln:nth-child(2)::after,
.is-ready .hero__h1 .ln:nth-child(2) > span { animation-delay: 115ms; }
.is-ready .hero__h1 .ln:nth-child(3)::after,
.is-ready .hero__h1 .ln:nth-child(3) > span { animation-delay: 230ms; }
.is-ready .hero__h1 .ln:nth-child(4)::after,
.is-ready .hero__h1 .ln:nth-child(4) > span { animation-delay: 345ms; }
.is-ready .hero .dashes i { animation: dashIn 420ms var(--ease-out) forwards; }
.is-ready .hero .dashes i:nth-child(2) { animation-delay: 90ms; }
.is-ready .hero__actions { animation: riseIn 420ms var(--ease-out) 620ms forwards; }
.is-ready .hero__foot   { animation: riseIn 420ms var(--ease-out) 760ms forwards; }

@keyframes wipe {
  0%   { transform: skewX(-18deg) translateX(-150%); }
  46%  { transform: skewX(-18deg) translateX(0%); }
  100% { transform: skewX(-18deg) translateX(150%); }
}
@keyframes lineIn { 0%, 43% { opacity: 0; } 56%, 100% { opacity: 1; } }
@keyframes dashIn { to { transform: skewX(-18deg) scaleX(1); } }
@keyframes riseIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

/* --- 1b  Image with EST-bar caption ------------------------- */
.fig-1b { position: relative; padding-bottom: 22px; }
.fig-1b > img, .fig-1b > picture > img { width: 100%; }
/* Crop to a set height where the source aspect would otherwise
   unbalance its column. --fig-h tunes it per instance. */
.fig-1b--crop > img, .fig-1b--crop > picture > img { height: var(--fig-h, clamp(320px, 34vw, 470px)); object-fit: cover; }
.fig-1b__cap { position: absolute; left: -10px; bottom: 6px; display: flex; flex-direction: column; gap: 5px; max-width: calc(100% + 10px); }
.fig-1b__bar {
  height: 38px; background: var(--ink-900); transform: skewX(var(--shear));
  display: flex; align-items: center; padding: 0 26px 0 22px;
}
.fig-1b__bar span {
  transform: skewX(var(--unshear));
  font-family: var(--font-body); font-weight: 700; font-size: 14px;
  letter-spacing: .12em; text-transform: uppercase; color: #e7e9ec; white-space: nowrap;
}
.fig-1b__rule { height: 5px; width: 76%; background: var(--mac-blue); transform: skewX(var(--shear)); }
/* The ink cartouche disappears against an ink section, so on dark
   bands the bar inverts: white fill, ink text (19.46:1). The blue
   rule and the shear are unchanged. */
.band--dark .fig-1b__bar { background: #fff; }
.band--dark .fig-1b__bar span { color: var(--ink-900); }
.fig-1b--flush .fig-1b__cap { left: 0; }

/* --- 1l  Stat row ------------------------------------------- */
.stats { display: flex; align-items: stretch; }
.stat { flex: 1; padding-inline: clamp(14px, 3vw, 34px); }
.stat:first-child { padding-left: 0; }
.stat:last-child { padding-right: 0; }
.stat__n {
  font-family: var(--font-display); font-weight: 800; font-style: italic;
  font-size: clamp(46px, 7vw, 62px); line-height: 1; color: var(--ink-900);
}
.stat__n em { font-style: italic; color: var(--mac-blue); }
.stat__l { margin-top: 8px; }
.stat-sep { width: 3px; background: var(--ink-200); transform: skewX(var(--shear)); flex: none; }

/* --- 1j / 1k  Sector cards ---------------------------------- */
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-5); }
/* 24px, and it is the stagger offset rather than any header
   clearance — the header is in flow now and an anchor jump leaves it
   behind entirely. A deep-link target (Projects' sector grid carries
   #asbestos/#commercial/#industrial for Home's cards) is a staggered
   child, so it sits at translateY(24px) while the browser picks the
   landing offset; the reveal then lifts it by exactly that, putting
   the card 24px above the top with no rule at all. Measured: -24.2px
   at 1440 and at 412. Section targets (.band, .sector-sec) are not
   transformed and land flush with no rule, so they get none. */
.grid-3 > [id] { scroll-margin-top: 24px; }

.card-1j {
  display: flex; flex-direction: column; background: #fff;
  border: 1px solid var(--border); text-decoration: none;
  transition: border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.card-1j:hover { border-color: var(--ink-300); box-shadow: var(--shadow-2); }
.card-1j__media { position: relative; display: block; }
.card-1j__media img { width: 100%; height: 190px; object-fit: cover; clip-path: polygon(0 0, 100% 0, 100% 84%, 0 100%); }
.chip {
  position: absolute; top: 14px; right: 16px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .08em;
  color: #fff; background: rgba(11,13,16,.72); padding: 4px 8px;
}
.card-1j__body { padding: 6px 22px 24px; display: flex; flex-direction: column; flex: 1; }
.card-1j__t { display: block; font-family: var(--font-display); font-weight: 800; font-style: italic; text-transform: uppercase; font-size: 30px; line-height: 1; color: var(--ink-900); }
.card-1j__p { display: block; margin: 8px 0 0; font-size: 14px; line-height: 1.5; color: var(--ink-500); }
.card-1j__rule { display: block; margin-top: auto; padding-top: 14px; }
.card-1j__rule i { display: block; height: 5px; width: 44px; background: var(--mac-blue); transform: skewX(var(--shear)); transition: width var(--dur-base) var(--ease-out); }
.card-1j:hover .card-1j__rule i { width: 78px; }

.card-1k {
  display: flex; flex-direction: column; justify-content: space-between;
  min-height: 230px; background: var(--ink-900); padding: 24px 24px 22px;
  position: relative; overflow: hidden; text-decoration: none;
  transition: background var(--dur-base) var(--ease-out);
}
/* A sliver, not a wedge. The shear spreads this bar by tan(18deg)
   times the card height, so on a full-height grid cell it has to
   start much narrower than the 70px the element sheet quotes. */
.card-1k::before {
  content: ""; position: absolute; top: 0; bottom: 0; right: -34px; width: 44px;
  background: var(--mac-blue); transform: skewX(var(--shear)); opacity: .9;
  transition: right var(--dur-base) var(--ease-out);
}
.card-1k:hover { background: var(--ink-800); }
.card-1k:hover::before { right: -20px; }
/* ink-300 not ink-400 here: 9.05:1 on ink-900 instead of 4.45:1 */
.card-1k__meta { display: block; position: relative; font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-300); }
.card-1k__foot { display: block; position: relative; }
.card-1k__t { display: block; font-family: var(--font-display); font-weight: 800; font-style: italic; text-transform: uppercase; font-size: 34px; line-height: .95; color: #fff; }
.card-1k__p { display: block; margin: 8px 0 0; max-width: 26ch; font-size: 13.5px; line-height: 1.5; color: var(--ink-300); }

/* --- 1o  Diagonal break ------------------------------------- */
/* Band height tracks viewport width so the wedge angle stays
   constant (atan(.044) = 2.52deg) and the dash can match it. */
/* margin-top/-bottom -1px: the clip-path edges anti-alias against the white
   page behind the transparent corners, which left a 1px grey seam at the
   bottom where the dark band met it flush; the 1px bleed tucks it under. */
.break-1o { position: relative; height: clamp(44px, 4.4vw, 96px); background: var(--ink-900); clip-path: polygon(0 100%, 100% 0, 100% 100%, 0 100%); margin-top: -1px; margin-bottom: -1px; }
.break-1o i { position: absolute; right: 8%; top: 46%; width: 100px; height: 8px; background: var(--mac-blue); transform: rotate(-2.52deg) skewX(var(--shear)); }

/* --- Case study --------------------------------------------- */
.split { display: grid; grid-template-columns: 1.05fr 1fr; gap: clamp(28px, 5vw, 68px); align-items: center; }
.split--wide { grid-template-columns: 1fr 1.15fr; }
.split--top { align-items: start; }
/* The scaffold tower sits low in the frame; bias the crop down. */
.fig-1b--case > img, .fig-1b--case > picture > img { object-position: 50% 62%; }

/* --- 1n  Accreditation rail --------------------------------- */
.rail__head { display: flex; justify-content: space-between; align-items: baseline; padding-bottom: 10px; border-bottom: 1px solid var(--ink-100); }
.rail__logos { display: flex; align-items: center; gap: 34px; flex-wrap: wrap; padding-top: 26px; }
.rail__logos img { width: auto; }

/* --- Footer ------------------------------------------------- */
.site-foot { background: var(--ink-900); color: var(--ink-300); padding-block: clamp(48px, 6vw, 72px) 34px; }
.foot-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: var(--s-6); }
/* ink-350, not ink-400: these sit on ink-900, where ink-400 is 4.16:1
   and fails. Hierarchy is held by size and letter-spacing instead. */
.foot-h { font-family: var(--font-body); font-weight: 700; font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-350); margin: 0 0 var(--s-3); }
.site-foot a { color: #fff; text-decoration: none; display: inline-block; padding-block: 11px; margin-block: -4px; }
.site-foot a:hover { color: var(--mac-blue); }
.foot-links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; font-size: 14.5px; }
.foot-links a { display: block; }
.foot-tag { font-family: var(--font-display); font-weight: 800; font-style: italic; text-transform: uppercase; font-size: clamp(28px, 4vw, 40px); line-height: .95; color: #fff; margin: 0; }
.foot-base { display: flex; align-items: center; justify-content: space-between; gap: var(--s-4); flex-wrap: wrap; margin-top: clamp(40px, 5vw, 60px); padding-top: 22px; border-top: 1px solid var(--ink-800); }
.foot-base .mono { color: var(--ink-350); }

/* --- Scroll reveal: one per section, fade-up 12px / 300ms ---- */
/* 20px, not 12px: over a longer duration a short travel reads as
   sluggish rather than graceful — the distance has to earn the time. */
.js .reveal { opacity: 0; transform: translateY(20px); }
.reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity var(--dur-reveal) var(--ease-reveal),
              transform var(--dur-reveal) var(--ease-reveal);
}

/* --- Scroll detail ------------------------------------------
   Everything below hangs off the section's single .is-in flag —
   no extra observers. Two rules kept it from turning into an
   effects reel: each one moves along the -18deg motif rather
   than in an arbitrary direction, and nothing that carries a
   fact (a stat, a headline, copy) animates on its own.
   ----------------------------------------------------------- */

/* A trigger only: does not fade or move itself. Must follow the
   base .reveal rule to win on source order. */
.js .reveal--bare { opacity: 1; transform: none; }
/* Where children stagger, the parent stops moving so the two
   motions don't compound into a double-shift. */
.js .reveal--stagger { transform: none; }

/* 1f slash underline wipes out from the left, ink then blue. */
.js .reveal .slash-rule span { transform: skewX(var(--shear)) scaleX(0); transform-origin: left center; }
.reveal.is-in .slash-rule span { transform: skewX(var(--shear)) scaleX(1); transition: transform 720ms var(--ease-reveal) 240ms; }
.reveal.is-in .slash-rule span:last-child { transition-delay: 420ms; }

/* 1l separators draw downward. The numerals never animate —
   no counters, per the spec's non-goals. */
.js .reveal .stat-sep { transform: skewX(var(--shear)) scaleY(0); transform-origin: center top; }
.reveal.is-in .stat-sep { transform: skewX(var(--shear)) scaleY(1); transition: transform 820ms var(--ease-reveal) 260ms; }

/* Sector cards arrive one after another, 140ms apart. */
.js .reveal .grid-3 > * { opacity: 0; transform: translateY(24px); }
/* This selector outranks .card-1j / .card-1k, and `transition` is a
   shorthand — so it replaces their hover transitions outright. The
   hover properties have to be restated here or the cards' border,
   shadow and background all inherit the slow reveal timing. */
.reveal.is-in .grid-3 > * {
  opacity: 1; transform: none;
  transition: opacity var(--dur-reveal) var(--ease-reveal),
              transform var(--dur-reveal) var(--ease-reveal),
              border-color var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out),
              background var(--dur-base) var(--ease-out);
}
.reveal.is-in .grid-3 > *:nth-child(2) { transition-delay: 140ms; }
.reveal.is-in .grid-3 > *:nth-child(3) { transition-delay: 280ms; }

/* Eight crew tiles, 60ms apart, written out to nth-child(8). The
   roster grid shipped once with delays defined only to nth-child(5)
   while rendering ten tiles, so half the set fired at 0ms and the
   second row arrived as a block — this is the shape that avoids
   repeating it. 60ms and not the rail's 70ms: eight tiles at 70ms
   is 490ms of stagger and stops reading as one gesture. */
.js .reveal .crew-grid > * { opacity: 0; transform: translateY(20px); }
.reveal.is-in .crew-grid > * {
  opacity: 1; transform: none;
  transition: opacity var(--dur-reveal) var(--ease-reveal),
              transform var(--dur-reveal) var(--ease-reveal);
}
.reveal.is-in .crew-grid > *:nth-child(2) { transition-delay:  60ms; }
.reveal.is-in .crew-grid > *:nth-child(3) { transition-delay: 120ms; }
.reveal.is-in .crew-grid > *:nth-child(4) { transition-delay: 180ms; }
.reveal.is-in .crew-grid > *:nth-child(5) { transition-delay: 240ms; }
.reveal.is-in .crew-grid > *:nth-child(6) { transition-delay: 300ms; }
.reveal.is-in .crew-grid > *:nth-child(7) { transition-delay: 360ms; }
.reveal.is-in .crew-grid > *:nth-child(8) { transition-delay: 420ms; }

/* The 1o blue dash runs in along the cut it sits on. */
.js .break-1o i { transform: rotate(-2.52deg) skewX(var(--shear)) scaleX(0); transform-origin: right center; }
.break-1o.is-in i { transform: rotate(-2.52deg) skewX(var(--shear)) scaleX(1); transition: transform 900ms var(--ease-reveal) 160ms; }

/* 1n marks settle in sequence — 70ms apart, close enough to read
   as one gesture rather than seven. */
.js .reveal .rail__logos img { opacity: 0; transform: translateY(14px); }
.reveal.is-in .rail__logos img { opacity: 1; transform: none; transition: opacity 560ms var(--ease-reveal), transform 560ms var(--ease-reveal); }
.reveal.is-in .rail__logos img:nth-child(2) { transition-delay: 70ms; }
.reveal.is-in .rail__logos img:nth-child(3) { transition-delay: 140ms; }
.reveal.is-in .rail__logos img:nth-child(4) { transition-delay: 210ms; }
.reveal.is-in .rail__logos img:nth-child(5) { transition-delay: 280ms; }
.reveal.is-in .rail__logos img:nth-child(6) { transition-delay: 350ms; }
.reveal.is-in .rail__logos img:nth-child(7) { transition-delay: 420ms; }

/* --- Hover detail -------------------------------------------- */

/* Arrow lives in CSS so it can move; it is decorative, so it is
   hidden from assistive tech. */
.tlink::after {
  content: "→"; display: inline-block; margin-left: 8px;
  transition: transform var(--dur-base) var(--ease-out);
}
.tlink:hover::after, .tlink:focus-visible::after { transform: translateX(5px); }

/* The photo drifts under the fixed diagonal cut, which now lives
   on the wrapper so the clipped edge itself stays put. */
.card-1j__media { overflow: hidden; clip-path: polygon(0 0, 100% 0, 100% 84%, 0 100%); }
.card-1j__media img { clip-path: none; transition: transform 620ms var(--ease-out); }
.card-1j:hover .card-1j__media img { transform: scale(1.045); }

/* --- Responsive --------------------------------------------- */
@media (max-width: 1080px) {
  .nav-toggle { display: grid; }

  /* The panel is laid out at all times and hidden by state, not by
     `display` — display cannot transition, which is why the old
     none/flex swap could not animate at all. `visibility` is what
     takes the panel out of the tab order and the accessibility tree;
     opacity alone would leave five invisible focus stops in the
     header. It stays absolutely positioned in both states so it can
     never re-enter the header's flex row. */
  .nav {
    display: flex; flex-direction: column; align-items: flex-start; gap: 0;
    position: absolute; left: 0; right: 0; top: 100%;
    background: var(--ink-900); padding: var(--s-4) var(--gut) var(--s-6);
    visibility: hidden; opacity: 0; transform: translateY(-10px);
    transition: opacity var(--dur-base) var(--ease-out),
                transform var(--dur-base) var(--ease-out),
                visibility 0s linear var(--dur-base);
  }
  .nav.is-open {
    visibility: visible; opacity: 1; transform: translateY(0);
    transition: opacity var(--dur-base) var(--ease-out),
                transform var(--dur-base) var(--ease-out),
                visibility 0s;
  }

  /* Colour has to be restated for the states the base block sets at
     higher specificity: `.nav a:hover` and `.nav a[aria-current]` are
     both (0,2,1) and beat a bare `.nav a` here whatever the order, so
     they would repaint ink-900 on an ink-900 panel — which is how the
     current page's own link disappears. The blue ::after underline
     still marks it. */
  .nav a,
  .nav a:hover,
  .nav a[aria-current="page"] { color: #fff; }

  .nav a {
    font-size: 17px; padding: 13px 0; width: 100%;
    border-bottom: 1px solid var(--ink-800);
    opacity: 0; transform: translateY(-8px);
    transition: color var(--dur-fast) var(--ease-out),
                opacity var(--dur-base) var(--ease-out),
                transform var(--dur-base) var(--ease-out);
  }
  .nav.is-open a { opacity: 1; transform: translateY(0); }

  /* Unfocusable the instant the panel closes. The panel above holds
     `visibility: visible` for the length of its fade-out, and a Tab
     inside that window would otherwise land on an invisible link —
     a child may hide itself while its parent is still visible. */
  .nav:not(.is-open) a { visibility: hidden; }

  .break-1o i { display: none; }
}
@media (max-width: 900px) {
  /* Straight from three-up to one-up: a two-column grid would leave
     the third sector orphaned on its own row. */
  .grid-3 { grid-template-columns: 1fr; }
  .card-1j__media img { height: 240px; }
  .card-1k { min-height: 200px; }
  .split, .split--wide { grid-template-columns: 1fr; }
  .foot-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  body { font-size: 16px; }
  /* The bar keeps its full 104px/74px here — that is the size the
     option was reviewed at, and it was measured for overflow at 375px. */
  .card-1j__media img { height: 200px; }
  .foot-grid { grid-template-columns: 1fr; }
  .stats { flex-wrap: wrap; gap: var(--s-5) 0; }
  .stat { flex: 1 1 100%; padding-inline: 0; }
  .stat-sep { display: none; }
  .stat + .stat { padding-top: var(--s-5); border-top: 1px solid var(--ink-100); }
  .hero { min-height: min(92svh, 680px); }
  .hero__foot { display: none; }
  .hero__actions .btn { width: 100%; }
  .rail__logos { gap: 22px 26px; }
  .rail__logos img { height: 30px !important; }
  .fig-1b__bar { height: 34px; padding: 0 20px 0 16px; }
  .fig-1b__bar span { font-size: 12px; letter-spacing: .1em; }
}

/* --- Motion preferences ------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .js .hero__h1 .ln > span,
  .js .hero__actions,
  .js .hero__foot,
  .js .reveal,
  .js .reveal .grid-3 > *,
  .js .reveal .crew-grid > *,
  .js .reveal .rail__logos img { opacity: 1; transform: none; }
  .js .hero__h1 .ln::after { display: none; }
  /* These carry the shear, so they resolve to their finished
     transform — never to `none`, which would straighten them. */
  .js .hero .dashes i { transform: skewX(var(--shear)); }
  .js .reveal .slash-rule span { transform: skewX(var(--shear)) scaleX(1); }
  .js .reveal .stat-sep { transform: skewX(var(--shear)) scaleY(1); }
  .js .break-1o i { transform: rotate(-2.52deg) skewX(var(--shear)) scaleX(1); }
  .js .card-1j:hover .card-1j__media img { transform: none; }
  /* The mobile panel is state, not arrival: it must land at once in
     both directions. The universal rule above collapses duration but
     not delay, and the close transition holds `visibility` on one. */
  .nav { transition-delay: 0s !important; }
}

/* ============================================================
   INNER PAGES
   Added for the Sectors page (CAP-2). Everything here is either
   a treatment element-system.md specifies but the home page had
   no occasion to build (1c, 1d, 1i.1, 1i.2), or a new element
   flagged for a spec update (the page hero).
   ============================================================ */

/* --- Page hero (inner pages) — NEW ELEMENT ------------------
   Home opens on a full-bleed photo; every other page needs an
   opening that is unmistakably not that. This is a compact ink
   strip carrying .band--dark, so it inherits every on-dark rule
   already in this file rather than restating them.
   Not in element-system.md — see DESIGN-NOTES.md.

   It was a ~300px block, and the block was the problem: its title
   took the speed-dash mark, the slash-rule and the display face,
   which is the section heading's own lockup — so every inner page
   opened with two headings for one subject. The marks stay with
   the headings and the photography treatments that own them; what
   they no longer do is appear twice above the fold. What is left
   here is one 62px row saying where you are, in the
   utility voice: breadcrumb running into the title, page fact
   right. The first section heading is the first real thing on
   the page.
   ----------------------------------------------------------- */
.page-hero { position: relative; overflow: hidden; padding-block: 0; }
.page-hero .wrap {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 0 var(--s-5); min-height: 62px;
}
/* The trail's last step is the h1 itself, so the crumb ends on its
   sheared separator and hands straight over. */
.page-hero__title { display: flex; align-items: center; gap: 11px; }
.page-hero__title .crumb { margin: 0; }
.page-hero .display {
  font-family: var(--font-body); font-weight: 700; font-style: normal;
  font-size: 14px; letter-spacing: .1em; line-height: 1;
}

/* The fact rides the same row, pushed right. */
.page-hero__util {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 10px var(--s-5); margin-left: auto;
}
.page-hero__fact {
  margin: 0; font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-350);
}
/* The 1p util bar carries breadcrumb + page fact only; the phone
   number that used to sit here is Contact-page-only now, so the
   fact stays visible at every width rather than swapping out. */

/* Breadcrumb. The separator is a sheared bar, not a slash —
   a "/" would be the only unsheared diagonal on the site. */
.crumb {
  display: flex; align-items: center; gap: 11px;
  margin: 0 0 clamp(18px, 2.4vw, 30px);
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-350);
}
.crumb a { position: relative; color: var(--ink-300); text-decoration: none; transition: color var(--dur-fast) var(--ease-out); }
.crumb a::before { content: ""; position: absolute; inset: -14px -8px; }
.crumb a:hover { color: #fff; }
/* ink-400 rather than ink-700. This is the hand-over from the trail
   to the page title now, not a divider between two labels, and at
   ink-700 it measured 1.55:1 on the band — present in the DOM and
   absent on screen. Not type, so the palette's white-only pairing
   note does not apply; 4.17:1 keeps it a step quieter than the
   labels' own ink-350. */
.crumb i { display: block; width: 2px; height: 11px; background: var(--ink-400); transform: skewX(var(--shear)); }

/* Micro type on dark bands takes the ink-background value. */
.band--dark .mono, .band--dark .micro { color: var(--ink-350); }

/* --- 1c  Offset ink plate ----------------------------------
   The quiet image treatment: the photo sits proud of a flat ink
   plate offset 16px down-right. The plate IS the depth, so no
   shadow. Used wherever there is no nameable site to put in a
   1b caption bar — see the 1b/1c rule in DESIGN-NOTES.md.
   ----------------------------------------------------------- */
.fig-1c { position: relative; margin: 0; padding: 0 16px 16px 0; }
.fig-1c::before { content: ""; position: absolute; top: 16px; left: 16px; right: 0; bottom: 0; background: var(--ink-900); }
.fig-1c img { position: relative; width: 100%; height: var(--fig-h, clamp(300px, 32vw, 440px)); object-fit: cover; }
/* Optional 10px mono micro-caption on the exposed plate edge. */
.fig-1c__cap {
  position: absolute; right: 6px; bottom: 0; height: 16px;
  display: flex; align-items: center;
  font-family: var(--font-mono); font-size: 10px; line-height: 1;
  letter-spacing: .1em; text-transform: uppercase; color: #fff;
}

/* --- Type-led proof panel (1k, portrait) --------------------
   Where a section has no photography, the 1k tile stretched to
   fill the image column. Never a stock photo — SPEC.md.
   ----------------------------------------------------------- */
.panel-1k {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; justify-content: space-between;
  min-height: var(--fig-h, clamp(300px, 32vw, 440px));
  background: var(--ink-900); color: #fff;
  padding: clamp(24px, 2.6vw, 34px);
}
/* Narrower and pushed further out than the 1k card's sliver: the
   shear spreads this bar by tan(18deg) x panel height, and this
   panel is roughly twice a card's height. */
.panel-1k::before {
  content: ""; position: absolute; top: 0; bottom: 0; right: -52px; width: 40px;
  background: var(--mac-blue); transform: skewX(var(--shear)); opacity: .9;
}
.panel-1k__meta { position: relative; font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-300); }
.panel-1k__body { position: relative; }
.panel-1k__n { font-family: var(--font-display); font-weight: 800; font-style: italic; text-transform: uppercase; font-size: clamp(56px, 7.4vw, 92px); line-height: .86; color: #fff; }
.panel-1k__n em { font-style: italic; color: var(--mac-blue); }
.panel-1k__p { margin: var(--s-4) 0 0; max-width: 30ch; font-size: 15px; line-height: 1.55; color: var(--ink-300); }
/* Contrast can't carry this down the hierarchy on ink, so size and
   letter-spacing do it instead. */
.panel-1k__note { position: relative; font-family: var(--font-mono); font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-350); margin: var(--s-5) 0 0; }

/* --- 1d  Sheared strip (section break) ---------------------
   Photo panel + 16px blue slash + ink panel with a short
   display-italic label. All three shear; the photo counter-skews
   and over-scales so no gap shows inside its mask. Once per page.
   ----------------------------------------------------------- */
.strip-1d { display: flex; gap: 10px; overflow: hidden; padding-inline: var(--gut); height: clamp(190px, 24vw, 300px); }
.strip-1d > * { transform: skewX(var(--shear)); overflow: hidden; }
.strip-1d__ph { flex: 2; }
.strip-1d__ph img { width: 130%; height: 100%; object-fit: cover; transform: skewX(var(--unshear)) translateX(-10%); }
.strip-1d__bar { flex: none; width: 16px; background: var(--mac-blue); }
.strip-1d__panel { flex: 1; background: var(--ink-900); display: flex; align-items: flex-end; }
.strip-1d__panel span {
  transform: skewX(var(--unshear)); padding: 0 0 18px 30px;
  font-family: var(--font-display); font-weight: 800; font-style: italic;
  text-transform: uppercase; font-size: clamp(24px, 2.8vw, 34px); line-height: .95; color: #fff;
}

/* --- Sector sections ---------------------------------------- */
.sector-sec { padding-block: clamp(56px, 7.4vw, 96px); --fig-h: clamp(300px, 33vw, 460px); }
/* On every one, not just between them: without a rule above the
   first, the set opens on 200px of unanchored white and the three
   sections stop reading as one run. */
.sector-sec { border-top: 1px solid var(--border); }

/* Replaces 1f's eyebrow on sector sections: the index chip from
   the grid above, plus that sector's meta line, so the card and
   the section read as the same object. */
.sec-ix { display: flex; align-items: center; gap: 11px; margin: 0 0 var(--s-4); font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-400); }
.sec-ix i { display: block; width: 2px; height: 11px; background: var(--ink-200); transform: skewX(var(--shear)); }
.sector-sec .head-1f .display { font-size: clamp(36px, 5vw, 52px); }

/* Mirror a split without reordering the source: the copy always
   comes first in the DOM, so the one-column phone layout reads
   heading, copy, image on every section. */
@media (min-width: 901px) {
  .split--flip > *:nth-child(1) { grid-column: 2; grid-row: 1; }
  .split--flip > *:nth-child(2) { grid-column: 1; grid-row: 1; }
}

/* --- Closing CTA -------------------------------------------- */
.cta { display: grid; grid-template-columns: 1.15fr 1fr; gap: clamp(24px, 4vw, 64px); align-items: center; }
.cta__actions { display: flex; flex-wrap: wrap; gap: var(--s-4); }

/* --- Motion ------------------------------------------------- */
/* The page hero runs on the load sequence, not on a scroll
   reveal: it is above the fold, and fading in something already
   on screen reads as a flash. Deliberately lighter than home's
   -18deg wipe — that stays the home page's one signature moment.
   Now that the strip carries no marks, the two rise-ins are the
   whole sequence, and the title leads: it holds the breadcrumb and
   the h1, so the page fact trailing it by 100ms is the right way
   round. It was the other way while the fact came first in the
   DOM. */
.js .page-hero__util, .js .page-hero__title { opacity: 0; }
.is-ready .page-hero__util, .is-ready .page-hero__title { animation: riseIn 520ms var(--ease-out) 80ms forwards; }
.is-ready .page-hero__util { animation-delay: 180ms; }

/* The 1d blue slash draws down its own shear. */
.js .reveal .strip-1d__bar { transform: skewX(var(--shear)) scaleY(0); transform-origin: center top; }
.reveal.is-in .strip-1d__bar { transform: skewX(var(--shear)) scaleY(1); transition: transform 820ms var(--ease-reveal) 200ms; }

/* --- Responsive --------------------------------------------- */
@media (max-width: 900px) {
  .cta { grid-template-columns: 1fr; }
  .strip-1d { height: clamp(170px, 34vw, 230px); }
}
/* The strip runs out of room for one row before the site's next
   breakpoint down, so it gets its own: the fact drops under the
   title rather than wrapping to a right-aligned second line. */
@media (max-width: 700px) {
  .page-hero .wrap { padding-block: 14px; }
  .page-hero__util { width: 100%; margin-left: 0; margin-top: 6px; }
}
@media (max-width: 640px) {
  .sector-sec { --fig-h: clamp(240px, 62vw, 320px); }
  .panel-1k { padding: 24px 22px; }
  .strip-1d { gap: 8px; height: 190px; }
  .strip-1d__panel span { padding: 0 0 14px 22px; }
  .cta__actions .btn { width: 100%; }
}

/* --- Motion preferences ------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .js .page-hero__util, .js .page-hero__title { opacity: 1; transform: none; }
  /* This carries the shear, so it resolves to the finished
     transform — never to `none`, which would straighten it. */
  .js .reveal .strip-1d__bar { transform: skewX(var(--shear)) scaleY(1); }
}

/* ============================================================
   PRODUCTION PAGES
   Components the mockups had no occasion to build: 1m / 1m.2
   quotes, the Team grid, the client strip, the expanded 1n list,
   the contact form and the privacy prose. Same tokens, same
   motif, same rules.
   ============================================================ */

/* --- 1m  Leadership pull quote -------------------------------
   Reserved for first-person leadership quotes (Dave Bevan,
   Gareth Hillman). Blue rule, full height. */
.quote-1m {
  margin: var(--s-6) 0 0; padding-left: var(--s-5);
  border-left: 4px solid var(--mac-blue);
}
.quote-1m p {
  font-family: var(--font-display); font-weight: 700; font-style: italic;
  font-size: clamp(21px, 2vw, 26px); line-height: 1.25;
  color: var(--ink-900); margin: 0 0 var(--s-4);
}
.band--dark .quote-1m p { color: #fff; }
.quote-1m footer { padding-top: 2px; }
.quote-1m footer b {
  display: block; font-family: var(--font-body); font-weight: 700;
  font-size: 14px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-900); font-style: normal;
}
.band--dark .quote-1m footer b { color: #fff; }
.quote-1m footer span {
  display: block; margin-top: 3px; font-family: var(--font-mono);
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-400);
}
.band--dark .quote-1m footer span { color: var(--ink-350); }

/* --- MD statement band (About) ------------------------------
   The sources carry a third-person bio and one first-person pull
   quote, and only the quote is actually his voice — so the quote
   IS the section and the bio's facts compress into the credit
   line. Full width, nothing set beside it: the two-column profile
   this replaces read as a wall of text.

   Not .display: that class uppercases, which is unreadable over
   80 words. Same sentence-case display italic as 1m, scaled up. */
.md-note__q {
  margin: 0; max-width: 24em;
  font-family: var(--font-display); font-weight: 700; font-style: italic;
  font-size: clamp(23px, 2.9vw, 40px); line-height: 1.16; color: #fff;
}
.md-note__q p { margin: 0 0 .55em; }
.md-note__q p:last-child { margin-bottom: 0; }
.md-note .slash-rule { margin-top: clamp(26px, 3vw, 40px); }
.md-note__by {
  margin: var(--s-5) 0 0; font-family: var(--font-body); font-weight: 700;
  font-size: 14px; letter-spacing: .08em; text-transform: uppercase; color: #fff;
}
.md-note__meta { margin: var(--s-2) 0 0; }

/* With a portrait column beside it the quote runs in roughly half the
   measure, so the display size steps down — held at the full-width
   scale it would set five or six words to the line. The step is the
   sheet's existing clamp(24px, 2.6vw, 30px) rung, not a new one.
   max-width goes: the column is now the measure. */
.md-note--split .md-note__q { font-size: clamp(24px, 2.6vw, 30px); max-width: none; }

/* --- 1m.2  Attributed endorsement ----------------------------
   Third-party variant: the rule is 60% height, top-aligned, and
   the attribution must carry an organisation — a client's words
   are visibly not MAC's voice. */
.quote-1m2 { border-left: 0; position: relative; }
.quote-1m2::before {
  content: ""; position: absolute; left: -4px; top: 0;
  width: 4px; height: 60%; background: var(--mac-blue);
}

/* 1k panel, facts variant (Safety): verifiable safeguards as a
   hairline-divided list in place of the pull-quote. */
.panel-1k__facts { position: relative; list-style: none; margin: var(--s-5) 0 0; padding: 0; }
.panel-1k__facts li {
  padding: 13px 0; border-top: 1px solid var(--ink-800);
  font-size: 15px; line-height: 1.5; color: var(--ink-300);
}
.panel-1k__facts li:first-child { border-top: 0; padding-top: 0; }
.panel-1k__facts b { color: #fff; font-weight: 700; }

/* --- Leadership profiles (About) ----------------------------- */
.profile { padding-block: clamp(40px, 5vw, 64px); border-top: 1px solid var(--border); }
.profile .display { font-size: clamp(34px, 4.6vw, 48px); }

/* --- 1k panel, generic use ----------------------------------
   The Sectors page built .panel-1k for its image column; Team,
   About (Gareth) and People (Finlay) reuse it at other heights.
   The sliver is retuned per height — see the sliver rule. */
.panel-1k--profile { --fig-h: clamp(320px, 36vw, 480px); }

/* On a band--dark the panel's own ink ground is the band's ground and
   the tile disappears. --ink-800 is the step the 1k facts list already
   uses for hairlines on ink, but ink-800 on ink-900 is only 1.14:1, so
   the edge is drawn rather than left to the fill: the tile has to be
   findable as an object, not merely present. */
.panel-1k--onink { background: var(--ink-800); outline: 1px solid var(--ink-700); outline-offset: -1px; }

/* --- Team roster (About, CAP-11) ─────────────────────────────
   Eight cards, four-up then straight to two-up. This replaces the
   seven alternating .split profile rows that used to live here —
   two blocks per person, roughly a screen each. The client's brief
   puts the name and role inside the card instead.

   Eight is a layout fact rather than a headcount: it divides
   cleanly by four and by two, so no row is ever orphaned. Seven
   orphans three at four-up, and three-up would orphan two. If the
   real roster turns out to be seven or nine, that is the first
   constraint to re-check.

   The cards carry no href — there are no individual profile pages
   — so there is deliberately no hover lift, no shadow and no
   pointer cursor. Signalling clickability on a card that does not
   click is the defect already ledgered against the sector cards. */
.crew-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s-4); }

.crew-card {
  position: relative; overflow: hidden;
  aspect-ratio: 3 / 4; background: var(--ink-900);
  display: flex; flex-direction: column; justify-content: flex-end;
}

/* The photo window takes the 1j diagonal cut, the name sits on the
   card's own ink ground beneath it, and a blue seam runs along the
   cut joining the two — so the card reads as one object rather than
   a photo with a caption parked under it.

   The seam is NOT the 1k sliver, and that is geometry rather than
   taste. A vertical bar at skewX(-18deg) spreads by tan(18deg) x
   height, and these cards are ~347px tall at four-up, so a 40px bar
   renders as a ~123px wedge straight across the subject's face and
   through the longer names — the same failure the element sheet's
   70px sliver hit on the home page cards, at twice the severity. No
   width fixes it; the card is simply too tall for a full-height bar.

   So the blue moves onto the cut, where the geometry works for it
   rather than against it: the window's ground is blue and the photo
   inside is clipped 2% shallower, which shows as a constant-thickness
   parallelogram along the diagonal — ~4.7px at four-up and ~2.5px at
   375px, matching the 5px the 1j rule and the slash-rule already use.
   It can never cross a face and never touch a name.

   flex:1 rather than a fixed 68%: at a fixed height the caption is
   shorter than its zone on every card and each one sat on ~60px of
   dead ink. The window absorbs the slack instead. */
.crew-card__win {
  position: relative; overflow: hidden; flex: 1 1 auto;
  background: var(--mac-blue);
  clip-path: polygon(0 0, 100% 0, 100% 86%, 0 100%);
}
.crew-card__win .crew-card__img,
.crew-card__win .crew-card__ph {
  position: absolute; inset: 0;
  clip-path: polygon(0 0, 100% 0, 100% 84%, 0 98%);
}
.crew-card__img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 18%; }

/* Placeholder state — the shipping state until portraits land. A
   ghosted monogram on the ink ground: never a stock portrait and
   never a silhouette (CAP-11), and not the words "photo to follow"
   repeated eight times down a page a buyer reads for credibility.
   Decorative, so it is hidden from assistive tech at the element —
   the name below it is the real content.

   ink-800 rather than ink-900 so the tile is findable as an object
   against the card behind it, which is the reasoning
   panel-1k--onink already records. */
.crew-card__ph { display: grid; place-items: center; background: var(--ink-800); }
.crew-card__mono {
  font-family: var(--font-display); font-weight: 800; font-style: italic;
  text-transform: uppercase; font-size: clamp(46px, 5.4vw, 74px);
  line-height: 1; color: var(--ink-700); user-select: none;
}

/* White on ink-900 is 19.46:1 and ink-300 on ink-900 is 9.05:1 —
   both clear AA comfortably, which is what buys the right to set
   the role this small. */
.crew-card__cap { position: relative; z-index: 3; padding: 16px; }
.crew-card__n {
  margin: 0; font-family: var(--font-display); font-weight: 800; font-style: italic;
  text-transform: uppercase; line-height: .94; color: #fff;
  font-size: clamp(19px, 1.55vw, 25px);
}
.crew-card__r {
  margin: 7px 0 0; font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: .12em; text-transform: uppercase; line-height: 1.35;
  color: var(--ink-300);
}

/* --- 1n expanded (Safety page) -------------------------------
   Every mark named, original colour, alongside what it vouches
   for. Two columns; one on phone. */
.acc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-4); margin-top: var(--s-6); }
.acc-item {
  display: flex; align-items: center; gap: var(--s-5);
  border: 1px solid var(--ink-100); padding: 18px 22px; background: #fff;
}
.acc-item img { flex: none; }
.acc-item h3 {
  margin: 0; font-family: var(--font-body); font-weight: 700;
  font-size: 15px; letter-spacing: .02em; color: var(--ink-900);
}
.acc-item p { margin: 3px 0 0; font-size: 13.5px; line-height: 1.5; color: var(--ink-500); }
.acc-item:last-child:nth-child(odd) { grid-column: 1 / -1; }

/* --- Contact ------------------------------------------------- */
.contact-grid { display: grid; grid-template-columns: 1fr 1.1fr; gap: clamp(28px, 5vw, 68px); align-items: start; }
.nap { font-style: normal; line-height: 1.75; color: var(--ink-500); }
.nap b { display: block; color: var(--ink-900); font-weight: 700; }
.nap a { color: var(--ink-900); display: inline-block; padding-block: 11px; margin-block: -3px;
  text-decoration: underline 2px var(--mac-blue); text-underline-offset: 4px; }
.nap a:hover { color: var(--mac-blue-700); }
.map-link { display: block; text-decoration: none; }
.map-note { margin: 10px 0 0; }

/* Inputs are 48px tall with a 1i.1 primary submit; 16px type so
   iOS does not zoom on focus. */
.form { display: grid; gap: var(--s-5); }
.form label {
  display: block; margin-bottom: 8px;
  font-family: var(--font-body); font-weight: 700; font-size: 13px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-600);
}
.form input, .form textarea {
  width: 100%; height: 48px; padding: 0 14px;
  border: 2px solid var(--ink-200); background: #fff;
  font-family: var(--font-body); font-size: 16px; color: var(--ink-900);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.form textarea { height: auto; min-height: 150px; padding: 12px 14px; resize: vertical; }
.form input:hover, .form textarea:hover { border-color: var(--ink-300); }
.form input:focus-visible, .form textarea:focus-visible {
  outline: 3px solid var(--mac-blue); outline-offset: 0; border-color: var(--ink-900);
}
.form-foot { display: flex; align-items: center; gap: var(--s-5); flex-wrap: wrap; }
.form-status { margin: 0; font-weight: 700; color: var(--ink-900); }
.form-status--err { color: #a4292f; }
/* Honeypot: hidden from people, present for bots. Not display:none —
   the cruder harvesters skip fields they cannot see. */
.hp { position: absolute !important; left: -9999px !important; width: 1px; height: 1px; overflow: hidden; }

/* --- Privacy prose ------------------------------------------- */
.prose { max-width: 70ch; }
.prose a { color: var(--ink-900); text-decoration: none; border-bottom: 2px solid var(--mac-blue); }
.prose a:hover { color: var(--mac-blue-700); }
.prose h2 {
  font-family: var(--font-display); font-weight: 800; font-style: italic;
  text-transform: uppercase; font-size: clamp(24px, 2.6vw, 30px);
  color: var(--ink-900); margin: var(--s-7) 0 var(--s-3);
}
.prose h2:first-child { margin-top: 0; }
.prose p, .prose li { color: var(--ink-500); }
.prose ul { margin: 0 0 var(--s-4); padding-left: 22px; }
.prose li { margin-bottom: 6px; }
.prose li::marker { color: var(--mac-blue); }

/* --- Responsive --------------------------------------------- */
@media (max-width: 1080px) {
  /* Four-up straight to two-up. Eight divides cleanly by both; a
     three-up step in between would orphan two tiles. */
  .crew-grid { grid-template-columns: repeat(2, 1fr); gap: var(--s-3); }
}
@media (max-width: 900px) {
  .acc-grid { grid-template-columns: 1fr; }
  .contact-grid { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .crew-card__cap { padding: 13px; }
}
/* Below 420px the caption gives ground, never the cut. Two-up at
   320px leaves a 126px card, and at the base 19px/10.5px a
   worst-case name and role ("Dafydd Emmanuel-Price" / "Health &
   Safety Advisor") wrap far enough to squeeze the photo window to
   23% of the card and the seam to 0.79px — sub-pixel, so the one
   device carrying the whole idea disappears on the narrowest
   screens. Measured, not guessed.

   17px and 10px are the floors the system already sets elsewhere
   (panel-1k__note is 10px), so this borrows nothing new. It takes
   the worst case back to a 40% window and a 1.33px seam at 320,
   and 58% / 2.39px at 375. Nothing clips at any width. The lever
   is deliberately the caption: moving the clip-path percentages
   would change the cut's angle relationship to the 1j motif. */
@media (max-width: 420px) {
  .crew-card__n { font-size: 17px; }
  .crew-card__r { font-size: 10px; letter-spacing: .08em; margin-top: 5px; }
  .crew-card__cap { padding: 11px; }
}
