/* ============================================================
   Lia Engineering — design system
   Palette: primary #1d2122, bg #ffffff — monochrome (black & white), no accent hue
   Type: Jost (display, matches the "LIA ENGINEERING" logo wordmark) + Barlow (body), self-hosted
   ============================================================ */

/* ---------- Fonts ---------- */
@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/Barlow-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('fonts/Barlow-600.woff2') format('woff2');
}
@font-face {
  font-family: 'Jost';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('fonts/Jost-VF.woff2') format('woff2');
}

/* ---------- Tokens ---------- */
:root {
  --ink: #1d2122;            /* client primary */
  --accent: #1d2122;         /* accent role, monochrome: ink on light surfaces */
  --paper: #ffffff;          /* client page background */
  --ink-soft: #495256;       /* secondary text, tinted from ink hue */
  --ink-faint: #6a7478;      /* tertiary, large text only */
  --line: #dde2e4;           /* hairlines on paper */
  --paper-dim: #f3f5f5;      /* alternate band, tinted from ink hue */
  --dark: #1d2122;           /* dark band background */
  --dark-2: #272c2e;         /* raised surface on dark */
  --dark-line: #3a4144;      /* hairlines on dark */
  --dark-text: #c3cacd;      /* secondary text on dark */
  --accent-press: #000000;   /* accent active state */
  --accent-on-dark: #ffffff; /* the accent role inverted, for dark surfaces */
  --display: 'Jost', 'Century Gothic', 'Futura', sans-serif;
  --body: 'Barlow', 'Helvetica Neue', Arial, sans-serif;
  --ease: cubic-bezier(0.33, 0, 0.2, 1);
  --fast: 180ms;
  --slow: 320ms;
  --radius: 4px;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --measure: 68ch;
  --header-top: clamp(14px, 1.8vw, 26px);
  --header-bar-h: 68px;
  /* space a page top must leave for the detached floating header */
  --header-clear: calc(var(--header-top) + var(--header-bar-h));
  /* height the home client strip reserves at the bottom of the first screen,
     so the hero photo fills the rest of the viewport and the logos still show */
  --client-strip-h: 150px;
  accent-color: var(--accent);
}

/* ---------- Reset & base ---------- */
*, *::before, *::after { box-sizing: border-box; }

/* The canvas is dark: every page opens on a dark band, so while main fades
   between pages the gap reads as that band rather than a white flash. The
   white page colour lives on main instead (body stays see-through). */
html {
  background: var(--dark);
  scroll-behavior: smooth;
  scroll-padding-top: 120px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--body);
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--ink);
  caret-color: var(--accent);
}
main.page { background: var(--paper); }

::selection { background: var(--ink); color: #fff; }

/* Themed scrollbars */
html { scrollbar-color: var(--ink-faint) var(--paper-dim); }
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--paper-dim); }
::-webkit-scrollbar-thumb { background: var(--ink-faint); border: 3px solid var(--paper-dim); border-radius: 6px; }
::-webkit-scrollbar-thumb:hover { background: var(--ink-soft); }

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

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin: 0 0 0.5em;
  text-wrap: balance;
}

h1 { font-size: clamp(2.6rem, 6.5vw, 4.6rem); }
h2 { font-size: clamp(2rem, 4.2vw, 3.1rem); }
h3 { font-size: clamp(1.35rem, 2.4vw, 1.7rem); }
h4 { font-size: 1.2rem; }

p { margin: 0 0 1em; max-width: var(--measure); }
p:last-child { margin-bottom: 0; }

ul, ol { margin: 0 0 1em; padding-left: 1.25em; }
li { margin-bottom: 0.35em; }

a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.22em;
  transition: color var(--fast) var(--ease), text-decoration-color var(--fast) var(--ease);
}
a:hover { color: var(--ink-soft); text-decoration-thickness: 3px; }

:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}
.on-dark :focus-visible, .site-footer :focus-visible { outline-color: var(--accent-on-dark); }

/* Skip link */
.skip-link {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 200;
  padding: 0.7rem 1.2rem;
  background: var(--ink);
  color: #fff;
  font-weight: 600;
  text-decoration: none;
  border-radius: 0 0 var(--radius) var(--radius);
  transition: top var(--fast) var(--ease);
}
.skip-link:focus { top: 0; }

/* ---------- Layout helpers ---------- */
.wrap {
  width: min(1180px, 100% - 2 * var(--gutter));
  margin-inline: auto;
}

.section { padding-block: clamp(3.5rem, 9vw, 6.5rem); }
.section-dim { background: var(--paper-dim); }
.section-dark { background: var(--dark); color: #fff; }
.section-dark p { color: var(--dark-text); }
.section-dark [data-mb="home-oqm-p1"],
.section-dark [data-mb="home-oqm-p2"],
.section-dark [data-mb="home-oqm-p3"] { color: #fff; }
.section-dark h2, .section-dark h3 { color: #fff; }
.section-dark a { color: #fff; text-decoration-color: rgba(255, 255, 255, 0.5); }
.section-dark a:hover { color: var(--dark-text); }
.section-dark .link-arrow { border-bottom-color: var(--accent-on-dark); }

/* Split section header: title left, lede right */
.section-head {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 1.5rem clamp(2rem, 6vw, 5rem);
  align-items: end;
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
}
.section-head p { color: var(--ink-soft); }
.section-dark .section-head p { color: var(--dark-text); }
@media (max-width: 760px) {
  .section-head { grid-template-columns: 1fr; align-items: start; }
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.85rem 1.6rem;
  background: var(--ink);
  color: #fff;
  font-family: var(--body);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.btn .arrow { transition: transform var(--fast) var(--ease); }
.btn:hover { background: #000; border-color: #000; color: #fff; }
.btn:hover .arrow { transform: translateX(4px); }
.btn:active { background: #000; border-color: #000; }

/* Solid buttons invert on dark surfaces and over the hero photo */
.section-dark .btn:not(.btn-outline),
.hero .btn:not(.btn-outline),
.btn.on-dark:not(.btn-outline) {
  background: #fff;
  border-color: #fff;
  color: var(--ink);
}
.section-dark .btn:not(.btn-outline):hover,
.hero .btn:not(.btn-outline):hover,
.btn.on-dark:not(.btn-outline):hover {
  background: var(--dark-text);
  border-color: var(--dark-text);
  color: var(--ink);
}

.btn-outline {
  background: transparent;
  border-color: var(--ink);
  color: var(--ink);
}
.btn-outline:hover { background: var(--ink); border-color: var(--ink); color: #fff; }
.btn-outline:active { background: #000; }

.on-dark .btn-outline, .btn-outline.on-dark, .section-dark .btn-outline {
  border-color: #fff;
  color: #fff;
  background: transparent;
}
.on-dark .btn-outline:hover, .btn-outline.on-dark:hover, .section-dark .btn-outline:hover { background: #fff; color: var(--ink); }

/* Arrow text link */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-weight: 600;
  text-decoration: none;
  border-bottom: 2px solid var(--accent);
  padding-bottom: 2px;
}
.link-arrow .arrow { transition: transform var(--fast) var(--ease); }
.link-arrow:hover .arrow { transform: translateX(4px); }
.link-arrow:hover { color: var(--ink-soft); }

.arrow { flex: none; }

/* ---------- Header (detached bar floating over the hero) ---------- */
.site-header {
  position: fixed;
  top: var(--header-top);
  left: 0;
  right: 0;
  z-index: 100;
  pointer-events: none;
}

.header-bar {
  position: relative;
  pointer-events: auto;
  width: min(1280px, 100% - 2 * var(--gutter));
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.4vw, 2.2rem);
  min-height: var(--header-bar-h);
  padding: 5px 5px 5px clamp(1rem, 2vw, 1.6rem);
  background: #fff;
  /* hairline keeps the white bar defined where it floats over pale sections */
  box-shadow: 0 0 0 1px var(--line), 0 14px 34px -18px rgba(29, 33, 34, 0.65);
  transition: box-shadow var(--slow) var(--ease);
}
.site-header.scrolled .header-bar { box-shadow: 0 0 0 1px var(--line), 0 18px 40px -16px rgba(29, 33, 34, 0.8); }

.brand {
  display: inline-flex;
  align-items: center;
  flex: none;
  padding-right: clamp(1rem, 2vw, 1.6rem);
  border-right: 1px solid rgba(29, 33, 34, 0.28);
}
/* the logo artwork is dark grey; darken it to ink so it reads on the white bar */
.brand img { width: 196px; height: auto; filter: brightness(0.45); }

/* Nav sits immediately right of the brand, separated from it only by the
   brand's divider rule and the bar's gap. The auto margin on this side is what
   pushes the phone and CTA to the far right edge of the bar. */
.site-nav { margin-right: auto; }

.site-nav ul {
  display: flex;
  gap: clamp(1rem, 2.2vw, 2rem);
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-nav a {
  position: relative;
  display: inline-block;
  padding: 0.4rem 0;
  font-family: var(--display);
  /* Weight and tracking are set to the "LIA ENGINEERING" wordmark in the logo:
     Jost at a light-regular weight, opened up. Heavier and tighter than this
     and the nav stops reading as the same lettering as the mark beside it. */
  font-weight: 400;
  font-size: 0.9rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
}
/* underline draws in from left — site signature interaction */
.site-nav a::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 2px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--fast) var(--ease);
}
.site-nav a:hover::after, .site-nav a:focus-visible::after { transform: scaleX(1); }
.site-nav a[aria-current='page'] { color: var(--ink); }
.site-nav a[aria-current='page']::after { transform: scaleX(1); }

/* The contact route lives in the header button on desktop. Below the mobile
   breakpoint that button is hidden, so this item carries it in the drawer. */
.site-nav .nav-cta { display: none; }

.header-phone {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-weight: 700;
  font-size: 0.98rem;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.header-phone:hover { color: rgba(29, 33, 34, 0.66); }

/* About page: the phone number is set in the same lettering as the nav items
   — Jost, light-regular, opened up — so header type reads as one voice. */
.header-phone--nav-type span {
  font-family: var(--display);
  font-weight: 400;
  font-size: 0.9rem;
  letter-spacing: 0.1em;
}

.header-cta {
  align-self: stretch;
  display: inline-flex;
  align-items: center;
  flex: none;
  white-space: nowrap;
  padding: 0.6rem clamp(1.1rem, 1.8vw, 1.7rem);
  border: 0;
  border-radius: 0;
  background: var(--ink);
  color: #fff;
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.88rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.header-cta:hover, .header-cta:focus-visible { background: #000; color: #fff; }
.header-cta::after { display: none; }

/* Mobile nav (CSS-only disclosure, JS enhances aria) */
.nav-toggle-box { position: absolute; opacity: 0; width: 1px; height: 1px; }
.nav-toggle {
  display: none;
  margin-left: auto;
  padding: 0.6rem;
  border: 0;
  border-radius: 0;
  background: transparent;
  cursor: pointer;
}
.nav-toggle .bars { display: block; width: 22px; height: 14px; position: relative; }
.nav-toggle .bars::before, .nav-toggle .bars::after {
  content: '';
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  background: var(--ink);
  transition: transform var(--fast) var(--ease), opacity var(--fast) var(--ease);
}
.nav-toggle .bars::before { top: 0; }
.nav-toggle .bars::after { top: 12px; }
.nav-toggle-box:focus-visible + .nav-toggle { outline: 3px solid var(--accent); outline-offset: 2px; }

@media (max-width: 1080px) {
  .header-phone span.label { display: none; }
  .site-nav ul { gap: 1rem; }
  .header-cta { font-size: 0.8rem; letter-spacing: 0.06em; }
}
@media (max-width: 960px) {
  .header-phone { display: none; }
}
@media (max-width: 820px) {
  .nav-toggle { display: inline-flex; }
  .header-cta, .header-phone { display: none; }
  .brand { border-right: 0; padding-right: 0; }
  .site-nav {
    position: absolute;
    top: calc(100% - 5px);
    left: 0;
    right: 0;
    background: #fff;
    box-shadow: 0 18px 32px -18px rgba(29, 33, 34, 0.5);
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--slow) var(--ease);
  }
  .site-nav > ul { overflow: hidden; min-height: 0; }
  .site-nav ul {
    flex-direction: column;
    gap: 0;
    padding: 0 var(--gutter);
  }
  .site-nav li { margin: 0; border-top: 1px solid rgba(29, 33, 34, 0.22); }
  .site-nav li:first-child { border-top: 0; }
  .site-nav .nav-cta { display: block; }
  .site-nav a { display: block; padding: 0.9rem 0; font-size: 1rem; }
  .site-nav a::after { display: none; }
  .site-nav a[aria-current='page'] { box-shadow: inset 4px 0 0 var(--ink); padding-left: 0.8rem; }
  .nav-toggle-box:checked ~ .site-nav { grid-template-rows: 1fr; }
  .nav-toggle-box:checked ~ .site-nav > ul { padding-bottom: 0.75rem; }
  .nav-toggle-box:checked ~ .nav-toggle .bars::before { transform: translateY(6px) rotate(45deg); }
  .nav-toggle-box:checked ~ .nav-toggle .bars::after { transform: translateY(-6px) rotate(-45deg); }
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  display: grid;
  align-items: center;
  /* the photo fills the first screen, less the sliver the client strip keeps */
  min-height: calc(100vh - var(--client-strip-h));
  min-height: calc(100svh - var(--client-strip-h));
  background: var(--dark);
  color: #fff;
  overflow: hidden;
}
.hero-media {
  position: absolute;
  inset: 0;
  /* No scrim over the hero: the photos are simply dimmed instead, evenly across
     the frame, so the white copy clears WCAG AA wherever it sits and each shot
     keeps its own composition rather than fading into a dark wedge. The filter
     sits on the wrapper so all three slides share one layer. 0.42 is set by the
     worst case: blown highlights (parkade ceiling lights, the kitchen window)
     fall under text, and at this level even a pure-white patch holds 5.3:1. */
  filter: brightness(0.42);
}
.hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Hero slideshow: the slides stack and crossfade. The first carries
   .is-active in the markup, so without JS it simply stays as a still photo. */
.hero-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1200ms var(--ease);
  /* Keep each slide on its own compositor layer: without this the browser
     builds and tears down a viewport-sized layer at every crossfade, which
     lands as a dropped frame mid-scroll every 8 seconds. */
  will-change: opacity;
}
.hero-slide.is-active { opacity: 1; }
/* engineering grid overlay */
.hero-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.055) 1px, transparent 1px);
  background-size: 72px 72px;
  mask-image: linear-gradient(180deg, transparent 0%, #000 22%, #000 78%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 22%, #000 78%, transparent 100%);
  pointer-events: none;
}
/* The hero copy is one centred lockup: wordmark, lede, CTAs and proof marks
   stacked on a single axis and held to --hero-col so the block stays condensed
   on wide screens instead of running the full 1180px wrap. Every child centres
   itself off that column, so the same rules give the mobile stack for free. */
.hero-inner {
  position: relative;
  --hero-col: 42rem;
  text-align: center;
  /* vh-based, so a short laptop screen still leaves the client strip in view;
     the hero grid centres the copy on taller screens anyway */
  padding-block: clamp(1.25rem, 3vh, 3rem);
  padding-top: calc(clamp(1.25rem, 3vh, 3rem) + var(--header-clear));
}
/* Hero headline is the firm name, so it runs a step smaller than the
   global h1 scale — it needs presence, not the full display size. */
.hero h1 { max-width: 21ch; margin-inline: auto; margin-bottom: clamp(1rem, 2.2vh, 1.6rem); font-size: clamp(2.2rem, 5vw, 3.6rem); }
/* The headline is the firm name, so it has to be set in the same face as the
   logo wordmark and the nav beside it. A font-family override on this element
   is held in the visual editor and lands in mb-overrides.css (loaded last, with
   !important), so the display font is reasserted here. Drop this line once that
   override is cleared in the editor. */
.hero h1[data-mb='home-hero-title'] { font-family: var(--display) !important; }
/* The hero headline is the logo lockup itself. The image is sized in em off the
   h1 font-size above, so the wordmark's cap height lands on the same size the
   headline type was set at, and it keeps scaling with the same clamp. */
.hero h1.hero-logo { max-width: none; line-height: 0; }
.hero h1.hero-logo img,
.hero h1.hero-logo svg { display: block; width: min(100%, 11.4em, var(--hero-col, 100%)); height: auto; margin-inline: auto; }

/* Hero logo intro. The whole icon plays at double size: the arrow pops in
   alone at the centre of the screen at 2x, shoves right with a small bounce
   to push the striped mark out from behind it (still 2x, like a splash mark),
   then the assembled icon shrinks to its real size as it glides left into the
   lockup while the wordmark wipes in behind it. Pure CSS so it never gates
   content on JS; translate values are viewBox user units (527-wide) and both
   groups scale about the viewBox centre, so scale(2) translateX(175px) holds
   the arrow (centre x≈88) doubled at screen centre and translateX(202px) does
   the same for the whole mark (centre x≈61). overflow:visible on the svg lets
   the doubled icon draw beyond the 60-unit viewBox instead of being clipped
   — which is why an earlier oversize attempt looked unchanged. */
.logo-intro { overflow: visible; }
.logo-intro .li-mark,
.logo-intro .li-arrow,
.logo-intro .li-text { will-change: transform, opacity; }
.logo-intro .li-arrow {
  transform-box: view-box;
  transform-origin: 50% 50%;
  animation: li-intro-arrow 2.6s ease both;
}
.logo-intro .li-mark {
  transform-box: view-box;
  transform-origin: 50% 50%;
  animation: li-intro-mark 2.6s ease both;
}
.logo-intro .li-text {
  transform-box: fill-box;
  animation: li-intro-text 2.6s ease both;
}
@keyframes li-intro-arrow {
  0%, 6% { opacity: 0; transform: scale(2.6) translateX(175px); animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); }
  22%    { opacity: 1; transform: scale(2) translateX(175px); }
  34%    { transform: scale(2) translateX(175px); animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); }
  48%    { transform: scale(2) translateX(202px); }
  62%    { transform: scale(2) translateX(202px); animation-timing-function: cubic-bezier(0.3, 1.25, 0.45, 1); }
  92%, 100% { transform: scale(1) translateX(0); }
}
@keyframes li-intro-mark {
  0%, 34% { opacity: 0; transform: scale(2) translateX(232px); animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); }
  42%     { opacity: 1; }
  48%     { transform: scale(2) translateX(202px); }
  62%     { transform: scale(2) translateX(202px); animation-timing-function: cubic-bezier(0.3, 1.25, 0.45, 1); }
  92%, 100% { transform: scale(1) translateX(0); }
}
@keyframes li-intro-text {
  0%, 62% { opacity: 0; clip-path: inset(-12% 100% -12% -2%); transform: translateX(-30px); animation-timing-function: cubic-bezier(0.3, 1.25, 0.45, 1); }
  70%     { opacity: 1; }
  92%, 100% { opacity: 1; clip-path: inset(-12% -2% -12% -2%); transform: translateX(0); }
}
/* As the wordmark wipes in (62–92% of the 2.6s intro, i.e. ~1.6–2.4s), the
   rest of the page rises from below with the same settle-bounce easing, one
   top-to-bottom cascade on a 160ms beat: nav bar, hero copy, CTAs, marks,
   then the client-logo carousel. Scoped via :has(.logo-intro) so pages
   without the logo intro are untouched. */
body:has(.logo-intro) .site-header { animation: hero-rise 450ms cubic-bezier(0.3, 1.25, 0.45, 1) 1.6s both; }
.hero-inner:has(.logo-intro) .lede { animation: hero-rise 450ms cubic-bezier(0.3, 1.25, 0.45, 1) 1.6s both; }
.hero-inner:has(.logo-intro) .hero-ctas { animation: hero-rise 450ms cubic-bezier(0.3, 1.25, 0.45, 1) 1.6s both; }
.hero-inner:has(.logo-intro) .hero-marks { animation: hero-rise 450ms cubic-bezier(0.3, 1.25, 0.45, 1) 1.6s both; }
body:has(.logo-intro) .client-strip { animation: hero-rise 450ms cubic-bezier(0.3, 1.25, 0.45, 1) 1.6s both; }
@keyframes hero-rise {
  from { opacity: 0; transform: translateY(30px); }
  to { opacity: 1; transform: none; }
}
/* Intro plays once per browser session: index.html's head script adds
   .intro-seen when the visitor has already seen it (e.g. coming back from another page). */
html.intro-seen .logo-intro .li-mark,
html.intro-seen .logo-intro .li-arrow,
html.intro-seen .logo-intro .li-text,
html.intro-seen body:has(.logo-intro) .site-header,
html.intro-seen .hero-inner:has(.logo-intro) .lede,
html.intro-seen .hero-inner:has(.logo-intro) .hero-ctas,
html.intro-seen .hero-inner:has(.logo-intro) .hero-marks,
html.intro-seen body:has(.logo-intro) .client-strip { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .logo-intro .li-mark,
  .logo-intro .li-arrow,
  .logo-intro .li-text { animation: none; }
  body:has(.logo-intro) .site-header,
  .hero-inner:has(.logo-intro) .lede,
  .hero-inner:has(.logo-intro) .hero-ctas,
  .hero-inner:has(.logo-intro) .hero-marks,
  body:has(.logo-intro) .client-strip { animation: none; }
}
.hero .lede {
  font-size: clamp(1.02rem, 1.5vw, 1.14rem);
  color: var(--dark-text);
  /* narrower than the 54ch body measure: centred copy reads better short, and
     it keeps the lede inside the wordmark's width rather than out past it */
  max-width: min(var(--hero-col), 50ch);
  margin-inline: auto;
  margin-bottom: clamp(1.1rem, 2.4vh, 1.6rem);
}
.hero-ctas {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.9rem;
  margin-bottom: clamp(1.3rem, 3vh, 2rem);
}
.hero-marks {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem 2rem;
  padding-top: clamp(0.9rem, 2vh, 1.2rem);
  border-top: 1px solid var(--dark-line);
  max-width: var(--hero-col);
  list-style: none;
  padding-left: 0;
  margin: 0 auto;
}
.hero-marks li {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--dark-text);
}
/* The items are inline-flex, so a list marker would not render — the bullet
   is drawn instead, sized to sit optically with the 0.95rem text. */
.hero-marks li::before {
  content: '';
  flex: none;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent-on-dark);
}

/* Phone: the same centred stack, tightened. The two CTAs share one width so
   they read as a pair once they wrap, and the proof marks become a single
   centred column instead of a ragged two-then-one wrap. */
@media (max-width: 640px) {
  .hero-inner { --hero-col: 24rem; }
  .hero-ctas .btn { min-width: min(100%, 15rem); justify-content: center; }
  .hero-marks {
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
  }
  .hero-marks li { font-size: 0.9rem; }
}

/* The visual editor holds pixel `translate` nudges on these hero children (see
   mb-overrides.css, loaded last with !important). They were hand-set against
   one desktop width and push the copy hundreds of pixels sideways at every
   other size, so the centred layout above reasserts itself by specificity —
   the same tactic used for the h1 font-family override. Drop this block once
   those nudges are cleared in the editor. */
.hero-inner .lede[data-mb='home-hero-lede'],
.hero-inner .hero-marks[data-mb='home-hero-marks'],
.hero-ctas .btn[data-mb='home-hero-cta'],
.hero-ctas .btn[data-mb='home-hero-call'] { translate: none !important; }

/* Page banner (inner pages) */
.banner {
  position: relative;
  background: var(--dark);
  color: #fff;
  overflow: hidden;
}
/* Corner accents: the logo's L mark (stripes + arrow, no "ia"), top right as
   drawn and turned 180° bottom left (l-mark-bl.svg) so both corners point
   outward. On load they start as one enlarged pair framing the banner's
   centre, then split apart to their corners while the banner copy opens out
   from the middle between them (timed with the grid rise below). */
.banner {
  --lm-w: clamp(56px, 7vw, 96px);
  --lm-h: calc(var(--lm-w) * 59 / 121);
}
.banner::before,
.banner::after {
  content: "";
  position: absolute;
  width: var(--lm-w);
  aspect-ratio: 121 / 59;
  background: url("images/l-mark.svg") center / contain no-repeat;
  opacity: 0.22;
  pointer-events: none;
}
.banner::before {
  top: calc(var(--header-clear) + clamp(12px, 2vw, 24px));
  right: var(--gutter);
  transform-origin: 0 100%;
  animation: lm-split-tr 900ms var(--ease) 120ms both;
}
.banner::after {
  bottom: clamp(12px, 2vw, 24px);
  left: var(--gutter);
  background-image: url("images/l-mark-bl.svg");
  transform-origin: 100% 0;
  animation: lm-split-bl 900ms var(--ease) 120ms both;
}
@keyframes lm-split-tr {
  from {
    top: calc(50% - var(--lm-h) - 4px);
    right: calc(50% - var(--lm-w) - 4px);
    transform: scale(1.9);
    opacity: 0.5;
  }
}
@keyframes lm-split-bl {
  from {
    bottom: calc(50% - var(--lm-h) - 4px);
    left: calc(50% - var(--lm-w) - 4px);
    transform: scale(1.9);
    opacity: 0.5;
  }
}
.banner .banner-inner { animation: banner-open 900ms var(--ease) 120ms both; }
@keyframes banner-open {
  from { clip-path: inset(50% 50% 50% 50%); opacity: 0.4; }
  to { clip-path: inset(0 0 0 0); opacity: 1; }
}
.banner-inner {
  position: relative;
  padding-block: clamp(3.5rem, 8vw, 5.5rem);
  padding-top: calc(clamp(3.5rem, 8vw, 5.5rem) + var(--header-clear));
}
.banner h1 {
  margin-bottom: 0.6rem;
  /* Same lettering as the nav links (.site-nav a): Jost light-regular,
     opened up, uppercase — reads as the logo wordmark at display size. */
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.banner .lede { color: var(--dark-text); font-size: clamp(1.02rem, 1.5vw, 1.15rem); max-width: 58ch; }
.breadcrumbs {
  margin: 0 0 1.4rem;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  font-size: 0.9rem;
  color: var(--dark-text);
}
.breadcrumbs li { margin: 0; display: inline-flex; align-items: center; gap: 0.35rem; }
.breadcrumbs li + li::before { content: '/'; color: var(--dark-line); }
.breadcrumbs a { color: var(--dark-text); text-decoration-color: var(--dark-line); }
.breadcrumbs a:hover { color: #fff; }
.breadcrumbs [aria-current='page'] { color: var(--accent-on-dark); }

/* ---------- Title-block stat strip (engineering drawing motif) ---------- */
.stat-strip {
  border-block: 2px solid var(--ink);
  background: var(--paper);
}
.stat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
.stat {
  padding: 1.5rem 1.75rem;
  border-left: 1px solid var(--line);
}
.stat:first-child { border-left: 0; }
.stat .num {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2rem, 3.6vw, 2.9rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.stat .num em { font-style: normal; color: var(--accent-press); }
.stat .cap { display: block; margin-top: 0.35rem; color: var(--ink-soft); font-size: 0.95rem; }
@media (max-width: 760px) {
  .stat-grid { grid-template-columns: 1fr 1fr; }
  .stat { border-left: 0; border-top: 1px solid var(--line); }
  .stat:nth-child(-n + 2) { border-top: 0; }
  .stat:nth-child(even) { border-left: 1px solid var(--line); }
}

/* ---------- Cards & carousel ---------- */
/* Registered so the edge fade can be animated as a length, not snapped. */
@property --fade-l { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --fade-r { syntax: '<length>'; inherits: false; initial-value: 0px; }

/* The rail bleeds to the viewport edge, so this section clips sideways to keep
   that (and the reveal slide behind it) off the page's horizontal scroll. */
[data-mb='home-services'] { overflow-x: clip; }

/* ---------- Pinned services rail ----------
   The section holds the page still for the length of the card run: one pixel
   of downward scroll walks the six cards one pixel sideways, so you scroll
   through the whole service list on the way past it. JS measures the runway
   and adds .is-pinned; until then (no JS, short viewport, reduced motion) the
   section is an ordinary block and the track scrolls on its own. */
.pin-stage { position: relative; }
/* The stage carries its own vertical rhythm; the section keeps a little floor
   under the runway so the band below doesn't butt straight up to the rail. */
.is-pinned { padding-block: 0 clamp(1.5rem, 4vw, 3rem); }
.is-pinned .pin-stage {
  position: sticky;
  top: 0;
  min-height: 100vh;
  display: grid;
  align-content: center;
  padding-block: var(--header-clear) clamp(1.25rem, 3vh, 2rem);
}
/* Pinned, the stage gets exactly one screen: a stage taller than the viewport
   fails the fit test in script.js and the sideways run is dropped altogether.
   So the head sits tighter and the photos take a shallower crop here — enough
   to clear a 13" laptop rather than only a desktop monitor. */
.is-pinned .section-head { margin-bottom: clamp(1.25rem, 3vh, 2rem); }
.is-pinned .card img { aspect-ratio: 16 / 9; }
.is-pinned .card-body { padding: 1rem 1.2rem 1.15rem; }
/* Snap would fight a scroll position the page is driving frame by frame. */
.is-pinned .carousel-track {
  scroll-snap-type: none;
  scroll-behavior: auto;
  padding-block: 0.5rem 1rem;
}

.carousel { position: relative; }
.carousel-track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: clamp(270px, 31%, 360px);
  gap: 1.25rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  /* The rail runs out to the viewport edge so cards leave the frame instead of
     being sliced flat against the container. The matching end padding brings
     the last card back onto the page grid once you reach it. */
  margin-right: calc(50% - 50vw);
  padding-right: calc(50vw - 50%);
  /* the 0.25rem inset keeps hover lift and focus rings off the clip edge; the
     matching negative margin keeps card 1 flush with the section title */
  margin-left: -0.25rem;
  padding-block: 0.5rem 1.5rem;
  padding-left: 0.25rem;
  scroll-padding-inline: 0.25rem calc(50vw - 50%);
  scrollbar-width: thin;
}
.carousel-track > * { scroll-snap-align: start; }

/* With JS the native bar is replaced by the progress rail in the footer, and
   whichever edge still has cards behind it is softened rather than cut. */
.js .carousel-track {
  scrollbar-width: none;
  -ms-overflow-style: none;
  --fade-l: 0px;
  --fade-r: 0px;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent);
  mask-image: linear-gradient(to right, transparent, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent);
  transition: --fade-l var(--slow) var(--ease), --fade-r var(--slow) var(--ease);
}
.js .carousel-track::-webkit-scrollbar { width: 0; height: 0; }
/* Snap keeps the leading card flush left, so that edge only gets a hairline
   vignette — enough to read as "more behind" without dimming live copy. */
.js .carousel.can-prev .carousel-track { --fade-l: 1rem; }
.js .carousel.can-next .carousel-track { --fade-r: 5.5rem; }

/* Drag the rail with a mouse the way you would a physical set of boards. */
.js .carousel.can-prev .carousel-track,
.js .carousel.can-next .carousel-track { cursor: grab; }
.js .carousel-track.dragging {
  cursor: grabbing;
  scroll-snap-type: none;
  scroll-behavior: auto;
}
.js .carousel-track.dragging .card,
.js .carousel-track.dragging .card * { transition: none; }

.carousel-foot {
  display: flex;
  align-items: center;
  margin-top: 0.25rem;
}
/* The rail is the page's own scrollbar, rebuilt in the content column: same
   12px trough, same 3px-inset rounded thumb, same hover darkening as the
   themed bars at the top of this file. It reports a position only JS can
   read, so without JS the track's native bar does the job instead. */
.carousel-rail { display: none; }
.js .carousel-rail { display: block; }
.carousel-rail {
  position: relative;
  flex: 1;
  height: 20px;
  min-width: 2rem;
  background: var(--paper-dim);
  border-radius: 999px;
  overflow: hidden;
  cursor: pointer;
  touch-action: none;
  transform-origin: center;
  /* Overshooting curve: reaching the bar swells it past its hover size and it
     settles back, so picking it up feels sprung rather than switched on. */
  transition: transform 520ms cubic-bezier(0.34, 1.56, 0.64, 1),
    background var(--fast) var(--ease);
}
.carousel-rail:hover { transform: scaleY(1.3); }
/* Under the pointer the swell holds and stops springing: a bar still bouncing
   while you drag it reads as lag, which is the opposite of the point. */
.carousel-rail.dragging {
  transform: scaleY(1.3);
  transition: transform var(--fast) var(--ease), background var(--fast) var(--ease);
  cursor: grabbing;
}
.carousel-rail-fill {
  position: absolute;
  inset-block: 0;
  width: var(--rail-len, 100%);
  left: calc(var(--rail-pos, 0) * (100% - var(--rail-len, 100%)));
  background: var(--ink-faint);
  border: 4px solid var(--paper-dim);
  border-radius: 999px;
  background-clip: padding-box;
  /* Background only. A transition on left/width would put the thumb behind
     the pointer on every drag frame. */
  transition: background var(--fast) var(--ease);
}
.carousel-rail:hover .carousel-rail-fill,
.carousel-rail.dragging .carousel-rail-fill { background: var(--ink-soft); }
.carousel-rail:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

.card {
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border-radius: var(--radius);
  box-shadow: 0 6px 18px -8px rgba(29, 33, 34, 0.28);
  overflow: hidden;
  text-decoration: none;
  color: var(--ink);
  transition: transform var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 14px 28px -14px rgba(29, 33, 34, 0.35);
}
.card:active { transform: translateY(-2px); }
.card img { aspect-ratio: 3 / 2; object-fit: cover; width: 100%; }
.card-body { padding: 1.2rem 1.3rem 1.4rem; display: flex; flex-direction: column; gap: 0.4rem; flex: 1; }
.card-body h3 { margin: 0; font-size: 1.35rem; }
.card-body p { color: var(--ink-soft); font-size: 0.98rem; margin: 0; }
.card-more {
  margin-top: auto;
  padding-top: 0.9rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--ink);
}
.card-more .arrow { transition: transform var(--fast) var(--ease); color: var(--accent-press); }
.card:hover .card-more .arrow { transform: translateX(4px); }

/* Sector tiles */
.sector-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem;
}
@media (max-width: 980px) { .sector-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 540px) { .sector-grid { grid-template-columns: 1fr; } }
/* Phone: the sector tiles shrink onto a swipe track that reads as a ring.
   The tile in the middle faces you; script.js turns the ones either side away
   and back, like boards on a drum. No rail: the angled neighbours are the cue.
   Tablet and desktop keep the grid. */
.sector-carousel .carousel-foot { display: none; }
@media (max-width: 767px) {
  [data-mb='home-sectors'] { overflow-x: clip; }
  .sector-carousel .sector-grid {
    position: relative;
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 200px;
    gap: 8px;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scroll-behavior: smooth;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    /* full bleed, with end padding so the first and last tile can sit centred */
    margin-inline: calc(50% - 50vw);
    padding: 12px calc(50vw - 100px) 16px;
    scrollbar-width: none;
  }
  .sector-carousel .sector-grid::-webkit-scrollbar { width: 0; height: 0; }
  .sector-carousel .sector-grid.dragging { scroll-behavior: auto; scroll-snap-type: none; }
  .sector-carousel .sector {
    scroll-snap-align: center;
    scroll-snap-stop: always;
    transform-origin: 50% 50%;
    will-change: transform;
    backface-visibility: hidden;
  }
  .js .sector-carousel .sector-grid {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent);
    mask-image: linear-gradient(to right, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent);
  }
  .sector-carousel .sector figcaption { padding: 1.75rem 12px 12px; }
  .sector-carousel .sector figcaption strong { font-size: 17px; line-height: 1.2; }
  .sector-carousel .sector figcaption span { display: block; margin-top: 4px; font-size: 13px; line-height: 1.3; }
}
@media (max-width: 767px) and (prefers-reduced-motion: reduce) {
  .sector-carousel .sector-grid { scroll-behavior: auto; }
}
.sector {
  margin: 0;
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--dark);
}
.sector img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--slow) var(--ease), opacity var(--slow) var(--ease);
  opacity: 0.92;
}
.sector:hover img { transform: scale(1.04); opacity: 1; }
.sector figcaption {
  position: absolute;
  inset: auto 0 0 0;
  padding: 2.4rem 1.2rem 1.1rem;
  background: linear-gradient(180deg, transparent, rgba(29, 33, 34, 0.88) 62%);
  color: #fff;
}
.sector figcaption strong { font-family: var(--display); font-size: 1.3rem; font-weight: 700; display: block; }
.sector figcaption span { color: var(--dark-text); font-size: 0.92rem; }

/* ---------- Client logo strip, sitting directly under the hero ---------- */
.client-strip {
  background: var(--paper);
  padding: clamp(0.7rem, 1.5vw, 1rem) 0 clamp(0.3rem, 0.8vw, 0.6rem);
}
.client-strip-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem clamp(1rem, 3vw, 2rem);
  margin-bottom: clamp(0.35rem, 0.9vw, 0.6rem);
}
.client-strip-head > div {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem clamp(1rem, 3vw, 2rem);
}
.client-strip-head h2 {
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin: 0;
}
.client-strip-head p {
  margin: 0;
  color: var(--ink-soft);
  font-size: 0.95rem;
  max-width: 52ch;
}

/* Client logo marquee — scrolls itself, no controls, no scrollbar, no framing */
.logo-grid {
  position: relative;
  overflow: hidden;
  /* clip, not hidden: keeps the strip from ever being scrolled off-position
     when a browser scrolls a focused or found logo into view */
  overflow: clip;
}
/* Fade the moving logos out at both edges instead of cutting them off.
   Painted as gradient overlays on the strip's solid paper background, not as
   a mask on .logo-grid: content animating under an ancestor mask forces the
   whole strip to repaint every frame, while overlays let the marquee's
   transform run entirely on the compositor. Scoped to .js because only the
   marquee moves — the no-JS fallback is a static wrapped row. */
.js .logo-grid::before,
.js .logo-grid::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: 7%;
  z-index: 1;
  pointer-events: none;
}
.js .logo-grid::before { left: 0; background: linear-gradient(90deg, var(--paper), transparent); }
.js .logo-grid::after { right: 0; background: linear-gradient(270deg, var(--paper), transparent); }
/* Without JS the row simply wraps: every logo stays visible and static. */
.logo-track { display: flex; flex-wrap: wrap; }
/* With JS the row is duplicated, so translating exactly half loops seamlessly. */
.js .logo-track {
  flex-wrap: nowrap;
  width: max-content;
  animation: logo-marquee 87s linear infinite;
}
@keyframes logo-marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

.logo-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.8rem 1.2rem;
  min-height: 72px;
  flex: 0 0 clamp(170px, 20vw, 230px);
}
.logo-cell img {
  max-height: 44px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  /* Logos rest at 40% colour and fade up to full colour on hover. The
     transition lives on the base rule so it eases both in and back out. */
  filter: grayscale(0.6);
  opacity: 0.82;
  transition: filter var(--slow) var(--ease), opacity var(--slow) var(--ease);
}
.logo-cell:hover img {
  filter: grayscale(0);
  opacity: 1;
}
/* Kokoro is a stacked two-line lockup, so it needs a little more height than
   the single-line wordmarks to read at the same optical size. Still inside the
   72px cell, so the strip height is unchanged. */
.logo-cell img[data-mb='img-byl3'] { max-height: 50px; }
/* Sandman's group lockup is the widest artwork in the row — S mark, two-line
   wordmark and crest, 6.1:1 — so in a cell sized for single-line wordmarks it
   runs out of width at barely 31px tall and its type reads half the size of the
   marks beside it. Widening just this cell lets it reach the same 44px cap as
   everything else; the row keeps one optical height and its 76px bounds. */
.logo-cell[data-mb='home-logo-sandman'] { flex-basis: min(308px, 80vw); }

/* ---------- Split feature rows ---------- */
.split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
.split.flip > .split-media { order: -1; }
@media (max-width: 860px) {
  .split, .split.flip { grid-template-columns: 1fr; }
  .split.flip > .split-media { order: 0; }
}
.split-media img {
  width: 100%;
  border-radius: var(--radius);
  box-shadow: 0 22px 44px -22px rgba(29, 33, 34, 0.45);
}
/* Founder portrait is a transparent cut-out: no card shadow, and on two-column
   layouts the torso sits flush on the bottom edge of the grey band. */
.split-media img[data-mb='img-bzhc'] { display: block; border-radius: 0; box-shadow: none; }
@media (min-width: 861px) {
  .section[data-mb='about-founder'] { padding-bottom: 0; }
}
/* About story: heading left, copy right, laid out for real. The editor holds
   `translate` nudges on these paragraphs (mb-overrides.css) that faked this
   two-column look but left their original space empty under the heading;
   the grid takes over and the nudges are cancelled by specificity, as with
   the home hero. The media column has no picture, so it is dropped. */
.section[data-mb='about-story'] { padding-block: clamp(2.5rem, 6vw, 4.5rem); }
.split[data-mb='div-bzi9'] { grid-template-columns: 1fr; }
.split[data-mb='div-bzi9'] > .split-media { display: none; }
@media (min-width: 861px) {
  .split-body[data-mb='div-bzia'] {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(2rem, 5vw, 4.5rem);
    align-items: start;
  }
  .split-body[data-mb='div-bzia'] > h2 { grid-row: 1 / span 4; }
  .split-body[data-mb='div-bzia'] > p { grid-column: 2; translate: none !important; }
}
.split-body h2 { margin-bottom: 0.8rem; }
.split-body p { color: var(--ink-soft); }
.split-body ul { color: var(--ink-soft); columns: 1; }

/* Checklist: plain bulleted list. Disc is set explicitly so the ordered
   career-history list carries the same bullet as the unordered ones. */
.checklist {
  list-style: disc;
  padding-left: 1.25em;
}
.checklist li {
  padding-left: 0;
  margin-bottom: 0.5rem;
}

/* ---------- Affiliations (about) ---------- */
/* Logo cards: every mark sits in the same fixed-height tile so wide wordmarks
   (CaGBC) and tall lockups (EGBC, ASPE) read at one optical size. */
.affil-grid {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
}
.affil {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin: 0;
  padding: 1.5rem 1.5rem 1.4rem;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.affil-logo {
  display: flex;
  align-items: center;
  height: 72px;
  margin-bottom: 1rem;
  padding-bottom: 1.25rem;
  box-sizing: content-box;
  border-bottom: 1px solid var(--line);
}
.affil-logo img {
  width: auto;
  height: auto;
  max-width: min(100%, 240px);
  max-height: 100%;
}
.affil-role {
  font-family: var(--display);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.affil-name {
  color: var(--ink);
  font-size: 1.0625rem;
  line-height: 1.35;
  overflow-wrap: anywhere;
}
@media (min-width: 768px) and (max-width: 1023px) {
  .affil-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .affil { padding: 1.25rem; }
  .affil-logo { height: 56px; margin-bottom: 0.75rem; padding-bottom: 1rem; }
}
.affil-short { display: none; }
@media (max-width: 767px) {
  .affil-full { display: none; }
  .affil-short { display: inline; }
  .section[data-mb='about-affiliations'] { padding-block: 28px; }
  [data-mb='about-affiliations'] .section-head { gap: 8px; margin-bottom: 16px; }
  [data-mb='about-affiliations'] .section-head p { font-size: 15px; line-height: 1.4; }
  .affil-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .affil { padding: 12px; gap: 2px; }
  .affil-logo { height: 36px; margin-bottom: 8px; padding-bottom: 8px; }
  .affil-role { font-size: 11px; letter-spacing: 0.1em; }
  .affil-name { font-size: 13px; line-height: 1.3; }
}

/* ---------- Services page ---------- */
/* The strip sits under the banner, then pins just below the floating header
   once the page scrolls past it, so the service list stays one tap away. */
.subnav {
  /* how much shorter than the header bar the docked box is, each end */
  --dock-trim: clamp(12px, 2vw, 28px);
  --dock-inset: calc((100% - min(1280px, 100% - 2 * var(--gutter))) / 2 + var(--dock-trim));
  position: sticky;
  top: var(--header-clear);
  z-index: 90;
}
/* The strip's paper and bottom rule live on ::before so they can narrow; the
   two side rules on ::after stand folded flat until the strip docks. */
.subnav::before,
.subnav::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.subnav::before {
  z-index: -1;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 14px 30px -22px rgba(29, 33, 34, 0);
  /* undocking: the sides fold down first, then the rule runs back out */
  transition: left 300ms var(--ease) 180ms, right 300ms var(--ease) 180ms,
    box-shadow var(--slow) var(--ease);
}
.subnav::after {
  left: var(--dock-inset);
  right: var(--dock-inset);
  border-inline: 1px solid var(--line);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 180ms var(--ease);
}
.subnav .wrap { transition: width 300ms var(--ease) 180ms; }

/* Docked under the header (script.js adds .is-docked): the bottom rule draws
   in evenly from both sides to just short of the header's width, then its
   two ends fold up to meet the header — one outlined box hanging off it. */
.subnav.is-docked::before {
  left: var(--dock-inset);
  right: var(--dock-inset);
  box-shadow: 0 14px 30px -22px rgba(29, 33, 34, 0.55);
  transition: left 300ms var(--ease), right 300ms var(--ease),
    box-shadow var(--slow) var(--ease) 300ms;
}
.subnav.is-docked::after {
  transform: scaleY(1);
  transition: transform 240ms var(--ease) 280ms;
}
.subnav.is-docked .wrap {
  width: min(1180px, 100% - 2 * var(--gutter) - 2 * var(--dock-trim));
  transition: width 300ms var(--ease);
}
/* With the strip hanging under it, the header's shadow eases off so it
   doesn't fall heavily across the tabs. */
.site-header.subnav-docked .header-bar {
  box-shadow: 0 0 0 1px var(--line), 0 8px 18px -14px rgba(29, 33, 34, 0.35);
}
.subnav ul {
  display: flex;
  gap: 0.25rem;
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.subnav ul::-webkit-scrollbar { display: none; }
.subnav li { margin: 0; flex: none; }
.subnav a {
  display: block;
  padding: 0.9rem 0.9rem;
  font-size: 0.95rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--ink-soft);
  border-bottom: 3px solid transparent;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
  white-space: nowrap;
}
.subnav a:hover { color: var(--ink); border-bottom-color: var(--line); }
.subnav a.active { color: var(--ink); border-bottom-color: var(--accent); }

/* A subnav jump has to clear the header and the pinned strip under it. Phones
   land the service just below the strip (the screen is too short to spare
   more); larger screens drop it lower, near eye level (script.js centres it
   exactly; this margin is the no-JS fallback). */
/* (Added on top of html's 120px scroll-padding, hence the subtraction.) */
.service-block { scroll-margin-top: calc(var(--header-clear) + 58px + 12px - 120px); }
@media (min-width: 768px) {
  .service-block { scroll-margin-top: 12svh; }
}
/* Side-sliding reveals wait 36px off their mark; every page clips sideways so
   that wait never widens it and a phone can't be dragged left/right (clip,
   unlike hidden, keeps the subnav's sticky pinning intact). */
main.page { overflow-x: clip; }
.service-block + .service-block { margin-top: clamp(3.5rem, 8vw, 6rem); }

/* ---------- Projects ---------- */
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.25rem;
}
@media (max-width: 980px) { .gallery { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .gallery { grid-template-columns: 1fr; } }
.gallery figure { margin: 0; position: relative; border-radius: var(--radius); overflow: hidden; }
.gallery img { width: 100%; aspect-ratio: 79 / 46; object-fit: cover; transition: transform var(--slow) var(--ease); }
.gallery figure:hover img { transform: scale(1.035); }
.gallery figcaption {
  position: absolute;
  inset: auto 0 0 0;
  padding: 2rem 1rem 0.85rem;
  background: linear-gradient(180deg, transparent, rgba(29, 33, 34, 0.85) 70%);
  color: #fff;
  font-size: 0.92rem;
  font-weight: 600;
}

.project-cat { border-top: 1px solid var(--line); padding-top: 2.2rem; margin-top: 2.2rem; }
.project-cat:first-of-type { border-top: 0; padding-top: 0; margin-top: 0; }
.project-cat h3 {
  display: flex;
  align-items: baseline;
  gap: 0.7rem;
}
.project-cat h3 .count {
  font-family: var(--body);
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink-faint);
}
.project-cols {
  columns: 2;
  column-gap: 3rem;
  color: var(--ink-soft);
  list-style: none;
  padding: 0;
}
.project-cols li {
  break-inside: avoid;
  padding: 0.45rem 0 0.45rem 1.1rem;
  border-left: 2px solid var(--line);
  margin: 0 0 0.35rem;
}
@media (max-width: 760px) { .project-cols { columns: 1; } }

.upcoming-list { list-style: none; padding: 0; counter-reset: up; }
.upcoming-list li {
  counter-increment: up;
  display: flex;
  align-items: baseline;
  gap: 1.1rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--dark-line);
  margin: 0;
  font-size: clamp(1.1rem, 2vw, 1.35rem);
  font-family: var(--display);
  font-weight: 600;
}
.upcoming-list li::before {
  content: counter(up, decimal-leading-zero);
  color: var(--accent-on-dark);
  font-variant-numeric: tabular-nums;
  font-size: 0.9em;
}

/* ---------- Tables ---------- */
table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
th, td {
  text-align: left;
  padding: 0.8rem 1rem 0.8rem 0;
  border-bottom: 1px solid var(--line);
}
th[scope='row'] { font-weight: 600; }
td { color: var(--ink-soft); }

/* CTA band that follows another dark section */
.cta-tight { padding-top: 0; }
/* Projects CTA follows a light section: give the heading room on phones */
@media (max-width: 767px) {
  .cta-tight[data-mb="projects-cta"] { padding-top: 56px; }
}

/* ---------- FAQ ---------- */
.faq-list { max-width: 820px; }
.faq-list details {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--paper);
  margin-bottom: 0.75rem;
  transition: border-color var(--fast) var(--ease);
}
.faq-list details:hover { border-color: var(--ink-soft); }
.faq-list details[open] { border-color: var(--ink); }
.faq-list summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.05rem 1.25rem;
  font-weight: 600;
  font-size: 1.05rem;
  cursor: pointer;
  list-style: none;
}
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary .ind {
  flex: none;
  width: 14px;
  height: 14px;
  position: relative;
  color: var(--accent-press);
}
.faq-list summary .ind::before, .faq-list summary .ind::after {
  content: '';
  position: absolute;
  background: currentColor;
  transition: transform 260ms cubic-bezier(0.18, 1.5, 0.4, 1);
}
.faq-list summary .ind::before { left: 0; top: 6px; width: 14px; height: 2px; }
.faq-list summary .ind::after { left: 6px; top: 0; width: 2px; height: 14px; }
.faq-list details[open] summary .ind::after { transform: scaleY(0); }
.faq-list .faq-a { padding: 0 1.25rem 1.2rem; color: var(--ink-soft); }

/* The plus/minus pops when the row is hovered — same spring as the hero CTAs. */
.faq-list summary .ind {
  transition: transform 260ms cubic-bezier(0.18, 1.5, 0.4, 1);
}
.faq-list details:hover summary .ind,
.faq-list summary:focus-visible .ind { transform: scale(1.3); }

/* script.js springs the row's height open and eases it shut; while that runs
   the box has to clip its own content. Without JS the native toggle stands. */
.faq-list details.faq-moving { overflow: clip; }

/* ---------- Forms ---------- */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
.form-grid .full { grid-column: 1 / -1; }
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }

.field label {
  display: block;
  font-weight: 600;
  font-size: 0.95rem;
  margin-bottom: 0.35rem;
}
.field .hint { color: var(--ink-faint); font-weight: 400; }
.field input, .field textarea, .field select {
  width: 100%;
  padding: 0.75rem 0.9rem;
  font: inherit;
  color: var(--ink);
  background: var(--paper);
  border: 1.5px solid var(--ink-faint);
  border-radius: var(--radius);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.field input::placeholder, .field textarea::placeholder { color: var(--ink-faint); }
.field input:hover, .field textarea:hover, .field select:hover { border-color: var(--ink-soft); }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(29, 33, 34, 0.28);
}
.field.invalid input, .field.invalid textarea { border-color: #b3261e; }
.field-error {
  display: none;
  margin-top: 0.35rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: #b3261e;
}
.field.invalid .field-error { display: block; }

/* Collection notice under the submit button */
.form-note {
  margin-top: 1rem;
  max-width: 48ch;
  color: var(--ink-soft);
  font-size: 0.9rem;
}

/* ---------- Contact page ---------- */
.contact-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.25rem;
}
@media (max-width: 860px) { .contact-cards { grid-template-columns: 1fr; } }
.contact-card {
  border: 1px solid var(--line);
  border-top: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 1.5rem;
}
.contact-card h3 { margin-bottom: 0.4rem; }
.contact-card p { color: var(--ink-soft); font-size: 0.98rem; }
.contact-card .big {
  font-family: var(--display);
  font-size: 1.45rem;
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 2px solid var(--accent);
}
.contact-card .big:hover { color: var(--ink-soft); }

/* ---------- CTA band ---------- */
.cta-band { text-align: left; }
.cta-band .wrap {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
  gap: 2rem clamp(2rem, 6vw, 5rem);
  align-items: center;
}
@media (max-width: 820px) { .cta-band .wrap { grid-template-columns: 1fr; } }
.cta-band h2 { margin-bottom: 0.6rem; }
.cta-band .cta-actions { display: flex; flex-wrap: wrap; gap: 0.9rem; align-items: center; }
.cta-band .trust {
  margin-top: 1.4rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--dark-line);
  color: var(--dark-text);
  font-size: 0.95rem;
  max-width: 60ch;
}

/* ---------- Legal pages (privacy policy) ---------- */
/* A single reading column: measure stays short, headings step down from the
   section scale so a long policy scans as a list of questions. */
.banner-meta {
  margin-top: 1rem;
  color: var(--dark-text);
  font-size: 0.92rem;
}
.legal { max-width: 72ch; }
.legal h3 { margin-top: 2.6rem; }
.legal > :first-child { margin-top: 0; }
.legal p, .legal li { color: var(--ink-soft); }
.legal strong { color: var(--ink); }
.legal .checklist { margin-bottom: 1em; }

/* ---------- Footer ---------- */
.site-footer {
  background: var(--dark);
  color: var(--dark-text);
  padding-block: clamp(3rem, 6vw, 4.5rem) 1.75rem;
  border-top: 4px solid var(--dark-line);
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 2.5rem;
  padding-bottom: 2.5rem;
}
@media (max-width: 860px) { .footer-grid { grid-template-columns: 1fr; gap: 2rem; } }
.site-footer h2 {
  color: #fff;
  font-size: 1.15rem;
  letter-spacing: 0.04em;
  margin-bottom: 0.9rem;
}
.site-footer p { color: var(--dark-text); font-size: 0.98rem; }
.site-footer a { color: #fff; text-decoration-color: rgba(255, 255, 255, 0.5); }
.site-footer a:hover { color: var(--dark-text); }
.footer-brand img { margin-bottom: 1.1rem; width: 196px; height: auto; }
.footer-nav ul, .footer-contact ul { list-style: none; margin: 0; padding: 0; }
.footer-nav li, .footer-contact li { margin-bottom: 0.55rem; }
.footer-contact .addr { font-style: normal; }
.footer-social { display: flex; gap: 0.8rem; margin-top: 1.2rem; }
.footer-social a {
  display: inline-flex;
  width: 40px;
  height: 40px;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--dark-line);
  border-radius: 50%;
  color: #fff;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.footer-social a:hover { border-color: #fff; background: #fff; color: var(--ink); }
.footer-legal {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2rem;
  justify-content: space-between;
  padding-top: 1.5rem;
  border-top: 1px solid var(--dark-line);
  font-size: 0.9rem;
}
.footer-legal p { margin: 0; font-size: 0.9rem; }
/* Phones: the legal row's links (privacy, site credit) get a full tap height. */
@media (max-width: 767px) {
  .footer-legal { gap: 0 2rem; }
  .footer-legal a { display: inline-flex; align-items: center; min-height: 48px; }
}

/* ---------- Motion: page transitions (slide) & scroll reveals ---------- */
/* Entrance runs as pure CSS so it cannot hide content when JS fails:
   it always plays to completion on load. */
/* main fades; its children carry the slide (on `translate`, so the scroll
   reveals' `transform` is untouched) inside main's sideways clip, so the
   slide never widens the page. */
main.page { animation: page-fade-in 420ms var(--ease) both; }
main.page > * { animation: page-slide-in 420ms var(--ease) both; }
@keyframes page-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes page-slide-in { from { translate: 48px 0; } to { translate: none; } }
body.page-exit main.page { animation: page-fade-out 220ms var(--ease) both; }
body.page-exit main.page > * { animation: page-slide-out 220ms var(--ease) both; }
@keyframes page-fade-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes page-slide-out { from { translate: none; } to { translate: -48px 0; } }
/* Phones keep the same transition as a plain fade: no sideways slide there. */
@media (max-width: 767px) {
  main.page > *, body.page-exit main.page > * { animation: none; }
}

/* Banner grid entrance (inner pages): the grid wipes up from the bottom edge,
   then a brighter copy of the lines flashes once and fades back. Pure CSS,
   ends on the resting grid, so nothing depends on it finishing. */
.banner .hero-grid { animation: grid-rise 900ms var(--ease) 120ms both; }
.banner .hero-grid::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.13) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.13) 1px, transparent 1px);
  background-size: inherit;
  opacity: 0;
  animation: grid-flash 1100ms ease-out 520ms both;
}
@keyframes grid-rise {
  from { clip-path: inset(100% 0 0 0); }
  to { clip-path: inset(0 0 0 0); }
}
@keyframes grid-flash {
  0% { opacity: 0; }
  25% { opacity: 1; }
  100% { opacity: 0; }
}

/* Scroll reveals: only when JS present (html.js), sections slide from
   alternating sides. Content stays visible without JS. */
.js .reveal { opacity: 0; transition: opacity 560ms var(--ease), transform 560ms var(--ease); }
.js .reveal-l { transform: translateX(-36px); }
.js .reveal-r { transform: translateX(36px); }
.js .reveal.in { opacity: 1; transform: none; }

/* ---------- Custom cursor: the arrow from the Lia mark ----------
   JS swaps the native pointer for the logo arrow on pointer-fine screens
   (html.has-cursor). Two copies of the glyph stack: the white one is clipped
   to whatever dark surface sits under the pointer, the black one to the light
   surface, so across a seam between sections the arrow splits colour at the
   boundary. Text fields keep the native I-beam; touch and no-JS are untouched. */
html.has-cursor,
html.has-cursor body * { cursor: none !important; }
html.has-cursor input,
html.has-cursor textarea,
html.has-cursor select { cursor: auto !important; }

.cursor-arrow {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--fast) var(--ease);
}
.cursor-arrow.is-on { opacity: 1; }
.ca-box {
  position: relative;
  /* grow and press from the arrow's tip, which rides the real hotspot */
  transform-origin: 100% 0;
  transition: transform var(--fast) var(--ease);
}
.cursor-arrow.is-link .ca-box { transform: scale(1.3); }
.cursor-arrow.is-down .ca-box { transform: scale(0.88); }
.ca-box svg { display: block; }
.ca-box svg + svg { position: absolute; inset: 0; }
.ca-w path { fill: #fff; }
.ca-k path { fill: var(--ink); }
/* The mark's three stripe lines ride tucked behind the arrow; a press pops
   them out to their place in the full logo (nearest line first), and they
   tuck back together on release. px in an SVG transform = viewBox units. */
.ca-line {
  opacity: 0;
  transform: translateX(46px);
  transition: transform 220ms var(--ease), opacity 140ms var(--ease);
}
.cursor-arrow.is-down .ca-line {
  opacity: 1;
  transform: none;
  transition: transform 260ms cubic-bezier(0.18, 1.5, 0.4, 1), opacity 100ms var(--ease);
}
.cursor-arrow.is-down .ca-l2 { transition-delay: 35ms; }
.cursor-arrow.is-down .ca-l1 { transition-delay: 70ms; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  main.page, body.page-exit main.page,
  main.page > *, body.page-exit main.page > * { animation: none; }
  .banner .hero-grid, .banner .hero-grid::after,
  .banner::before, .banner::after, .banner .banner-inner { animation: none; }
  .js .reveal, .js .reveal-l, .js .reveal-r { opacity: 1; transform: none; transition: none; }
  .subnav::before, .subnav::after, .subnav .wrap { transition: none !important; }
  /* Marquee stops and falls back to a static wrapped row so no logo is clipped. */
  .js .logo-track {
    animation: none !important;
    flex-wrap: wrap;
    width: auto;
    transform: none;
  }
  .js .logo-track > [aria-hidden='true'] { display: none; }
  /* The row no longer moves, so nothing should fade its edges. */
  .js .logo-grid::before, .js .logo-grid::after { content: none; }
  /* The rail keeps its darkening hover state, but drops the spring. */
  .carousel-rail:hover, .carousel-rail.dragging { transform: none; }
  /* FAQ rows open instantly (script.js skips the spring) and the plus/minus
     holds still on hover. */
  .faq-list details:hover summary .ind,
  .faq-list summary:focus-visible .ind { transform: none; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ---------- Utilities ---------- */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.muted { color: var(--ink-soft); }
.mt-2 { margin-top: 2rem; }
.mt-3 { margin-top: 3rem; }
