/* ==========================================================================
   FINAL PHASE CONCRETE
   Design system. Built around the logo: black, charcoal #434949, red #DE181C.
   Sections are composed, not stacked. Type and material do the work.
   ========================================================================== */

/* --------------------------------------------------------------- 1. FONTS */

@font-face {
  font-family: 'Archivo';
  src: url('../fonts/archivo-latin.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  src: url('../fonts/inter-latin.woff2') format('woff2-variations');
  font-weight: 300 700;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --------------------------------------------------------------- 2. TOKENS */

:root {
  /* Surface */
  --ink:        #0A0B0C;
  --ink-2:      #141617;
  --ink-3:      #1E2122;
  --charcoal:   #434949;   /* sampled from the logo wordmark */
  --concrete:   #8C8F8E;
  --concrete-2: #B4B6B3;
  --bone:       #F4F3F0;
  --bone-2:     #333836;
  --white:      #FFFFFF;

  /* Accent, sampled from the logo */
  --red:        #DE181C;
  --red-deep:   #B41316;
  --red-glow:   rgba(222, 24, 28, 0.28);

  /* The brand red is 4.45:1 on bone and 3.99:1 on ink, so it clears WCAG AA for
     large display type but not for small text. These two shift lightness only,
     holding the hue at 358.8 degrees, so small red text reads as the same colour
     while meeting 4.5:1. Use --red for fills and display type, these for copy. */
  --red-text:      #E82A2E;   /* marks and display type, 3.32:1 on the ground */
  --red-text-dark: #E82A2E;   /* small text on dark surfaces, 4.50:1 on ink */

  /* The light ground is a matte grey rather than the near-white bone. Bone is
     still the colour of type on dark surfaces; it is no longer the colour of
     the page.

     The ground is dark, so every colour that used to sit on a light page is
     inverted below. Two consequences worth knowing:

     A mid grey was not an option. At #787B78 the darkest usable text manages
     4.60:1 and the lightest 3.86:1, so neither direction clears the bar. A
     ground either commits to light type or to dark type.

     Brand red cannot be small text here. #E82A2E measures 3.32:1 on this
     ground against a 4.5 floor, and no saturated red at this hue clears it. So
     red is a mark and a display colour on this site now, and the small text
     that used to turn red turns bone instead. */
  --matte:      #262A29;
  /* Raised light surfaces: cards, inputs. A step up from the ground rather
     than a jump to white, so nothing on the page is stark white any more.
     The step is only 1.16:1 against the ground, so these surfaces keep their
     borders and shadows to stay legible as separate objects. */
  --matte-2:    #1B1E1D;

  /* Semantic */
  --bg:         var(--matte);
  --fg:         var(--bone);
  --muted:      #B4B6B3;
  --rule:       rgba(244, 243, 240, 0.16);
  --rule-soft:  rgba(244, 243, 240, 0.075);

  /* Type */
  --display: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --body:    'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;

  /* Capped by height as well as width. Sized on width alone this stayed at
     118px on a 720px-tall screen and pushed the last 314px of the hero below
     the fold. */
  --fs-mega:  clamp(2.25rem, min(8.2vw, 11.2vh), 8.5rem);
  --fs-h1:    clamp(2.5rem, 6.6vw, 6.5rem);
  --fs-h2:    clamp(2rem, 4.4vw, 4rem);
  --fs-h3:    clamp(1.375rem, 2.1vw, 1.875rem);
  --fs-h4:    clamp(1.125rem, 1.5vw, 1.375rem);
  --fs-lead:  clamp(1.0625rem, 1.45vw, 1.3125rem);
  --fs-body:  clamp(1rem, 1.05vw, 1.0625rem);
  --fs-small: 0.875rem;
  --fs-micro: 0.75rem;

  /* Space */
  --gutter:  clamp(1.25rem, 4.2vw, 4.5rem);
  --section: clamp(4.5rem, 10vw, 10rem);
  --stack:   clamp(1.5rem, 3vw, 2.75rem);
  --maxw:    88rem;
  --measure: 34rem;

  /* Motion */
  --ease:     cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in:  cubic-bezier(0.62, 0, 0.35, 1);
  --t-fast:   0.22s;
  --t-mid:    0.5s;
  --t-slow:   0.9s;

  --header-h: 92px;
}

@media (max-width: 900px) { :root { --header-h: 68px; } }

/* Narrow screens: hold the authored hero line breaks rather than letting a
   phrase split across lines. */
@media (max-width: 430px) {
  /* Capped at 40px: measured as the largest size at which the longest authored
     hero line still holds on one line inside the 375px gutter. */
  :root { --fs-mega: clamp(1.9rem, 10.6vw, 2.5rem); }
  .hero__title { letter-spacing: -0.03em; }
}

/* --------------------------------------------------------------- 3. RESET */

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--body);
  font-size: var(--fs-body);
  line-height: 1.68;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

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

h1, h2, h3, h4, h5, h6 { margin: 0; font-family: var(--display); font-weight: 700; }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; }

a { color: inherit; text-decoration: none; }

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

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

::selection { background: var(--red); color: var(--white); }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  background: var(--ink);
  color: var(--white);
  padding: 1rem 1.5rem;
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.skip-link:focus { left: 0; }

.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;
}

/* --------------------------------------------------------- 4. TYPE STYLES */

.u-mega, .u-h1, .u-h2, .u-h3 {
  font-family: var(--display);
  line-height: 0.92;
  letter-spacing: -0.028em;
  text-wrap: balance;
}

.u-mega {
  font-size: var(--fs-mega);
  font-weight: 800;
  font-stretch: 108%;
  line-height: 0.94;
  letter-spacing: -0.035em;
  text-transform: uppercase;
}

.u-h1 { font-size: var(--fs-h1); font-weight: 800; font-stretch: 104%; text-transform: uppercase; }
.u-h2 { font-size: var(--fs-h2); font-weight: 700; text-transform: uppercase; }
/* For a heading whose longest authored line must not wrap inside its column.
   Sized so the longest line ("WE WILL TELL YOU WHAT IT NEEDS.") holds on one
   line at every width down to the point the layout stacks. */
.u-h2--fit { font-size: clamp(1.25rem, 2.35vw, 2.05rem); letter-spacing: -0.022em; }
@media (max-width: 900px) { .u-h2--fit { font-size: clamp(1.4rem, 5.2vw, 2rem); } }
.u-h3 { font-size: var(--fs-h3); font-weight: 700; line-height: 1.14; letter-spacing: -0.015em; }
.u-h4 { font-size: var(--fs-h4); font-weight: 600; line-height: 1.25; letter-spacing: -0.01em; }

.u-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
}
.u-eyebrow::before {
  content: '';
  width: 2rem; height: 2px;
  background: var(--red);
  flex: none;
}
.u-eyebrow--plain::before { display: none; }
.is-dark .u-eyebrow--plain, .ctaband .u-eyebrow--plain { color: var(--concrete-2); }

.u-lead {
  font-size: var(--fs-lead);
  line-height: 1.55;
  color: var(--muted);
  max-width: var(--measure);
  text-wrap: pretty;
}

.u-body { max-width: var(--measure); text-wrap: pretty; }
.u-body + .u-body { margin-top: 1.15em; }

.u-num {
  font-family: var(--display);
  font-weight: 700;
  font-size: var(--fs-micro);
  letter-spacing: 0.14em;
  color: var(--red-text);
  font-variant-numeric: tabular-nums;
}

.u-center { text-align: center; margin-inline: auto; }
.u-center .u-lead, .u-center .u-body { margin-inline: auto; }

/* On dark surfaces */
.is-dark { background: var(--ink); color: var(--bone); }
/* 3.32:1 on this ground at label size. The numeral reads in bone and the red
   stays on the rule beside it. */
.u-num, .is-dark .u-num, .ctaband .u-num { color: var(--concrete-2); }
.is-dark .callout__label { color: var(--concrete-2); }
.is-dark .link:hover, .is-dark .link:focus-visible { color: var(--red-text-dark); }
.is-dark .u-lead, .is-dark .u-eyebrow { color: var(--concrete-2); }
.is-dark .u-body { color: #C9CBC9; }

/* ------------------------------------------------------------- 5. LAYOUT */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap--wide { max-width: 104rem; }
.wrap--tight { max-width: 62rem; }

/* Fine grain over the light ground, so a large flat area reads as a matte
   surface rather than as an untextured fill. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.35;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4'/%3E%3C/filter%3E%3Crect width='150' height='150' filter='url(%23n)' opacity='0.32'/%3E%3C/svg%3E");
  mix-blend-mode: multiply;
}
.section { padding-block: var(--section); position: relative; z-index: 1; }
.section--flush { padding-block: 0; }

/* Two sections of the same tone, one after the other, used to stack a full
   pad against a full pad and open a band of empty page wide enough to read
   as a mistake. Where there is no change of background to justify the break,
   the seam is a single measure rather than two. */
.section + .section:not(.is-dark) { padding-top: calc(var(--section) * 0.42); }
.is-dark + .section { padding-top: var(--section); }
.section--half { padding-block: calc(var(--section) * 0.55); }

.section__head { margin-bottom: clamp(2.5rem, 5vw, 4.5rem); }
.section__head .u-eyebrow { margin-bottom: 1.1rem; }
.section__head .u-lead { margin-top: 1.3rem; }

/* Editorial variant: heading left, supporting line right, so the row reads as
   one deliberate composition rather than a short column against a void. */
.section__head--split { display: grid; grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(1.5rem, 4vw, 4rem); align-items: end; }
.section__head--split > .u-eyebrow { grid-column: 1 / -1; }
.section__head--split .u-lead { margin-top: 0; max-width: 40rem; }
@media (max-width: 900px) {
  .section__head--split { grid-template-columns: 1fr; align-items: start; }
  .section__head--split .u-lead { margin-top: 0.4rem; }
}

/* Statement above, prose in columns beneath it.

   This was a two-column grid with the statement on the left and the prose on
   the right. A short heading beside three long paragraphs left a tall empty
   rectangle in the left column on almost every interior page, which is where
   most of the site's empty space came from. Putting the heading across the top
   and flowing the prose into columns fills the row and keeps each column at a
   readable measure. */
.spread { display: grid; grid-template-columns: 1fr; gap: clamp(1.25rem, 3vw, 2.5rem); }
.spread > * { min-width: 0; }

/* Everything after the statement flows in columns. The 22rem minimum means a
   narrow container simply stays single-column rather than producing two
   unreadable ones. */
.spread > * + * {
  columns: 2 22rem;
  column-gap: clamp(2rem, 5vw, 4.5rem);
}
.spread > * + * > * { break-inside: avoid; }
.spread > * + * > :is(h2, h3, h4) { break-after: avoid; }
.spread .u-body, .spread .u-lead, .spread p { max-width: none; }

/* The callout is a panel, not prose: it spans rather than splitting. */
.spread .callout { column-span: all; }

/* The absolute row and column rule: grouped items share height and rhythm. */
.grid { display: grid; gap: clamp(1.25rem, 2.4vw, 2.25rem); align-items: stretch; }
.grid > * { min-width: 0; }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 1000px) {
  .grid--3, .grid--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grid--2, .grid--3, .grid--4 { grid-template-columns: 1fr; }
}

.rule { height: 1px; background: var(--rule); border: 0; margin: 0; }
.is-dark .rule { background: rgba(244, 243, 240, 0.16); }

/* ------------------------------------------------------------ 6. BUTTONS */

.btn {
  --btn-bg: var(--ink);
  --btn-fg: var(--bone);
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  padding: 1.05rem 1.75rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--display);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  overflow: hidden;
  isolation: isolate;
  transition: color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
  will-change: transform;
}

.btn::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--red);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--t-mid) var(--ease);
  z-index: -1;
}

.btn:hover::before, .btn:focus-visible::before { transform: scaleX(1); }
.btn:hover, .btn:focus-visible { color: var(--white); }

.btn__arrow {
  flex: none;
  width: 1.05em;
  height: 1.05em;
  transition: transform var(--t-mid) var(--ease);
}
.btn:hover .btn__arrow, .btn:focus-visible .btn__arrow { transform: translateX(6px); }

.btn--red { --btn-bg: var(--red); --btn-fg: var(--white); }
.btn--red::before { background: var(--ink); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--rule);
}
.btn--ghost:hover, .btn--ghost:focus-visible { box-shadow: inset 0 0 0 1.5px var(--red); }

.is-dark .btn--ghost, .btn--ghost-light {
  --btn-fg: var(--bone);
  box-shadow: inset 0 0 0 1.5px rgba(244, 243, 240, 0.28);
}

.btn--lg { padding: 1.25rem 2.25rem; font-size: 0.9375rem; }

/* Inline text link with an animated rule */
.link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--display);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  padding-bottom: 3px;
  background-image: linear-gradient(var(--red), var(--red));
  background-size: 0% 2px;
  background-position: left bottom;
  background-repeat: no-repeat;
  transition: background-size var(--t-mid) var(--ease), color var(--t-fast) var(--ease);
}
.link:hover, .link:focus-visible { background-size: 100% 2px; color: var(--red-text); }

/* Inside running prose a link keeps the sentence's case and size. */
p .link, li .link, .u-body .link {
  font-family: inherit;
  font-size: inherit;
  font-weight: 600;
  letter-spacing: inherit;
  text-transform: none;
  background-size: 100% 1px;
  padding-bottom: 1px;
}
p .link:hover, li .link:hover, .u-body .link:hover { background-size: 100% 2px; }
.link .btn__arrow { transition: transform var(--t-mid) var(--ease); }
.link:hover .btn__arrow { transform: translateX(5px); }

/* --------------------------------------------------------- 7. SITE HEADER */

.header {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  transition: background var(--t-mid) var(--ease), height var(--t-mid) var(--ease),
              box-shadow var(--t-mid) var(--ease);
}

.header::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(10, 11, 12, 0.82);
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  opacity: 0;
  transition: opacity var(--t-mid) var(--ease);
  z-index: -1;
}

.header.is-stuck { --header-h: 72px; }
.header.is-stuck::after { opacity: 1; }
@media (max-width: 900px) { .header.is-stuck { --header-h: 60px; } }

/* Pages that do not open with a dark hero get a solid bar immediately */
.header.is-solid::after { opacity: 1; }

.header__inner {
  width: 100%;
  max-width: 104rem;
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(1rem, 2.5vw, 2.5rem);
}

.header__logo { flex: none; display: inline-flex; align-items: center; min-height: 44px; }
.header__logo img {
  height: clamp(30px, 3.4vw, 44px);
  width: auto;
  transition: height var(--t-mid) var(--ease);
}
.header.is-stuck .header__logo img { height: clamp(26px, 2.7vw, 34px); }

/* The logo lockup is horizontal, so the nav sits to the right of it. */
.nav { display: flex; align-items: center; gap: clamp(0.5rem, 1.6vw, 1.9rem); }
@media (max-width: 1080px) { .nav { display: none; } }

.nav__list { display: contents; list-style: none; }
.nav__item { position: relative; }

.nav__link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.6rem 0.2rem;
  font-family: var(--display);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--bone);
  white-space: nowrap;
  transition: color var(--t-fast) var(--ease);
}

.nav__link::after {
  content: '';
  position: absolute;
  left: 0.2rem; right: 0.2rem; bottom: 0.35rem;
  height: 2px;
  background: var(--red);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-mid) var(--ease);
}
.nav__item:hover .nav__link::after,
.nav__link:focus-visible::after,
.nav__link[aria-current='page']::after { transform: scaleX(1); }

.nav__caret { width: 9px; height: 9px; transition: transform var(--t-fast) var(--ease); }
.nav__item:hover .nav__caret { transform: rotate(180deg); }

/* Mega menu. Only used where the section actually has depth. */
.mega {
  position: absolute;
  top: calc(100% + 0.35rem);
  left: 50%;
  translate: -50% 0;
  width: min(46rem, 78vw);
  background: var(--ink-2);
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.5);
  padding: 2rem;
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 2rem;
  opacity: 0;
  visibility: hidden;
  translate: -50% 10px;
  transition: opacity var(--t-mid) var(--ease), translate var(--t-mid) var(--ease),
              visibility 0s linear var(--t-mid);
}

.nav__item:hover .mega,
.nav__item:focus-within .mega {
  opacity: 1;
  visibility: visible;
  translate: -50% 0;
  transition: opacity var(--t-mid) var(--ease), translate var(--t-mid) var(--ease),
              visibility 0s;
}

.mega__list { display: grid; gap: 0.25rem; list-style: none; }

.mega__link {
  display: block;
  padding: 0.9rem 1rem;
  border-left: 2px solid transparent;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.mega__link:hover, .mega__link:focus-visible {
  background: rgba(244, 243, 240, 0.06);
  border-left-color: var(--red);
}

.mega__title {
  font-family: var(--display);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bone);
}
.mega__desc {
  font-size: var(--fs-small);
  line-height: 1.45;
  color: var(--concrete);
  margin-top: 0.2rem;
}

.mega__feature { position: relative; overflow: hidden; min-height: 13rem; }
.mega__feature img { width: 100%; height: 100%; object-fit: cover; position: absolute; inset: 0; }
.mega__feature-body {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  padding: 1.25rem;
  background: linear-gradient(to top, rgba(10, 11, 12, 0.92), transparent);
  color: var(--bone);
}

.header__cta { display: flex; align-items: center; gap: 0.75rem; flex: none; }
@media (max-width: 1080px) { .header__cta .btn { display: none; } }

/* Burger */
.burger {
  display: none;
  width: 46px; height: 46px;
  align-items: center;
  justify-content: center;
  flex: none;
}
@media (max-width: 1080px) { .burger { display: inline-flex; } }

.burger__box { position: relative; width: 26px; height: 14px; }
.burger__line {
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  background: var(--bone);
  transition: transform var(--t-mid) var(--ease), opacity var(--t-fast) var(--ease);
}
.burger__line:nth-child(1) { top: 0; }
.burger__line:nth-child(2) { top: 6px; }
.burger__line:nth-child(3) { top: 12px; }

.burger[aria-expanded='true'] .burger__line:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.burger[aria-expanded='true'] .burger__line:nth-child(2) { opacity: 0; }
.burger[aria-expanded='true'] .burger__line:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* --------------------------------------------------- 8. MOBILE FULL MENU */

.mobilenav {
  position: fixed;
  inset: 0;
  z-index: 99;
  background: var(--ink);
  padding: calc(var(--header-h) + 1.5rem) var(--gutter) 2rem;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  clip-path: inset(0 0 100% 0);
  transition: clip-path 0.62s var(--ease);
  visibility: hidden;
}
.mobilenav.is-open { clip-path: inset(0 0 0 0); visibility: visible; }

.mobilenav__list { list-style: none; display: flex; flex-direction: column; }

.mobilenav__row { border-bottom: 1px solid rgba(244, 243, 240, 0.13); }

.mobilenav__link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.15rem 0;
  font-family: var(--display);
  font-size: clamp(1.5rem, 7vw, 2.25rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--bone);
  opacity: 0;
  transform: translateY(18px);
}
.mobilenav.is-open .mobilenav__link {
  animation: navIn 0.55s var(--ease) forwards;
  animation-delay: calc(var(--i, 0) * 55ms + 120ms);
}

@keyframes navIn { to { opacity: 1; transform: none; } }

.mobilenav__link .btn__arrow {
  width: 0.72em; height: 0.72em;
  color: var(--red);
  transition: transform var(--t-mid) var(--ease);
}
.mobilenav__link:hover .btn__arrow { transform: translateX(7px); }

.mobilenav__sub { list-style: none; padding: 0 0 1.1rem 0; display: grid; gap: 0.15rem; }
.mobilenav__sublink {
  display: flex;
  align-items: center;
  /* 44px minimum so a thumb can hit these reliably; WCAG 2.5.8 asks for 24, the
     brief asks for large touch targets, so this takes the larger number. */
  min-height: 44px;
  padding: 0.35rem 0.75rem 0.35rem 1rem;
  font-size: var(--fs-small);
  letter-spacing: 0.05em;
  color: var(--concrete-2);
  border-left: 2px solid rgba(244, 243, 240, 0.18);
  transition: color var(--t-fast) var(--ease), border-left-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease);
}
.mobilenav__sublink:hover, .mobilenav__sublink:focus-visible {
  color: var(--bone);
  border-left-color: var(--red);
  background: rgba(244, 243, 240, 0.05);
}

.mobilenav__foot { margin-top: auto; padding-top: 2rem; display: grid; gap: 1rem; }
.mobilenav__foot .btn { justify-content: center; }

/* ----------------------------------------------------- 9. STICKY MOBILE BAR */

.quickbar {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 90;
  display: none;
  background: var(--ink);
  border-top: 1px solid rgba(244, 243, 240, 0.14);
  padding-bottom: env(safe-area-inset-bottom, 0);
  transform: translateY(110%);
  transition: transform var(--t-mid) var(--ease);
}
.quickbar.is-visible { transform: none; }

@media (max-width: 780px) { .quickbar { display: block; } }

.quickbar__grid { display: grid; grid-template-columns: repeat(3, 1fr); }

.quickbar__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  min-height: 60px;
  padding: 0.55rem 0.4rem;
  font-family: var(--display);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--bone);
}
.quickbar__item + .quickbar__item { border-left: 1px solid rgba(244, 243, 240, 0.14); }
.quickbar__item--accent { background: var(--red); color: var(--white); }
.quickbar__item svg { width: 17px; height: 17px; }

@media (max-width: 780px) { body { padding-bottom: 60px; } }

/* ------------------------------------------------------------- 10. HERO */

.hero {
  position: relative;
  z-index: 2;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--ink);
  color: var(--bone);
}

.hero__media { position: absolute; inset: 0; z-index: 0; }
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  will-change: transform;
  transform: scale(1.06);
  filter: brightness(1.14) contrast(1.04) saturate(0.96);
}

.hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  /* Weighted to the left, where the type sits, so the lit floor on the right
     stays visible. A flat overlay just buries the photograph. */
  background:
    linear-gradient(100deg, rgba(10,11,12,0.92) 0%, rgba(10,11,12,0.78) 26%,
                    rgba(10,11,12,0.34) 55%, rgba(10,11,12,0.10) 78%, rgba(10,11,12,0.28) 100%),
    linear-gradient(to top, rgba(10,11,12,0.72) 0%, rgba(10,11,12,0) 38%),
    linear-gradient(to bottom, rgba(10,11,12,0.55) 0%, rgba(10,11,12,0) 22%);
}

/* Fine grain, keeps large dark areas from banding */
.hero__grain {
  position: absolute; inset: 0; z-index: 2;
  opacity: 0.16;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.42'/%3E%3C/svg%3E");
}

.hero__inner {
  position: relative;
  z-index: 3;
  width: 100%;
  max-width: 104rem;
  margin-inline: auto;
  padding: calc(var(--header-h) + clamp(0.75rem, 3.2vh, 3rem))
           var(--gutter)
           clamp(1.25rem, 3.4vh, 4rem);
}

.hero__eyebrow { color: var(--concrete-2); margin-bottom: clamp(0.5rem, 1.6vh, 1.5rem); }
.hero__eyebrow .hide-sm { display: inline; }
@media (max-width: 560px) {
  .hero__eyebrow { align-items: flex-start; }
  .hero__eyebrow .hide-sm { display: none; }
  .hero__eyebrow::before { margin-top: 0.55em; }
}
.hero__eyebrow::before { background: var(--red); }

/* The authored line breaks decide the lines; an 18ch cap was re-wrapping them
   and forcing the fitter to shrink type that already fitted. */
/* text-wrap: balance narrows the box to even out line lengths, which re-wrapped
   every authored break and made a two-line headline render as four. These lines
   are balanced by hand, so the browser must not re-balance them. */
.hero__title { color: var(--bone); max-width: none; text-wrap: wrap; }
.hero__title .rl > span { text-wrap: wrap; }
.hero__title .rl { display: block; overflow: hidden; padding-block: 0.04em 0.1em; }
.hero__title .rl > span { display: block; transform: translateX(-104%); font-style: normal; }
.hero__title.is-in .rl > span,
.no-js .hero__title .rl > span {
  transform: none;
  transition: transform 1.05s var(--ease);
  transition-delay: calc(var(--i, 0) * 110ms + 120ms);
}
.hero__title em { font-style: normal; }
/* 2.94:1 against a 3:1 floor once the ground beneath it lightened. The lighter
   variant holds the same hue and clears it. */
.hero__title .accent { color: var(--red-text-dark); }

.hero__lead {
  margin-top: clamp(0.9rem, 2.2vh, 2rem);
  max-width: 44ch;
  color: #CFD1CF;
  font-size: var(--fs-lead);
  line-height: 1.55;
}

.hero__actions {
  margin-top: clamp(1rem, 2.6vh, 2.6rem);
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
}

.hero__foot {
  margin-top: clamp(1.1rem, 3.2vh, 3.5rem);
  padding-top: clamp(0.8rem, 1.8vh, 1.6rem);
  border-top: 1px solid rgba(244, 243, 240, 0.2);
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.5rem, 4vw, 4rem);
  align-items: baseline;
}

.hero__stat { display: grid; gap: 0.2rem; }
.hero__stat dt {
  font-family: var(--display);
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--bone);
}
.hero__stat dd {
  margin: 0;
  font-size: var(--fs-micro);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* Masking the hero media at its foot lightened the ground the stat row sits
     on, and --concrete landed at 4.45:1 against a 4.5 floor. */
  color: var(--concrete-2);
}

.hero__scroll {
  position: absolute;
  z-index: 3;
  right: var(--gutter);
  bottom: clamp(3rem, 7vh, 6rem);
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--concrete-2);
  writing-mode: vertical-rl;
}
@media (max-width: 900px) { .hero__scroll { display: none; } }

.hero__scroll-line {
  width: 1px; height: 62px;
  background: rgba(244, 243, 240, 0.3);
  position: relative;
  overflow: hidden;
}
.hero__scroll-line::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  height: 40%;
  background: var(--red);
  animation: scrollHint 2.1s var(--ease) infinite;
}
@keyframes scrollHint {
  0%   { transform: translateY(-100%); }
  100% { transform: translateY(250%); }
}

/* Compact hero for interior pages */
/* Full fold, same as the homepage. It was capped at 640px, which left the
   picture stopping short of the bottom of the screen. */
.hero--page { min-height: 100svh; }
/* The interior-page hero capped its headline at 18ch, which is 1113px at this
   size and re-wrapped every authored two-line headline into four. The authored
   breaks decide the lines. */
.hero--page .hero__title { max-width: none; }

/* ------------------------------------------------- 11. SPLIT ENTRY PANELS */

.split { display: grid; grid-template-columns: 1fr 1fr; min-height: clamp(28rem, 62vh, 40rem); }
@media (max-width: 820px) { .split { grid-template-columns: 1fr; } }

.split__panel {
  position: relative;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  padding: clamp(1.75rem, 3.6vw, 3.25rem);
  color: var(--bone);
  min-height: clamp(20rem, 42vh, 28rem);
  isolation: isolate;
}

.split__panel img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 1.1s var(--ease);
}
.split__panel::after {
  content: '';
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top, rgba(10, 11, 12, 0.9), rgba(10, 11, 12, 0.24));
  transition: background var(--t-mid) var(--ease);
}
.split__panel:hover img { transform: scale(1.055); }
.split__panel:hover::after { background: linear-gradient(to top, rgba(10,11,12,0.94), rgba(222,24,28,0.2)); }

.split__body { position: relative; width: 100%; display: block; }
.split__body .u-num { display: block; margin-bottom: 0.5rem; }
.split__title { font-size: clamp(1.9rem, 3.6vw, 3.1rem); }
.split__desc { display: block; margin-top: 0.6rem; color: #C4C6C4; max-width: 34ch; }
.split__go { display: inline-flex; margin-top: 1.35rem; }

/* --------------------------------------------------- 12. SERVICE INDEX */

/* A vertical accordion: the active row expands to reveal a short description
   while the rest stay as slim teaser rows. The stage on the right shows the
   matching visual. Hover drives it on a fine pointer, tap on touch. */

.svcindex { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: clamp(2rem, 5vw, 5rem); align-items: start; }
@media (max-width: 940px) { .svcindex { grid-template-columns: 1fr; } }

.svcindex__list { list-style: none; border-top: 1px solid var(--rule); }
.is-dark .svcindex__list { border-color: rgba(244, 243, 240, 0.18); }

.svcindex__row { border-bottom: 1px solid var(--rule); }
.is-dark .svcindex__row { border-color: rgba(244, 243, 240, 0.18); }

.svcindex__link {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: clamp(0.9rem, 2.2vw, 1.8rem);
  width: 100%;
  text-align: left;
  padding: clamp(0.95rem, 2vw, 1.35rem) 0;
  transition: padding-inline-start var(--t-mid) var(--ease), color var(--t-fast) var(--ease);
}
.svcindex__row.is-active .svcindex__link,
.svcindex__link:focus-visible { padding-inline-start: clamp(0.6rem, 1.6vw, 1.35rem); }
.svcindex__row.is-active .svcindex__link { color: var(--red-text-dark); }

.svcindex__num {
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--concrete);
  font-variant-numeric: tabular-nums;
  transition: color var(--t-fast) var(--ease);
}
.svcindex__row.is-active .svcindex__num { color: var(--red-text-dark); }

.svcindex__name {
  font-family: var(--display);
  font-size: clamp(1.2rem, 2.4vw, 1.9rem);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}

.svcindex__arrow {
  width: 1.1rem; height: 1.1rem;
  color: var(--concrete);
  transition: transform var(--t-mid) var(--ease), color var(--t-fast) var(--ease);
}
.svcindex__row.is-active .svcindex__arrow { transform: translateX(7px); color: var(--red-text-dark); }

/* The panel that opens. Height is committed by script and never animated by a
   CSS transition, for the same reason as the FAQ: a stalled transition would
   leave a panel jammed shut. The tween runs on the inner wrapper instead. */
.svcindex__panel { overflow: hidden; }
.svcindex__panel > div { padding-bottom: clamp(1rem, 2.2vw, 1.5rem); }
.svcindex__desc {
  max-width: 46ch;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--muted);
}
.is-dark .svcindex__desc { color: #C2C5C3; }
.svcindex__more {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin-top: 0.85rem;
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--red-text-dark);
}
.svcindex__more svg { width: 0.85em; height: 0.85em; transition: transform var(--t-mid) var(--ease); }
.svcindex__more:hover svg { transform: translateX(5px); }

/* Sticky visual stage */
.svcindex__stage {
  position: sticky;
  top: calc(var(--header-h) + 2rem);
  /* Pinned to the clips' own aspect. The stage used to be sized from the
     viewport, which meant object-fit: cover threw away half of every 16:9
     clip and magnified what was left. Matching the two exactly means the
     whole frame is seen at its native scale. */
  aspect-ratio: 7 / 8;
  max-height: min(78vh, 44rem);
  overflow: hidden;
  background: var(--ink-2);
}
@media (max-width: 940px) { .svcindex__stage { display: none; } }

.svcindex__shot {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity 0.5s var(--ease);
}
.svcindex__shot.is-active { opacity: 1; }
.svcindex__shot img,
.svcindex__shot video { width: 100%; height: 100%; object-fit: cover; display: block; }

.svcindex__caption {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  padding: 1.4rem;
  background: linear-gradient(to top, rgba(10, 11, 12, 0.9), transparent);
  color: var(--bone);
  font-family: var(--display);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

/* Below the stage breakpoint each row carries its own visual inside the panel. */
.svcindex__thumb { display: none; }
@media (max-width: 940px) {
  .svcindex__thumb {
    display: block;
    aspect-ratio: 16 / 10;
    overflow: hidden;
    margin-bottom: 1rem;
    background: var(--ink-2);
  }
  .svcindex__thumb img,
  .svcindex__thumb video { width: 100%; height: 100%; object-fit: cover; display: block; }
}

/* ------------------------------------------------------- 13. FEATURE ROW */

/* The media matches the height of the column beside it. Centring a fixed-ratio
   image against a long column of prose left a band of empty page under the
   picture that read as an unfinished layout. */
.feature { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2rem, 5vw, 5.5rem); align-items: stretch; }
.feature--flip .feature__media { order: 2; }
@media (max-width: 900px) {
  .feature, .feature--flip { grid-template-columns: 1fr; }
  .feature--flip .feature__media { order: 0; }
}

.feature__media {
  position: relative;
  overflow: hidden;
  min-height: clamp(22rem, 46vh, 34rem);
}
.feature__media img,
.feature__media picture { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 900px) {
  .feature__media { position: relative; min-height: 0; aspect-ratio: 5 / 4; }
}
.feature__media img { width: 100%; height: 100%; object-fit: cover; }

.feature__body .u-eyebrow { margin-bottom: 1rem; }
.feature__body .u-h2 { margin-bottom: 1.2rem; }
.feature__actions { margin-top: 1.9rem; display: flex; flex-wrap: wrap; gap: 0.85rem; }

/* Specs list under a feature */
.speclist { list-style: none; margin-top: 1.9rem; border-top: 1px solid var(--rule); }
.is-dark .speclist { border-color: rgba(244, 243, 240, 0.18); }
.speclist li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.9rem;
  align-items: baseline;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--rule);
}
.is-dark .speclist li { border-color: rgba(244, 243, 240, 0.18); }
.speclist svg { width: 0.9rem; height: 0.9rem; color: var(--red); transform: translateY(2px); }

/* -------------------------------------------------------- 14. STAT BAND */

/* Black wherever it lands. These are the hard numbers on each page and they
   should read as a plate set into the page, not as four more light cells. */
.statband { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
  background: rgba(244, 243, 240, 0.16); }
@media (max-width: 860px) { .statband { grid-template-columns: repeat(2, 1fr); } }

.statband__cell {
  background: var(--bg);
  padding: clamp(1.6rem, 3.4vw, 2.75rem) clamp(1.1rem, 2vw, 1.8rem);
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  min-height: 100%;
}
.statband__cell { background: var(--ink); color: var(--bone); }

.statband__num {
  font-family: var(--display);
  font-size: clamp(2rem, 4.2vw, 3.4rem);
  font-weight: 800;
  line-height: 0.95;
  letter-spacing: -0.03em;
}
.statband__label {
  font-size: var(--fs-micro);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
.statband__label { color: var(--concrete-2); }

/* ----------------------------------------------------- 15. CALLOUT BLOCK */

.callout {
  position: relative;
  padding: clamp(1.5rem, 3vw, 2.25rem) clamp(1.5rem, 3vw, 2.5rem);
  background: var(--bone-2);
  border-left: 3px solid var(--red);
  margin-block: clamp(2rem, 4vw, 3rem);
  max-width: 100%;
}
.is-dark .callout { background: var(--ink-2); }

.callout__label {
  display: block;
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--red-text);
  margin-bottom: 0.7rem;
}
.callout p { max-width: none; }
.callout p + p { margin-top: 0.9rem; }

/* ---------------------------------------------------- 16. COMPARISON TABLE */

.tablewrap { overflow-x: auto; margin-block: clamp(1.75rem, 3.5vw, 2.75rem); -webkit-overflow-scrolling: touch; }

.ctable { width: 100%; min-width: 34rem; border-collapse: collapse; font-size: var(--fs-small); }
.ctable caption {
  text-align: left;
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  padding-bottom: 0.9rem;
}
.ctable th, .ctable td {
  text-align: left;
  padding: 0.95rem 1.1rem;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}
.ctable thead th {
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  border-bottom: 2px solid var(--ink);
  white-space: nowrap;
}
.ctable tbody th { font-family: var(--body); font-weight: 600; }
.ctable tbody tr:hover { background: rgba(10, 11, 12, 0.035); }
.is-dark .ctable th, .is-dark .ctable td { border-color: rgba(244, 243, 240, 0.18); }
.is-dark .ctable thead th { border-bottom-color: var(--bone); }

/* ------------------------------------------------------------ 17. GALLERY */

/* Twelve columns on a fixed row track. Every tile spans the SAME number of row
   tracks, so tiles sharing a row are always exactly the same height regardless of
   how wide each one is. Per-item aspect ratios cannot guarantee that, because a
   half-width tile and a third-width tile resolve to different heights. */
.gallery {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: clamp(4rem, 6.6vw, 7.5rem);
  gap: clamp(0.5rem, 1.1vw, 1rem);
}
@media (max-width: 820px) {
  .gallery { grid-template-columns: repeat(6, 1fr); grid-auto-rows: clamp(3.5rem, 12vw, 6rem); }
}

.gitem {
  position: relative;
  overflow: hidden;
  background: var(--ink-2);
  cursor: pointer;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
}
.gitem img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.85s var(--ease); }
.gitem:hover img { transform: scale(1.055); }

.gitem::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(10, 11, 12, 0.85), transparent 55%);
  opacity: 0;
  transition: opacity var(--t-mid) var(--ease);
}
.gitem:hover::after, .gitem:focus-visible::after { opacity: 1; }

.gitem__meta {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 2;
  padding: 1.1rem 1.25rem;
  text-align: left;
  color: var(--bone);
  transform: translateY(10px);
  opacity: 0;
  transition: transform var(--t-mid) var(--ease), opacity var(--t-mid) var(--ease);
}
.gitem:hover .gitem__meta, .gitem:focus-visible .gitem__meta { transform: none; opacity: 1; }

.gitem__title {
  font-family: var(--display);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.gitem__tag { font-size: var(--fs-micro); color: var(--concrete-2); letter-spacing: 0.08em; }

/* Widths vary for editorial rhythm; the row span is constant so heights match. */
.gitem { grid-row: span 3; }
.gitem--w3  { grid-column: span 3; }
.gitem--w4  { grid-column: span 4; }
.gitem--w6  { grid-column: span 6; }
.gitem--w8  { grid-column: span 8; }
.gitem--w12 { grid-column: span 12; grid-row: span 2; }  /* full-bleed banner runs shorter */

@media (max-width: 820px) {
  .gitem--w3, .gitem--w4, .gitem--w8 { grid-column: span 3; }
  .gitem--w6 { grid-column: span 3; }
  .gitem--w12 { grid-column: span 6; grid-row: span 2; }
}
@media (max-width: 480px) {
  .gitem--w3, .gitem--w4, .gitem--w6, .gitem--w8 { grid-column: span 6; }
}

/* The tile is a fixed box; the photograph fills it. */
.gitem { height: 100%; }
.gitem img { height: 100%; }

/* ----------------------------------------------------------- 18. LIGHTBOX */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(6, 7, 8, 0.97);
  display: grid;
  grid-template-rows: auto 1fr auto;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s var(--ease), visibility 0s linear 0.35s;
}
.lightbox.is-open { opacity: 1; visibility: visible; transition: opacity 0.35s var(--ease), visibility 0s; }

.lightbox__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.25rem var(--gutter);
  color: var(--bone);
}
.lightbox__count {
  font-family: var(--display);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: 0.16em;
  font-variant-numeric: tabular-nums;
}
.lightbox__close { width: 46px; height: 46px; display: grid; place-items: center; color: var(--bone); }
.lightbox__close svg { width: 20px; height: 20px; }
.lightbox__close:hover { color: var(--red-text-dark); }

.lightbox__stage {
  position: relative;
  display: grid;
  place-items: center;
  padding: 0 clamp(0.5rem, 5vw, 5rem);
  min-height: 0;
}
.lightbox__figure { margin: 0; max-height: 100%; display: grid; place-items: center; }
.lightbox__figure img {
  max-width: 100%;
  max-height: calc(100svh - 200px);
  width: auto;
  object-fit: contain;
}

.lightbox__nav {
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  width: 52px; height: 52px;
  display: grid;
  place-items: center;
  background: rgba(244, 243, 240, 0.09);
  color: var(--bone);
  transition: background var(--t-fast) var(--ease);
}
.lightbox__nav:hover { background: var(--red); }
.lightbox__nav svg { width: 20px; height: 20px; }
.lightbox__nav--prev { left: clamp(0.5rem, 2vw, 2rem); }
.lightbox__nav--next { right: clamp(0.5rem, 2vw, 2rem); }

.lightbox__caption {
  padding: 1.25rem var(--gutter) 2rem;
  text-align: center;
  color: var(--concrete-2);
  font-size: var(--fs-small);
}

/* ----------------------------------------------------------- 19. SWATCHES */

/* Eighteen swatches. Column counts are explicit and all divide 18 exactly, so
   the final row is never short: 6 x 3, 3 x 6, 2 x 9. auto-fill was giving 5
   across, which left an orphan row of 3. */
.swatches {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: clamp(0.6rem, 1.4vw, 1.15rem);
  align-items: start;
}
@media (max-width: 1100px) { .swatches { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 560px)  { .swatches { grid-template-columns: repeat(2, 1fr); } }

/* Fixed six-across strip. Column counts are explicit at every breakpoint so a
   row can never end with a single orphan tile. */
.swatches--strip { grid-template-columns: repeat(6, 1fr); }
@media (max-width: 1100px) { .swatches--strip { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 560px)  { .swatches--strip { grid-template-columns: repeat(2, 1fr); } }

/* The tile is a fixed square; the caption sits under it in normal flow. Letting
   the grid stretch the swatch made the square grow past its box and the caption
   was then covered by the following row. */
.swatch { display: block; }
.swatch__tile { flex: none; }
.swatch__name { min-height: 1.35em; }
.swatch__tone { min-height: 1.2em; }

.swatch { position: relative; display: block; width: 100%; padding: 0; border: 0; background: none; text-align: left; cursor: pointer; }
.swatch__tile { position: relative; aspect-ratio: 1 / 1; overflow: hidden; background: var(--bone-2); }
.swatch__tile img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.7s var(--ease); }
.swatch:hover .swatch__tile img { transform: scale(1.07); }

.swatch__tile::after {
  content: '';
  position: absolute; inset: 0;
  box-shadow: inset 0 0 0 0 var(--red);
  transition: box-shadow var(--t-mid) var(--ease);
}
.swatch:hover .swatch__tile::after, .swatch:focus-visible .swatch__tile::after { box-shadow: inset 0 0 0 3px var(--red); }

.swatch__name {
  display: block;
  margin-top: 0.7rem;
  font-family: var(--display);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.swatch__tone { display: block; font-size: var(--fs-micro); color: var(--muted); letter-spacing: 0.08em; text-transform: uppercase; }

/* Filter chips */
.filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: clamp(1.75rem, 3.5vw, 2.75rem); }
.filter {
  padding: 0.6rem 1.15rem;
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  box-shadow: inset 0 0 0 1.5px var(--rule);
  transition: box-shadow var(--t-fast) var(--ease), background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.filter:hover { box-shadow: inset 0 0 0 1.5px var(--ink); }
.filter[aria-pressed='true'],
.filter[aria-selected='true'] { background: var(--ink); color: var(--bone); box-shadow: none; }

/* On dark bands the default rule colour is invisible, so the chips need their own
   border, selected state and focus treatment. */
.is-dark .filter, .is-dark [role='tab'] {
  color: var(--concrete-2);
  box-shadow: inset 0 0 0 1.5px rgba(244, 243, 240, 0.26);
}
.is-dark .filter:hover, .is-dark [role='tab']:hover {
  color: var(--bone);
  box-shadow: inset 0 0 0 1.5px var(--bone);
}
.is-dark .filter[aria-pressed='true'],
/* The picker is a tablist too, but it carries its own selected state. Without
   this exclusion it inherits the pill styling and the option turns solid red. */
.is-dark [role='tab'][aria-selected='true']:not(.picker__opt) {
  background: var(--red);
  color: var(--white);
  box-shadow: none;
}

/* Tabs sit on a rule so the selected chip reads as a chosen panel. */
[role='tablist'].filters {
  gap: 0.4rem;
  padding-bottom: 1.1rem;
  margin-bottom: clamp(2rem, 4vw, 3rem);
  border-bottom: 1px solid var(--rule);
}
.is-dark [role='tablist'].filters { border-bottom-color: rgba(244, 243, 240, 0.18); }

/* ----------------------------------------------------------- 20. PROCESS */

.process { counter-reset: step; display: grid; gap: 1px; background: var(--rule); }
.is-dark .process { background: rgba(244, 243, 240, 0.18); }

.process__step {
  background: var(--bg);
  padding: clamp(1.5rem, 3vw, 2.5rem);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(1rem, 3vw, 2.5rem);
  align-items: start;
}
.is-dark .process__step { background: var(--ink); }
@media (max-width: 640px) { .process__step { grid-template-columns: 1fr; gap: 0.75rem; } }

.process__step::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  font-family: var(--display);
  font-size: clamp(1.5rem, 3vw, 2.25rem);
  font-weight: 800;
  line-height: 1;
  color: var(--red);
  letter-spacing: -0.02em;
}
.process__body h3 { margin-bottom: 0.5rem; }
.process__body p { max-width: 52rem; }

/* -------------------------------------------------------------- 21. FAQ */

.faq { border-top: 1px solid var(--rule); }
.is-dark .faq { border-color: rgba(244, 243, 240, 0.18); }

.faq__item { border-bottom: 1px solid var(--rule); }
.is-dark .faq__item { border-color: rgba(244, 243, 240, 0.18); }

.faq__q {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 1.25rem;
  align-items: center;
  text-align: left;
  padding: clamp(1.1rem, 2.2vw, 1.6rem) 0;
  font-family: var(--display);
  font-size: var(--fs-h4);
  font-weight: 600;
  line-height: 1.3;
  transition: color var(--t-fast) var(--ease);
}
.faq__q:hover { color: var(--red-text); }

.faq__sign { position: relative; width: 16px; height: 16px; flex: none; }
.faq__sign::before, .faq__sign::after {
  content: '';
  position: absolute;
  background: currentColor;
  transition: transform var(--t-mid) var(--ease), opacity var(--t-fast) var(--ease);
}
.faq__sign::before { inset-inline: 0; top: 7px; height: 2px; }
.faq__sign::after { inset-block: 0; left: 7px; width: 2px; }
.faq__q[aria-expanded='true'] .faq__sign::after { transform: scaleY(0); opacity: 0; }
.faq__q[aria-expanded='true'] { color: var(--red-text); }

/* Answers are open by default so they are readable without JavaScript; the
   script collapses them on load and animates the toggle.
   No CSS height transition here on purpose. The script commits the final height
   immediately and tweens with the Web Animations API, so a throttled or
   non-advancing transition can never leave an answer stuck shut. The 0fr -> 1fr
   grid trick is avoided for a related reason: the inner wrapper needs
   overflow:hidden, which zeroes the row's automatic minimum, so 1fr resolves
   against zero free space and the panel never opens at all. */
.faq__a { overflow: hidden; }
.faq__a > div { overflow: hidden; }
.faq__a p { padding-bottom: 1.5rem; max-width: 46rem; }
.faq__a p + p { padding-bottom: 1.5rem; margin-top: -0.5rem; }

/* --------------------------------------------------------- 22. CTA BAND */

.ctaband { position: relative; overflow: hidden; background: var(--ink); color: var(--bone); isolation: isolate; }
.ctaband img { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; object-fit: cover; opacity: 0.34; }
.ctaband::after {
  content: '';
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(105deg, rgba(10,11,12,0.95) 22%, rgba(10,11,12,0.62) 100%);
}

.ctaband__inner {
  padding-block: clamp(4rem, 9vw, 8rem);
  display: grid;
  grid-template-columns: 1.35fr auto;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: end;
}
@media (max-width: 900px) { .ctaband__inner { grid-template-columns: 1fr; align-items: start; } }

.ctaband__title { color: var(--bone); max-width: 16ch; }
.ctaband__actions { display: flex; flex-wrap: wrap; gap: 0.9rem; }

/* ---------------------------------------------------------- 23. PARTNERS */

.partners { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: clamp(1.75rem, 5vw, 4.5rem); }
.partners__strip { height: auto; max-width: min(100%, 58rem); }
.partners img { width: auto; opacity: 0.6;
  transition: opacity var(--t-mid) var(--ease); }
.partners img:hover { opacity: 0.9; }

/* ------------------------------------------------------------- 24. FORMS */

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

.field { display: grid; gap: 0.45rem; }
.field label {
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.is-dark .field label { color: var(--concrete); }

/* The honeypot is in here too. It sits off-canvas and nobody ever sees it, but
   leaving one white box in the document makes "no white surfaces" untrue and
   the next check ambiguous. */
.hp input,
.field input, .field textarea, .field select {
  width: 100%;
  padding: 0.95rem 1.1rem;
  font: inherit;
  font-size: 1rem;
  color: var(--fg);
  background: var(--matte-2);
  border: 1.5px solid var(--rule);
  border-radius: 0;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
  min-height: 48px;
}
.is-dark .field input, .is-dark .field textarea, .is-dark .field select {
  background: var(--ink-2);
  color: var(--bone);
  border-color: rgba(244, 243, 240, 0.2);
}
.field textarea { resize: vertical; min-height: 8rem; }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none;
  border-color: var(--red);
  box-shadow: 0 0 0 3px var(--red-glow);
}
.field input::placeholder, .field textarea::placeholder { color: #9AA0A0; }

.field--error input, .field--error textarea { border-color: var(--red); }
.field__error { font-size: var(--fs-micro); color: var(--red-text); letter-spacing: 0.04em; min-height: 1em; }

.form__note { font-size: var(--fs-small); color: var(--muted); max-width: 40rem; }
.is-dark .form__note { color: var(--concrete); }

.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.formstate {
  display: none;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border-left: 3px solid var(--red);
  background: var(--bone-2);
}
.is-dark .formstate { background: var(--ink-2); }
.formstate.is-shown { display: block; animation: fadeUp 0.5s var(--ease); }
@keyframes fadeUp { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

/* --------------------------------------------------------- 25. CONTACT AS */

.contactcard { display: grid; gap: 1.6rem; }
.contactcard__row { display: grid; grid-template-columns: auto 1fr; gap: 1rem; align-items: start; }
.contactcard__row svg { width: 1.15rem; height: 1.15rem; color: var(--red); transform: translateY(3px); }
.contactcard__label {
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.15rem;
}
.is-dark .contactcard__label { color: var(--concrete); }
.contactcard__value { font-size: var(--fs-lead); line-height: 1.35; }

/* Marks values the client still has to supply. Visible on purpose. */
.tbd {
  display: inline-block;
  padding: 0.1em 0.5em;
  background: repeating-linear-gradient(45deg, rgba(222,24,28,0.13), rgba(222,24,28,0.13) 6px, rgba(222,24,28,0.05) 6px, rgba(222,24,28,0.05) 12px);
  box-shadow: inset 0 0 0 1px rgba(222, 24, 28, 0.45);
  color: inherit;
  font-family: var(--body);
  font-size: 0.9em;
  letter-spacing: 0.02em;
}
.tbd::before { content: '⚑ '; color: var(--red); }

/* ------------------------------------------------------------ 26. FOOTER */

.footer { background: var(--ink); color: var(--bone); padding-block: clamp(3.5rem, 7vw, 6rem) 0; }

.footer__top {
  display: grid;
  grid-template-columns: 1.5fr repeat(4, 1fr);
  gap: clamp(1.75rem, 3vw, 3rem);
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
}
@media (max-width: 1100px) { .footer__top { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 1100px) { .footer__brand { grid-column: 1 / -1; } }
@media (max-width: 720px)  { .footer__top { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 420px)  { .footer__top { grid-template-columns: 1fr; } }

.footer__logo img { height: 40px; width: auto; }
.footer__blurb { margin-top: 1.25rem; color: var(--concrete); max-width: 30ch; font-size: var(--fs-small); line-height: 1.6; }

.footer__coltitle {
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--concrete);
  margin-bottom: 1.15rem;
}

.footer__list { list-style: none; display: grid; gap: 0.2rem; }
.footer__list a {
  display: inline-flex;
  align-items: center;
  /* Comfortable tap height on touch screens without opening up the desktop rhythm. */
  min-height: 34px;
  font-size: var(--fs-small);
  color: #D3D5D3;
  transition: color var(--t-fast) var(--ease), padding-left var(--t-fast) var(--ease);
}
.footer__list a:hover, .footer__list a:focus-visible { color: var(--red-text-dark); padding-left: 5px; }

@media (pointer: coarse) {
  .footer__list a { min-height: 44px; }
  .footer__legal a { display: inline-flex; align-items: center; min-height: 44px; }
}

.footer__bottom {
  border-top: 1px solid rgba(244, 243, 240, 0.15);
  padding-block: 1.6rem clamp(1.6rem, 3vw, 2.25rem);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  font-size: var(--fs-micro);
  color: var(--concrete);
  letter-spacing: 0.06em;
}
.footer__legal { display: flex; flex-wrap: wrap; gap: 1.5rem; }
.footer__credit { color: var(--concrete); }
.footer__credit a {
  color: #D3D5D3;
  padding-bottom: 1px;
  background-image: linear-gradient(var(--red-text-dark), var(--red-text-dark));
  background-size: 0% 1px;
  background-position: left bottom;
  background-repeat: no-repeat;
  transition: background-size var(--t-mid) var(--ease), color var(--t-fast) var(--ease);
}
.footer__credit a:hover, .footer__credit a:focus-visible {
  color: var(--red-text-dark);
  background-size: 100% 1px;
}
@media (pointer: coarse) { .footer__credit a { display: inline-flex; align-items: center; min-height: 44px; } }
.footer__legal a:hover { color: var(--red-text-dark); }

/* --------------------------------------------------- 27. SCROLL PROGRESS */

.progress {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  height: 2px;
  z-index: 101;
  background: transparent;
  pointer-events: none;
}
.progress__bar { height: 100%; width: 0%; background: var(--red); transform-origin: left; }

/* ------------------------------------------------------ 29. PAGE PRELOAD */

.preload {
  position: fixed;
  inset: 0;
  z-index: 400;
  background: var(--ink);
  display: grid;
  place-items: center;
  transition: clip-path 0.75s var(--ease) 0.1s;
  clip-path: inset(0 0 0 0);
}
.preload.is-done { clip-path: inset(0 0 100% 0); pointer-events: none; }

.preload__mark { width: min(240px, 52vw); opacity: 0; animation: preIn 0.5s var(--ease) forwards; }
@keyframes preIn { to { opacity: 1; } }

.preload__line {
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  height: 2px;
  width: 100%;
  background: var(--red);
  transform: scaleX(0);
  transform-origin: left;
  animation: preBar 0.85s var(--ease-in) forwards;
}
@keyframes preBar { to { transform: scaleX(1); } }

/* -------------------------------------------------- 30. REVEAL ON SCROLL */

[data-reveal] { opacity: 0; transform: translateY(26px); }
[data-reveal].is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.85s var(--ease), transform 0.85s var(--ease);
  transition-delay: var(--d, 0ms);
}

[data-reveal='mask'] { opacity: 1; transform: none; clip-path: inset(0 0 100% 0); }
[data-reveal='mask'].is-in {
  clip-path: inset(0 0 0 0);
  transition: clip-path 1.05s var(--ease);
  transition-delay: var(--d, 0ms);
}

[data-reveal='fade'] { transform: none; }

/* Line-by-line headline reveal */
.reveal-lines { display: block; }
.reveal-lines .rl {
  display: block;
  overflow: hidden;
  /* The glyph box is taller than the line box at display sizes, so the mask
     needs a little breathing room or it crops the letterforms. */
  padding-block: 0.04em 0.1em;
}
.reveal-lines .rl > span {
  display: block;
  transform: translateY(102%);
}
.reveal-lines.is-in .rl > span {
  transform: none;
  transition: transform 0.95s var(--ease);
  transition-delay: calc(var(--i, 0) * 80ms);
}

/* ------------------------------------------------------- 31. UTILITIES */

/* Line-reveal indices, so per-line delays do not need inline styles. */
.i-0 { --i: 0; } .i-1 { --i: 1; } .i-2 { --i: 2; } .i-3 { --i: 3; } .i-4 { --i: 4; }
.i-5 { --i: 5; } .i-6 { --i: 6; } .i-7 { --i: 7; } .i-8 { --i: 8; } .i-9 { --i: 9; }

/* Reveal stagger steps, so delays do not need inline styles. */
.d-1 { --d: 90ms; }
.d-2 { --d: 170ms; }
.d-3 { --d: 250ms; }
.d-4 { --d: 330ms; }

/* Text tones for use on dark bands. */
.u-on-dark { color: #C9CBC9; }
.u-on-dark-quiet { color: var(--concrete-2); }

.u-mt-0 { margin-top: 0; }
.u-mt-1 { margin-top: 1rem; }
.u-mt-2 { margin-top: 2rem; }
.u-mt-3 { margin-top: clamp(2.25rem, 4.5vw, 3.75rem); }
.u-mb-1 { margin-bottom: 1rem; }
.u-mb-2 { margin-bottom: 2rem; }
.u-mb-3 { margin-bottom: clamp(2rem, 4vw, 3.25rem); }
.u-flow > * + * { margin-top: 1.15em; }
.u-nowrap { white-space: nowrap; }

/* ------------------------------------------------- 32. REDUCED MOTION */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  [data-reveal], [data-reveal='mask'] { opacity: 1 !important; transform: none !important; clip-path: none !important; }
  .reveal-lines .rl > span { transform: none !important; }
  .hero__media img { transform: none !important; }
  .hero__scroll-line::after { animation: none; }
  .preload { display: none; }
}

/* ------------------------------------------------------ 33. PRINT */

@media print {
  .header, .quickbar, .mobilenav, .progress, .preload, .hero__scroll, .lightbox { display: none !important; }
  body { background: #fff; color: #000; padding: 0; }
  .hero { min-height: auto; color: #000; }
  .hero__media, .hero__scrim, .hero__grain { display: none; }
  a[href^='http']::after { content: ' (' attr(href) ')'; font-size: 0.8em; }
}

/* =========================================================================
   19. MOTION LAYER
   Scroll-driven and pointer-driven behaviour added on top of the static
   design. Every rule here degrades to the static layout when JavaScript is
   off or when the visitor asks for reduced motion, which is handled once at
   the foot of this file rather than per component.
   ========================================================================= */

/* ---------------------------------------------------------- hero video */

/* The still is the base layer and always paints. The clip is layered over it
   and only fades in once it can actually play, so a slow connection or a
   codec refusal degrades to exactly the photograph that was there before. */
.hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.1s var(--ease);
  filter: brightness(1.14) contrast(1.04) saturate(0.96);
  pointer-events: none;
}
.hero__video.is-ready { opacity: 1; }

/* ------------------------------------------------------------- marquee */

/* A continuously travelling strip. The track is duplicated in the markup and
   the animation moves exactly one copy's width, so the seam never lands on
   screen and the loop reads as endless at any viewport width. */
.marquee {
  --marquee-secs: 34s;
  position: relative;
  overflow: hidden;
  padding-block: clamp(1.1rem, 2.4vw, 1.9rem);
  border-block: 1px solid var(--rule);
  background: var(--bg);
  user-select: none;
}
.is-dark .marquee, .marquee--dark {
  background: var(--ink);
  border-color: rgba(244, 243, 240, 0.16);
}

.marquee__track {
  display: flex;
  width: max-content;
  will-change: transform;
  animation: marquee-run var(--marquee-secs) linear infinite;
}
.marquee--reverse .marquee__track { animation-direction: reverse; }
.marquee:hover .marquee__track { animation-play-state: paused; }

.marquee__group { display: flex; flex: none; }

@keyframes marquee-run {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* ------------------------------------------------------- counting stats */

/* Reserve the final width before the count starts, otherwise the row shifts
   sideways on every tick while the digits grow. */
.count { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------- parallax */

[data-parallax] { will-change: transform; }
[data-parallax] > img,
[data-parallax] > picture > img { transform: scale(1.14); }

/* ---------------------------------------------- sticky editorial column */

/* The statement rides alongside the prose instead of stranding a column of
   empty page beneath it. */
/* Nothing to pin any more: the statement sits above the prose rather than
   beside it, so there is no second column for it to ride alongside. */






/* ---------------------------------------------------- process, animated */

.process { position: relative; }

/* A rail that fills as the reader moves through the steps. It sits in the
   gutter the step numbers already occupy, so it costs no extra layout. */
.process__rail {
  position: absolute;
  inset-block: 0;
  inset-inline-start: clamp(1.5rem, 3vw, 2.5rem);
  width: 2px;
  background: var(--rule);
  overflow: hidden;
  pointer-events: none;
}
.is-dark .process__rail { background: rgba(244, 243, 240, 0.18); }
.process__rail::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: var(--fill, 0%);
  background: var(--red);
  transition: height 0.35s linear;
}
@media (max-width: 640px) { .process__rail { display: none; } }

.process__step {
  transition: background var(--t-mid) var(--ease);
}
.process__step::before {
  transition: color var(--t-mid) var(--ease), transform var(--t-mid) var(--ease);
  color: var(--concrete-2);
}
.process__step.is-current::before { color: var(--red); transform: scale(1.18); transform-origin: left center; }
.process__step.is-current .u-h4 { color: var(--red-text); }
.is-dark .process__step.is-current .u-h4 { color: var(--red-text-dark); }

/* ------------------------------------------------------ magnetic controls */

[data-magnetic] { will-change: transform; }

/* ------------------------------------------------- word-by-word headings */

.reveal-words .w {
  display: inline-block;
  transform: translateY(0.9em);
  opacity: 0;
}
.reveal-words.is-in .w {
  transform: none;
  opacity: 1;
  transition: transform 0.72s var(--ease), opacity 0.52s linear;
  transition-delay: calc(var(--w, 0) * 34ms);
}

/* --------------------------------------------------- swatch entry stagger */

.swatches [data-stagger] {
  opacity: 0;
  transform: translateY(18px) scale(0.965);
}
.swatches.is-in [data-stagger] {
  opacity: 1;
  transform: none;
  transition: opacity 0.5s linear, transform 0.66s var(--ease);
  transition-delay: calc(var(--s, 0) * 42ms);
}
.swatch__tile { transition: transform var(--t-mid) var(--ease); }
.swatch:hover .swatch__tile { transform: scale(1.05); }

/* ------------------------------------------------------------ scroll cue */

/* The whole page is nudged by scroll velocity. Tiny on purpose: it registers
   as weight rather than as an effect. */
.skewable { will-change: transform; }

/* ------------------------------------------------- reduced motion, once */

@media (prefers-reduced-motion: reduce) {
  .section--smoke::before, .section--umber::before { animation: none; transform: none; }
  .marquee__track { animation: none; transform: none; }
  .hero__video { display: none; }
  .reveal-words .w { transform: none; opacity: 1; }
  .swatches [data-stagger] { opacity: 1; transform: none; }
  [data-parallax] > img,
  [data-parallax] > picture > img { transform: none; }
  .process__rail::after { transition: none; }
}

/* The answers sit in their own column with the question heading pinned beside
   them, rather than in a narrow strip with half the row left empty. */
.spread--faq { grid-template-columns: 0.82fr 1.18fr; }
.spread--faq .u-lead { margin-top: 1.2rem; max-width: 26rem; }
@media (max-width: 900px) { .spread--faq { grid-template-columns: 1fr; } }

/* The manufacturer strip travels rather than sitting still. It is one composite
   image, so duplicating it end to end tiles cleanly and the seam never shows. */
.marquee--logos {
  border: 0;
  background: transparent;
  padding-block: 0;
  /* Fade the ends so logos arrive and leave rather than being cut by the edge. */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 9%, #000 91%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 9%, #000 91%, transparent);
}
/* No padding on the group. The animation travels exactly one group's width, so
   any padding shows up as a gap at the seam and only at the seam, which is what
   made the loop visible. The composite already carries its own spacing between
   logos; the margin below reproduces that spacing across the join. */
.marquee--logos .marquee__group { align-items: center; padding-inline: 0; }
.marquee--logos .partners__strip { margin-inline-end: clamp(2rem, 5vw, 4.5rem); }
.marquee--logos .partners__strip { height: clamp(2rem, 3.4vw, 2.75rem); width: auto; max-width: none; }

/* ------------------------------------------------- 20. OPENING STATEMENT */

/* Laid out as a specification sheet rather than a page of prose: a bordered
   sheet on a drawn grid, a spec block in the top corner, the work broken into
   numbered cells, and a caption strip along the foot. It suits a trade that
   already works from drawings, and it gives the section structure to look at
   instead of three columns of body copy. */

.sheet-section {
  position: relative;
  /* Matte black ground. The sheet reads as a drawing laid on a bench rather
     than a panel sitting in the page. */
  background: var(--ink);
  overflow: hidden;
}

/* The grid behind the sheet. Faint enough to read as paper rather than as a
   pattern, and it fades out top and bottom so it never meets a section edge. */
.sheet-section::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, rgba(244, 243, 240, 0.055) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(244, 243, 240, 0.055) 1px, transparent 1px);
  background-size: 68px 68px;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 18%, #000 82%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 18%, #000 82%, transparent);
  pointer-events: none;
}
.sheet-section > .wrap { position: relative; z-index: 1; }

.sheet {
  border: 1px solid var(--rule);
  background: var(--matte-2);
  /* A drop shadow is invisible against black. The sheet lifts off the ground
     with a thin light edge instead. */
  box-shadow: 0 0 0 1px rgba(244, 243, 240, 0.08), 0 40px 80px -60px rgba(0, 0, 0, 0.9);
}

/* ---- head: copy left, spec block right, photograph bleeding in behind ---- */

.sheet__head {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
  padding: clamp(1.6rem, 3.4vw, 3rem);
  border-bottom: 1px solid var(--rule);
  overflow: hidden;
  isolation: isolate;
  min-height: clamp(19rem, 30vw, 26rem);
}

/* A short red segment on the sheet's top edge, the way a drawing marks its
   datum. It used to sit on the rule under the head, which was fine while the
   cells below were white and wrong the moment they began with a photograph. */
.sheet { position: relative; }
.sheet::before {
  content: '';
  position: absolute;
  inset-inline-start: -1px;
  top: -1px;
  width: clamp(3.5rem, 9vw, 8rem);
  height: 3px;
  background: var(--red);
  z-index: 3;
}

/* The head carries the picture for whichever division the reader is pointing
   at. Both shots are in the markup and stacked; only the opacity changes, so
   there is no load on switch and no flash of an empty frame. */
.sheet__stage {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  width: 58%;
  z-index: -1;
}
.sheet__shot {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.5s var(--ease);
}
.sheet__shot.is-active { opacity: 1; }
.sheet__shot img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 58%;
}
/* Blended into the sheet from the left so the photograph arrives rather than
   sitting in a box, and so the heading never has to fight it. */
.sheet__stage::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  background: linear-gradient(100deg, #FFFFFF 0%, rgba(255,255,255,0.92) 12%, rgba(255,255,255,0.28) 42%, rgba(255,255,255,0) 68%);
}
/* No pointer to hover with below this width, so the swap has nothing to drive
   it and one of the two divisions would simply never be seen. Both shots show
   instead, side by side, in the order the rows appear underneath. */
@media (max-width: 900px) {
  .sheet__stage {
    position: relative;
    inset: auto;
    width: auto;
    z-index: 0;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1px;
    background: var(--rule);
    margin: clamp(1.4rem, 3vw, 2rem) calc(clamp(1.6rem, 3.4vw, 3rem) * -1)
            calc(clamp(1.6rem, 3.4vw, 3rem) * -1);
    border-top: 1px solid var(--rule);
  }
  .sheet__stage::after { display: none; }
  .sheet__shot { position: relative; inset: auto; opacity: 1; aspect-ratio: 4 / 3; }
  /* The resting plate is the answer to "neither is hovered", which cannot
     happen without a pointer, so it has no job here. */
  .sheet__shot--default { display: none; }
}
@media (max-width: 520px) {
  .sheet__stage { grid-template-columns: 1fr; }
  .sheet__shot { aspect-ratio: 16 / 10; }
}

.sheet__intro { position: relative; z-index: 2; max-width: 34rem; }

.sheet__index {
  margin: 0 0 clamp(0.9rem, 2vw, 1.4rem);
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}

.sheet__title {
  margin: 0;
  font-family: var(--display);
  font-size: clamp(1.85rem, 4vw, 3.4rem);
  font-weight: 800;
  line-height: 0.98;
  letter-spacing: -0.032em;
  text-transform: uppercase;
  color: var(--ink);
  text-wrap: balance;
}

.sheet__lead {
  margin: clamp(0.9rem, 2vw, 1.35rem) 0 0;
  max-width: 34ch;
  color: var(--muted);
  text-wrap: pretty;
}

/* ---- the spec block ---- */

.sheet__spec {
  position: relative;
  z-index: 2;
  margin: 0;
  /* A label plate. The block used to sit directly on a near-white texture; a
     photograph of a gym floor underneath it would leave 12px grey labels
     unreadable, so it carries its own ground. */
  background: rgba(255, 255, 255, 0.94);
  border: 1px solid var(--rule);
  padding: clamp(0.7rem, 1.4vw, 1rem) clamp(0.85rem, 1.6vw, 1.15rem);
  display: grid;
  gap: 0.45rem;
  font-family: var(--display);
  font-size: var(--fs-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.sheet__spec > div {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: clamp(1rem, 3vw, 2.5rem);
  align-items: baseline;
}
.sheet__spec dt { color: var(--muted); font-weight: 600; }
.sheet__spec dd { margin: 0; color: var(--ink); font-weight: 800; letter-spacing: 0.08em; }
@media (max-width: 620px) {
  .sheet__head { grid-template-columns: 1fr; }
  .sheet__spec { margin-top: 0.5rem; }
}

/* ---- the numbered cells ---- */

/* One pixel of rule showing through a gap, so every cell is divided by a single
   hairline and the outer edges stay square against the sheet border. */
.sheet__cells {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--rule);
}
@media (max-width: 900px) { .sheet__cells { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .sheet__cells { grid-template-columns: 1fr; } }

/* Two cells rather than four, each carrying the division's own plate. */
.sheet__cells--divisions { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 700px) { .sheet__cells--divisions { grid-template-columns: 1fr; } }

.sheet__cell {
  background: var(--matte-2);
  padding: clamp(1.35rem, 2.6vw, 2.25rem);
  transition: background var(--t-mid) var(--ease);
}
.sheet__cell:hover { background: var(--bone); }

.sheet__num {
  display: block;
  font-family: var(--display);
  font-size: clamp(2.75rem, 5.4vw, 4.25rem);
  font-weight: 800;
  line-height: 0.9;
  letter-spacing: -0.04em;
  /* Outlined, not filled: it reads as a drawing callout and stays behind the
     label instead of competing with it. */
  color: transparent;
  -webkit-text-stroke: 2.5px #D8D6D1;
  padding-bottom: clamp(0.85rem, 1.8vw, 1.25rem);
  border-bottom: 1px solid var(--rule);
  margin-bottom: clamp(0.85rem, 1.8vw, 1.25rem);
  transition: -webkit-text-stroke-color var(--t-mid) var(--ease);
}
.sheet__cell:hover .sheet__num { -webkit-text-stroke-color: var(--red); }

.sheet__cell h3 {
  margin: 0 0 0.5rem;
  font-family: var(--display);
  font-size: var(--fs-h4);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.sheet__cell p { margin: 0; font-size: 0.9375rem; color: var(--muted); }

/* ---- foot strip ---- */

.sheet__foot {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.6rem 1.5rem;
  padding: clamp(0.85rem, 1.8vw, 1.15rem) clamp(1.6rem, 3.4vw, 3rem);
  border-top: 1px solid var(--rule);
  background: var(--bone);
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---- division cells ---- */

.sheet__division {
  display: block;
  height: 100%;
  color: inherit;
  text-decoration: none;
}
.sheet__division h3 { font-size: clamp(1.4rem, 2.6vw, 2.1rem); text-transform: uppercase; }
.sheet__division p { max-width: 40ch; }
.sheet__go { display: inline-flex; margin-top: clamp(0.9rem, 1.8vw, 1.35rem); }
.sheet__division:focus-visible { outline: 2px solid var(--red); outline-offset: -6px; }

/* The cell the reader is pointing at is marked, so the head picture and the
   text below it are visibly the same thing. */
.sheet__cells--divisions .sheet__cell.is-active { background: var(--bone); }
.sheet__cells--divisions .sheet__cell.is-active .sheet__num { -webkit-text-stroke-color: var(--red); }
.sheet__cells--divisions .sheet__cell.is-active .sheet__go { background-size: 100% 2px; color: var(--red-text); }

/* ------------------------------------------------ 21. DARK SECTION GROUNDS */

/* Both grounds are painted with gradients rather than an image, so they cost
   nothing to load and cannot band on a wide screen. The haze is kept weak on
   purpose: every point on these surfaces still has to clear 4.5:1 against the
   red used for small text, and that is what sets the ceiling, not taste. */

.section--smoke,
.section--umber { position: relative; isolation: isolate; overflow: hidden; }

.section--smoke::before,
.section--umber::before {
  content: '';
  position: absolute;
  /* Oversized so the drift below can never bring an edge of this layer into
     view, and so the gradients keep their shape as it moves. */
  inset: -14%;
  z-index: -1;
  pointer-events: none;
  will-change: transform;
  animation: ground-drift 46s ease-in-out infinite alternate;
}

/* Slow enough that nobody watches it happen; present enough that the section
   is never completely still. */
@keyframes ground-drift {
  from { transform: translate3d(-2.2%, -1.4%, 0) scale(1.02); }
  to   { transform: translate3d(2.2%, 1.4%, 0) scale(1.06); }
}

/* Fine grain over both. Without it a large field of near-black bands badly on
   an 8-bit display. */
.section--smoke::after,
.section--umber::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0.19;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

/* Smoky black: soft plumes drifting across a near-black ground. */
.section--smoke { background-color: #0A0B0C; }
.section--smoke::before {
  background:
    radial-gradient(122% 78% at 16% 8%,  rgba(146, 152, 156, 0.075), transparent 62%),
    radial-gradient(96% 72% at 86% 74%,  rgba(120, 126, 130, 0.055), transparent 64%),
    radial-gradient(78% 64% at 52% 46%,  rgba(96, 100, 104, 0.040), transparent 72%);
}

/* Brown and black, kept cool rather than tan: the warmth sits in the shadows
   and the highlights stay grey, which is how concrete under a work light
   actually reads. */
.section--umber { background-color: #14100E; }
.section--umber::before {
  background:
    radial-gradient(120% 82% at 22% 10%, rgba(150, 118, 92, 0.085), transparent 62%),
    radial-gradient(94% 70% at 84% 80%,  rgba(112, 92, 76, 0.065), transparent 66%),
    radial-gradient(80% 66% at 56% 44%,  rgba(88, 84, 82, 0.045), transparent 72%),
    linear-gradient(160deg, rgba(0, 0, 0, 0.35), transparent 46%);
}

/* Small red text on a hazed ground.
   --red-text-dark clears 4.5:1 on flat --ink with no margin at all, so the
   moment a section carries smoke or umber over that ink, every small red label
   drops to about 3.2:1. No saturated red can pass 4.5:1 on a ground this
   light, so small text goes to bone here and red is kept for the large names,
   the numerals and the marks, all of which only owe 3:1. */
.section--smoke .svcindex__more,
.section--umber .svcindex__more { color: var(--bone); }
.section--smoke .svcindex__more:hover,
.section--smoke .svcindex__more:focus-visible,
.section--umber .svcindex__more:hover,
.section--umber .svcindex__more:focus-visible { color: var(--white); }

.section--smoke .svcindex__row.is-active .svcindex__num,
.section--umber .svcindex__row.is-active .svcindex__num { color: var(--bone); }

.section--smoke .link:hover,
.section--smoke .link:focus-visible,
.section--umber .link:hover,
.section--umber .link:focus-visible { color: var(--bone); }

/* Red used as a mark rather than as text owes 3:1. #DE181C manages that on flat
   ink and 2.9:1 once the haze is over it, so marks in these sections take the
   lighter variant, which holds the same hue and clears the bar. */
.section--smoke .u-eyebrow::before,
.section--umber .u-eyebrow::before,
.section--smoke .speclist svg,
.section--umber .speclist svg,
.section--smoke .svcindex__row.is-active .svcindex__arrow,
.section--umber .svcindex__row.is-active .svcindex__arrow { color: var(--red-text-dark); }
.section--smoke .u-eyebrow::before,
.section--umber .u-eyebrow::before { background: var(--red-text-dark); }

/* ------------------------------------------------------------ 22. STEPS */

/* A stack of numbered cards with the sequence drawn between them, rather than
   five rows sharing one long rule. The order is the point of this section, so
   the arrows carry it. */

.section__head--center { text-align: center; }
.section__head--center .u-lead { margin-inline: auto; max-width: 46rem; }
.u-eyebrow--center { justify-content: center; }

.rule-short {
  display: block;
  width: 3.25rem;
  height: 2px;
  margin: clamp(1.4rem, 3vw, 2rem) auto 0;
  background: var(--red);
}
.is-dark .rule-short { background: var(--red-text-dark); }

.steps { list-style: none; margin: 0; padding: 0; }
.steps__item { position: relative; }

/* The cards stack. Each one sticks under the header at its own offset, so as
   the next card rises it covers the one before and leaves a sliver of it
   showing. The stack builds as the reader moves through the sequence, which is
   what the section is about, and it takes far less page than five cards laid
   end to end.

   Sticky needs somewhere to travel, which is what the item's own height gives
   it: the card is the visible part and the space beneath it is the run. */
:root {
  --steps-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 24'%3E%3Cpath d='M6 0v20M1 15l5 6 5-6' fill='none' stroke='%23000' stroke-width='2'/%3E%3C/svg%3E");
}

.steps { --steps-top: calc(var(--header-h) + clamp(1rem, 3vh, 2.25rem)); }

.steps__item {
  position: sticky;
  top: calc(var(--steps-top) + var(--i, 0) * 14px);
  /* The run between one card pinning and the next covering it. Too short and
     the whole stack assembles in half a flick of the wheel. */
  --run: clamp(4.5rem, 15vh, 10rem);
  padding-bottom: var(--run);
}
.steps__item:last-child { --run: 0px; padding-bottom: 0; }

/* The arrow sits in the run below its own card, so it trails that card while
   it is pinned and is covered by the next one as it rises. Drawn rather than
   typed, so it can never pick up a font fallback, and hidden from assistive
   tech because the ordered list already carries the sequence. */
.steps__item:not(:last-child)::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: calc(var(--run) / 2 - 11px);
  width: 11px;
  height: 22px;
  transform: translateX(-50%);
  background: var(--concrete);
  -webkit-mask: var(--steps-arrow) center / contain no-repeat;
          mask: var(--steps-arrow) center / contain no-repeat;
}
.is-dark .steps__item:not(:last-child)::after { background: var(--concrete-2); }

@media (max-width: 700px) {
  .steps__item { top: calc(var(--steps-top) + var(--i, 0) * 9px); }
}

.steps__card {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(1rem, 2.2vw, 1.6rem);
  align-items: start;
  padding: clamp(1.35rem, 2.8vw, 2.1rem);
  background: var(--matte-2);
  border: 1px solid var(--rule);
  /* Cast downward and hard, so the card reads as lying on the one beneath it
     rather than floating over the page. */
  box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.6), 0 22px 34px -26px rgba(10, 11, 12, 0.42);
  transition: box-shadow var(--t-mid) var(--ease);
}
.is-dark .steps__card {
  background: var(--ink-2);
  border-color: rgba(244, 243, 240, 0.12);
  box-shadow: none;
}

.steps__badge {
  display: grid;
  place-items: center;
  width: clamp(2.5rem, 4.4vw, 3.1rem);
  aspect-ratio: 1;
  background: var(--ink);
  color: var(--bone);
  font-family: var(--display);
  font-size: var(--fs-small);
  font-weight: 800;
  letter-spacing: 0.06em;
  transition: background var(--t-mid) var(--ease);
}

.steps__body h3 {
  margin: 0 0 0.4rem;
  font-family: var(--display);
  font-size: var(--fs-h4);
  font-weight: 700;
  letter-spacing: -0.005em;
}
.steps__body p { margin: 0; max-width: 62ch; color: var(--muted); }
.is-dark .steps__body p { color: var(--concrete-2); }

/* The card the reader is level with lifts and takes the accent, so the stack
   reads as a sequence being worked through rather than five equal blocks. */
.steps__item.is-current .steps__card {
  box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.6), 0 30px 46px -26px rgba(10, 11, 12, 0.5);
}
.steps__item.is-current .steps__badge { background: var(--red); }

@media (max-width: 560px) {
  .steps__card { grid-template-columns: 1fr; gap: 0.85rem; }
}

@media (prefers-reduced-motion: reduce) {
  .steps__card { transition: none; }
  /* Sticky stacking is movement the reader did not ask for, and it hides four
     of the five cards behind the fifth while it does it. Laid out flat here. */
  .steps__item { position: static; padding-bottom: clamp(1rem, 2vw, 1.5rem); }
}

/* ---------------------------------------------------------- HERO ENTRANCE */

/* Everything in the hero arrives from the left, in reading order. The headline
   wipes in behind its own line masks; the rest slide. The starting state is
   only ever applied by script, so with JavaScript off the hero is simply
   there, fully legible, which is the one thing this must not get wrong. */
.hero.is-arming .hero__inner > * {
  opacity: 0;
  transform: translateX(-44px);
}

/* The stat row travels further and lands slower than the rest. At the same 44px
   as the paragraph above it the movement was there but nobody saw it: it is the
   last thing to arrive, on the busiest line of the hero, and it needs enough
   distance to read as an entrance. */
.hero.is-arming .hero__foot.is-split > * {
  opacity: 0;
  transform: translateX(-130px);
}
.hero.is-entered .hero__foot.is-split > * {
  transition: opacity 0.7s linear, transform 1.15s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(var(--e, 0) * 135ms);
}
/* The row itself stays put once its children are the ones travelling. */
.hero.is-arming .hero__foot.is-split,
.hero.is-entered .hero__foot.is-split { opacity: 1; transform: none; transition: none; }

.hero.is-entered .hero__inner > * {
  opacity: 1;
  transform: none;
  transition: opacity 0.62s linear, transform 0.95s var(--ease);
  transition-delay: calc(var(--e, 0) * 105ms);
}

@media (prefers-reduced-motion: reduce) {
  .hero.is-arming .hero__inner > *,
  .hero.is-entered .hero__inner > *,
  .hero.is-arming .hero__foot.is-split > *,
  .hero.is-entered .hero__foot.is-split > * { opacity: 1; transform: none; transition: none; }
  .hero__title .rl > span { transform: none; }
}

/* --------------------------------------------------------- 23. FLAKE ACCORDION */

/* An expanding row: the open panel carries the colour's name, tone and
   description, the rest stand as slim strips with a number and the name set on
   its side. Widths are driven by grid-template-columns rather than flex-grow,
   because a grid track animates from a known value to a known value and cannot
   be dragged around by the content inside it. */

.flakes {
  display: grid;
  grid-template-columns: 3.4fr 1fr 1fr 1fr 1fr 1fr;
  gap: 2px;
  height: clamp(20rem, 44vh, 30rem);
  background: rgba(244, 243, 240, 0.14);
  transition: grid-template-columns 0.62s var(--ease);
}
.is-dark .flakes { background: rgba(244, 243, 240, 0.14); }

.flakes__panel {
  position: relative;
  display: block;
  min-width: 0;
  padding: 0;
  border: 0;
  background: var(--ink-2);
  overflow: hidden;
  cursor: pointer;
  text-align: left;
  color: var(--bone);
}
.flakes__panel img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.8s var(--ease), filter 0.5s var(--ease);
  filter: saturate(0.82) brightness(0.72);
}
.flakes__panel.is-open img { filter: none; transform: scale(1.03); }

/* The collapsed panels are dimmed by a filter, so their labels sit on a known
   surface. The open panel is not, which leaves its card lying on a bright and
   very busy flake photograph, so the scrim under it has to do all the work. */
.flakes__panel.is-open::after {
  background: linear-gradient(to top,
    rgba(10, 11, 12, 0.95) 0%,
    rgba(10, 11, 12, 0.88) 26%,
    rgba(10, 11, 12, 0.38) 52%,
    transparent 76%);
}

/* A scrim only where type sits, so the flake itself is never dulled to make
   room for a label. */
/* Scrimmed at the top, where the collapsed label sits, and lightly at the foot
   so the panel has a base. The open panel replaces this entirely, because its
   card sits at the bottom and its flake should not be dulled at the top. */
.flakes__panel::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgba(10, 11, 12, 0.82) 0%, rgba(10, 11, 12, 0.28) 28%, transparent 54%),
    linear-gradient(to top, rgba(10, 11, 12, 0.62) 0%, rgba(10, 11, 12, 0.1) 34%, transparent 58%);
}

/* ---- collapsed strip ---- */

.flakes__strip {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  /* Number and name together at the head of the strip, so the row reads left
     to right along one line instead of along its foot. */
  justify-content: flex-start;
  gap: clamp(0.5rem, 1vw, 0.8rem);
  padding: clamp(0.9rem, 1.8vw, 1.35rem) clamp(0.7rem, 1.2vw, 1rem);
  opacity: 1;
  transition: opacity 0.34s linear;
}
.flakes__panel.is-open .flakes__strip { opacity: 0; pointer-events: none; }

.flakes__num {
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 800;
  letter-spacing: 0.14em;
  color: var(--concrete-2);
}
/* Set horizontally and allowed to wrap. A collapsed strip is only about 110px
   wide at the narrowest desktop width this row is used at, and the longest
   name here is SOLAR FLARE 1/8", so the label has to be able to take a second
   line rather than being held on one and clipped. */
.flakes__edge {
  font-family: var(--display);
  font-size: 0.6875rem;
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  text-wrap: balance;
  hyphens: none;
}
@media (min-width: 1200px) { .flakes__edge { font-size: 0.75rem; letter-spacing: 0.11em; } }

/* ---- open card ---- */

.flakes__card {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  z-index: 1;
  display: block;
  padding: clamp(1.1rem, 2.2vw, 1.75rem);
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.34s linear 0.14s, transform 0.5s var(--ease) 0.14s;
}
.flakes__panel.is-open .flakes__card { opacity: 1; transform: none; }

.flakes__tone {
  display: block;
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--bone);
  margin-bottom: 0.5rem;
  display: flex;
  align-items: center;
  gap: 0.55rem;
}
.flakes__tone::before {
  content: '';
  width: 1.4rem;
  height: 2px;
  background: var(--red);
  flex: none;
}
.flakes__name {
  display: block;
  font-family: var(--display);
  font-size: clamp(1.25rem, 2.2vw, 1.9rem);
  font-weight: 800;
  letter-spacing: -0.015em;
  text-transform: uppercase;
  line-height: 1.05;
}
.flakes__desc {
  display: block;
  margin-top: 0.55rem;
  max-width: 40ch;
  font-size: 0.9375rem;
  color: #C8CAC8;
}

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

/* Stacked on a phone: an expanding row of six needs width this narrow screen
   does not have, and a 40px strip cannot hold a legible label. */
@media (max-width: 760px) {
  .flakes {
    grid-template-columns: 1fr 1fr;
    grid-auto-rows: clamp(11rem, 34vw, 15rem);
    height: auto;
    transition: none;
  }
  .flakes__panel img { filter: none; }
  .flakes__strip { display: none; }
  .flakes__card { opacity: 1; transform: none; transition: none; padding: 0.9rem; }
  .flakes__desc { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .flakes { transition: none; }
  .flakes__panel img, .flakes__card, .flakes__strip { transition: none; }
}

/* ------------------------------------------------- 24. CARBON FIBRE SHEET */

/* The sheet is woven rather than white. The weave is drawn with gradients, not
   an image: it tiles at any size, costs no request, and stays crisp on a
   retina screen where a bitmap of a 20px twill would not.

   Flipping the ground from #FFF to near-black inverts every contrast decision
   inside the sheet, so all of them are restated here rather than left to the
   light-surface rules above. */

.sheet {
  --carbon: #131313;
  --carbon-line: rgba(244, 243, 240, 0.10);
  background-color: var(--carbon);
  background-image:
    linear-gradient(27deg,  #171717 5px, transparent 5px),
    linear-gradient(207deg, #171717 5px, transparent 5px),
    linear-gradient(27deg,  #202020 5px, transparent 5px),
    linear-gradient(207deg, #202020 5px, transparent 5px),
    linear-gradient(90deg,  #1a1a1a 10px, transparent 10px),
    linear-gradient(#1c1c1c 25%, #191919 25%, #191919 50%, transparent 50%,
                    transparent 75%, #222222 75%, #222222);
  background-position: 0 5px, 10px 0, 0 10px, 10px 5px, 0 0, 0 0;
  background-size: 20px 20px;
  border-color: rgba(244, 243, 240, 0.16);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6), 0 40px 80px -60px rgba(0, 0, 0, 0.9);
  color: var(--bone);
}

.sheet__head { border-bottom-color: var(--carbon-line); }
.sheet__index { color: var(--concrete-2); }
.sheet__title { color: var(--bone); }
.sheet__lead  { color: var(--concrete-2); }

/* The photograph blends into the weave now, not into white. */
.sheet__stage::after {
  background:
    linear-gradient(200deg, rgba(19, 19, 19, 0.92) 0%, rgba(19, 19, 19, 0.66) 18%, rgba(19, 19, 19, 0) 44%),
    linear-gradient(100deg, var(--carbon) 4%, rgba(19, 19, 19, 0.9) 24%,
                    rgba(19, 19, 19, 0.4) 56%, rgba(19, 19, 19, 0.06) 100%);
}

/* The spec plate keeps its job of giving the block a known surface; it is just
   a dark plate now. */
.sheet__spec {
  background: rgba(10, 10, 10, 0.82);
  border-color: rgba(244, 243, 240, 0.18);
}
.sheet__spec dt { color: var(--concrete-2); }
.sheet__spec dd { color: var(--bone); }

/* Cells let the weave through, with the divider drawn in light. */
.sheet__cells { background: var(--carbon-line); }
.sheet__cell  { background: transparent; }
.sheet__cell:hover { background: rgba(244, 243, 240, 0.04); }
.sheet__cells--divisions .sheet__cell.is-active { background: rgba(244, 243, 240, 0.055); }

/* The outline was drawn at a quarter opacity against a woven ground and all
   but vanished. Thicker and much closer to bone, so the callout actually
   reads as a callout. */
.sheet__num {
  -webkit-text-stroke-width: 2.5px;
  -webkit-text-stroke-color: rgba(244, 243, 240, 0.62);
  border-bottom-color: var(--carbon-line);
}
.sheet__cell:hover .sheet__num,
.sheet__cells--divisions .sheet__cell.is-active .sheet__num {
  /* A mark, so it owes 3:1. Brand red manages 2.9:1 on this weave; the lighter
     variant holds the same hue and clears it. */
  -webkit-text-stroke-color: var(--red-text-dark);
}

.sheet__division h3, .sheet__cell h3 { color: var(--bone); }
.sheet__division p,  .sheet__cell p  { color: var(--concrete-2); }

/* Small text cannot be red on a ground this light-shifted, the same as in the
   smoke and umber sections. The link reads in bone and takes its accent from
   the rule under it. */
.sheet__go { color: var(--bone); background-image: linear-gradient(var(--red-text-dark), var(--red-text-dark)); }
.sheet__cells--divisions .sheet__cell.is-active .sheet__go,
.sheet__division:hover .sheet__go,
.sheet__division:focus-visible .sheet__go { color: var(--white); background-size: 100% 2px; }

.sheet__foot {
  background: rgba(0, 0, 0, 0.42);
  border-top-color: var(--carbon-line);
  color: var(--concrete-2);
}

/* -------------------------------------------------------- 25. CLIMATE */

/* Not a picture beside a column of prose. A full-bleed band carries the
   heading, then the three forces the copy actually names are broken out as
   their own row, and what we do about them sits underneath as the answer.
   Same facts, read in the order they matter. */

.climate { padding-block: 0 var(--section); }

.climate__banner {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: clamp(20rem, 48vh, 34rem);
  overflow: hidden;
  isolation: isolate;
}
.climate__shot { position: absolute; inset: 0; z-index: -2; }
.climate__shot img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 62%; }

/* Weighted to the bottom left, where the heading sits, so the slab and its
   joint stay readable across the rest of the band. */
.climate__banner::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(to top, rgba(12, 9, 8, 0.94) 0%, rgba(12, 9, 8, 0.55) 34%, rgba(12, 9, 8, 0.12) 68%),
    linear-gradient(100deg, rgba(12, 9, 8, 0.8) 0%, rgba(12, 9, 8, 0.1) 52%);
}
.climate__banner-inner {
  width: 100%;
  /* The data band is pulled up over this edge, so the heading has to sit above
     where it lands or the band cuts the second line off. */
  padding-block: clamp(2rem, 5vw, 3.5rem)
                 calc(clamp(3.5rem, 8vw, 7rem) + clamp(1.5rem, 3vw, 2.5rem));
}
.climate__banner h2 { color: var(--bone); margin: 0; }

.climate__body { padding-top: clamp(2rem, 5vw, 3.5rem); }

.climate__lead {
  margin: 0 0 clamp(2rem, 4.5vw, 3.5rem);
  max-width: 46rem;
  font-size: clamp(1.15rem, 1.9vw, 1.6rem);
  line-height: 1.4;
  letter-spacing: -0.012em;
  color: var(--bone);
  text-wrap: pretty;
}




/* --------------------------------------------------- DROP-IN STAGGER */

/* Children arrive from above in sequence. The container itself stays put, so
   only what is inside it moves, and the reveal observer's own backstop still
   covers the whole thing: if the trigger never fires, everything is shown. */
[data-reveal='drop'] { opacity: 1; transform: none; }
[data-reveal='drop'] > * {
  opacity: 0;
  transform: translateY(-68px) scale(0.985);
  transform-origin: top center;
}
[data-reveal='drop'].is-in > * {
  opacity: 1;
  transform: none;
  /* Long, and eased so almost all of the travel happens early and the last few
     pixels take their time. That slow settle is what makes it read as a camera
     move instead of a slide. The opacity runs shorter than the transform, so a
     row is fully present while it is still coming to rest. */
  transition: opacity 0.9s linear, transform 1.45s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(var(--d, 0) * 135ms);
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal='drop'] > * { opacity: 1; transform: none; transition: none; }
}


/* ------------------------------------------------------ SCROLL DRIFT */

/* Two halves of a section moving at slightly different rates as the page
   scrolls. It is the cheapest way to make a static column of type feel like it
   has depth behind it, and at this amplitude it registers as weight rather
   than as an effect. */
[data-drift] { will-change: transform; }

@media (prefers-reduced-motion: reduce) {
  [data-drift] { transform: none !important; }
}

/* ------------------------------------------------- 26. PAGE TRANSITIONS */

/* The panel is only ever in the document while script is running, and it lifts
   on a timer regardless, so it cannot leave a page covered. */
.veil {
  position: fixed;
  inset: 0;
  z-index: 900;
  background: var(--ink);
  transform: scaleY(0);
  transform-origin: bottom center;
  pointer-events: none;
  transition: transform 0.46s cubic-bezier(0.7, 0, 0.3, 1);
}
.veil.is-covering { transform: scaleY(1); transform-origin: top center; }
/* Used for one frame on arrival, so the panel starts covering without the
   browser animating it into place from nothing. */
.veil.is-instant { transition: none; }

/* --------------------------------------------------------- HEADER TRAVEL */

.header { transition: transform 0.42s var(--ease), background var(--t-mid) var(--ease); }
.header.is-away { transform: translateY(-100%); }

@media (prefers-reduced-motion: reduce) {
  .veil { display: none; }
  .header, .header.is-away { transform: none; transition: none; }
}

/* ------------------------------------------------------------ 27. PICKER */

/* Options on the left, the matching detail on the right. The reader says which
   of the three they are actually looking at and gets that answer, instead of
   reading all three and working it out. Built on tab semantics, so a keyboard
   moves through it with the arrow keys and a screen reader announces which
   panel is showing. */

.picker {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: clamp(1rem, 2.4vw, 2rem);
  align-items: start;
}
@media (max-width: 900px) { .picker { grid-template-columns: 1fr; } }

.picker__list { list-style: none; margin: 0; padding: 0; display: grid; gap: clamp(0.6rem, 1.2vw, 0.9rem); }

.picker__opt {
  width: 100%;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: clamp(0.85rem, 1.8vw, 1.35rem);
  padding: clamp(1rem, 2vw, 1.4rem) clamp(1.1rem, 2.2vw, 1.6rem);
  background: rgba(244, 243, 240, 0.045);
  border: 1px solid rgba(244, 243, 240, 0.14);
  color: var(--bone);
  text-align: left;
  cursor: pointer;
  transition: background var(--t-mid) var(--ease), border-color var(--t-mid) var(--ease);
}
.picker__opt:hover { background: rgba(244, 243, 240, 0.085); }
.picker__opt.is-active {
  background: #22282A;
  border-color: rgba(244, 243, 240, 0.3);
}
.picker__opt:focus-visible { outline: 2px solid var(--red-text-dark); outline-offset: 2px; }

.picker__num {
  font-family: var(--display);
  font-size: clamp(1.1rem, 2vw, 1.5rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--concrete);
  transition: color var(--t-mid) var(--ease);
}
/* Bone, not red: 12px red measures 3.2:1 on the active grey against a 4.5
   floor, and the arrow beside it already carries the accent. */
.picker__opt.is-active .picker__num { color: var(--bone); }

.picker__text { display: grid; gap: 0.2rem; min-width: 0; }
.picker__text strong {
  font-family: var(--display);
  font-size: var(--fs-h4);
  font-weight: 700;
  letter-spacing: -0.008em;
}
.picker__text span { font-size: 0.9375rem; color: var(--concrete-2); }

.picker__opt svg {
  width: 1.1em; height: 1.1em; flex: none;
  color: var(--concrete);
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity var(--t-mid) var(--ease), transform var(--t-mid) var(--ease), color var(--t-mid) var(--ease);
}
.picker__opt.is-active svg { opacity: 1; transform: none; color: var(--red-text-dark); }

/* ---- the panel ---- */

.picker__stage { position: relative; }

.picker__panel {
  background: #101314;
  border: 1px solid rgba(244, 243, 240, 0.14);
  padding: clamp(1.5rem, 3.2vw, 2.6rem);
}
.picker__panel[hidden] { display: none; }
.picker__panel:focus-visible { outline: 2px solid var(--red-text-dark); outline-offset: 2px; }

.picker__figure {
  margin: 0 0 clamp(1.1rem, 2.4vw, 1.8rem);
  padding-bottom: clamp(1.1rem, 2.4vw, 1.6rem);
  border-bottom: 1px solid rgba(244, 243, 240, 0.16);
  font-family: var(--display);
  font-size: clamp(1.9rem, 4vw, 3.1rem);
  font-weight: 800;
  line-height: 0.92;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  color: var(--bone);
}
.picker__figure span {
  display: block;
  margin-top: 0.7rem;
  font-family: var(--body);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--concrete);
}

.picker__copy { margin: 0 0 1rem; color: var(--concrete-2); }
.picker__copy strong { color: var(--bone); font-weight: 600; }

/* What we do about it, set apart from what is happening. */
.picker__answer {
  margin: 0;
  padding-left: clamp(0.9rem, 1.8vw, 1.25rem);
  border-left: 2px solid var(--red-text-dark);
  color: var(--concrete-2);
}

.picker__actions {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(0.6rem, 1.4vw, 1rem);
  margin-top: clamp(1.4rem, 3vw, 2.2rem);
}

/* The incoming panel settles rather than appearing. */
.picker__panel.is-entering {
  animation: picker-in 0.5s var(--ease) both;
}
@keyframes picker-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .picker__panel.is-entering { animation: none; }
  .picker__opt, .picker__opt svg, .picker__num { transition: none; }
}

/* ------------------------------------------- 28. DARK GROUND CORRECTIONS */

/* The base tokens now describe a dark page. Everything below is a component
   that was written against a light one and needs its assumption reversed.
   Kept together rather than edited in place, so the light-surface rules stay
   readable and this stays one thing to undo. */

/* The page grain multiplied against a light ground. Over a dark one it has to
   lighten, or it just paints the page darker still. */
body::before { mix-blend-mode: overlay; opacity: 0.22; }

/* Small red text does not clear 4.5:1 anywhere on this ground. Red stays on
   the marks and the display type; these all step to bone.
   The callout label was the one this missed on the first pass: 12px red on the
   recessed panel measured 3.84:1. */
.callout__label,
.link:hover, .link:focus-visible,
.faq__q:hover,
.faq__q[aria-expanded='true'],
.footer__list a:hover, .footer__list a:focus-visible,
.footer__legal a:hover,
.lightbox__close:hover,
.steps__item.is-current .u-h4,
.steps__item.is-current h3 { color: var(--bone); }

/* Ghost buttons and chips drew their outline from a dark rule on a light page. */
.btn--ghost { --btn-fg: var(--bone); box-shadow: inset 0 0 0 1.5px rgba(244, 243, 240, 0.28); }
.btn--ghost:hover, .btn--ghost:focus-visible { box-shadow: inset 0 0 0 1.5px var(--red); }
.btn { --btn-bg: var(--bone); --btn-fg: var(--ink); }
.btn:hover, .btn:focus-visible { color: var(--white); }

/* Cards, callouts and tiles: a step down from the ground rather than up, so
   they read as recessed panels and marks on them gain contrast instead of
   losing it. */
.steps__card { background: var(--matte-2); border-color: rgba(244, 243, 240, 0.14); box-shadow: none; }
.steps__body p { color: var(--concrete-2); }
.steps__badge { background: var(--bone); color: var(--ink); }
.steps__item.is-current .steps__badge { background: var(--red); color: var(--white); }

.callout { background: var(--matte-2); border-left-color: var(--red); }
.swatch__tile { background: var(--matte-2); }

.field input, .field textarea, .field select,
.hp input { background: var(--matte-2); color: var(--bone); border-color: rgba(244, 243, 240, 0.2); }
.field label { color: var(--concrete-2); }

/* The stat band was black to stand out from a light page. On a dark one it
   needs the opposite: a plate lighter than the ground. */
.statband__cell { background: var(--matte-2); }

/* The step arrows were drawn in a mid grey for a light page. */
.steps__item:not(:last-child)::after { background: var(--concrete-2); }

/* The sheet section's drawn grid and the sheet's own light edge were tuned
   against a near-black band; on this ground they need less contrast, not more. */
.sheet-section::before { opacity: 0.5; }

/* Every section boundary, not just the treated ones.

   All the grounds are dark now but no two are the same dark, so each boundary
   drew a hard horizontal step. Each section darkens gradually toward its own
   top and bottom edges, which means two sections meeting both approach the
   same value at the seam and the step becomes a soft trough instead of a line.
   Done with inset shadows rather than pseudo-elements, because several
   sections already use ::before and ::after for their grain and haze. */
.section, .ctaband, .sheet-section, .climate {
  box-shadow: inset 0 170px 130px -130px rgba(0, 0, 0, 0.85),
              inset 0 -170px 130px -130px rgba(0, 0, 0, 0.85);
}

/* A CTA band heading that is centred rather than ranged left. The band's own
   grid puts the button beside the copy, so centring the title means the title
   spans the full row and the actions sit under it. */
.ctaband__title--center {
  grid-column: 1 / -1;
  text-align: center;
  margin-inline: auto;
  max-width: 22ch;
}
.ctaband__title--center + * { text-align: center; }

/* ------------------------------------------------------ 29. SECTION SEAMS */

/* Adjacent sections are all dark now but not the same dark, so every boundary
   drew a hard horizontal line. Each treated ground fades its own texture in at
   the top and out at the bottom, which turns those lines into blends without
   changing any of the colours. */
.section--smoke::before,
.section--umber::before {
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 14%, #000 86%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 14%, #000 86%, transparent);
}
.section--smoke::after,
.section--umber::after {
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 10%, #000 90%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 10%, #000 90%, transparent);
}

/* The hero used to fade to a fixed colour at its foot, which only matched when
   the next section happened to be that colour; everywhere else it produced a
   step. The media is masked away instead, so the picture dissolves into
   whatever the page ground is and there is nothing to mismatch. */
.hero__media,
.hero__video {
  -webkit-mask-image: linear-gradient(to bottom, #000 62%, rgba(0, 0, 0, 0.55) 84%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 62%, rgba(0, 0, 0, 0.55) 84%, transparent 100%);
}
.hero { background: var(--bg); }
/* The scrim is not masked. Fading the darkening overlay out at the same point
   the picture fades left the lower half of the hero visibly brighter than the
   top, which read as a band of glare that had nothing to do with the footage.
   The picture dissolves; the scrim carries on to the foot. */

/* Same at the foot of the carbon sheet's own band. */
.sheet-section { padding-bottom: calc(var(--section) * 1.1); }

/* --------------------------------------------- 30. ACCESSIBILITY & LANGUAGE */

.utility { position: fixed; inset-block-end: 1rem; inset-inline-start: 1rem; z-index: 800; }
@media (max-width: 900px) { .utility { inset-block-end: calc(var(--quickbar-h, 4rem) + 0.75rem); } }

/* A round mark rather than a labelled bar. It sits in the corner, reads as a
   standard accessibility control, and does not compete with the quick bar. */
.utility__toggle {
  display: grid;
  place-items: center;
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 50%;
  background: var(--ink);
  color: var(--bone);
  box-shadow: 0 12px 30px -10px rgba(0, 0, 0, 0.85),
              inset 0 0 0 1px rgba(244, 243, 240, 0.16);
  transition: background var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.utility__toggle svg { width: 1.5rem; height: 1.5rem; }
.utility__toggle:hover { background: var(--ink-3); transform: translateY(-2px); }
.utility__toggle:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }
/* The word is for assistive tech; the mark carries it on screen. */
.utility__label {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.utility__panel {
  position: absolute; inset-block-end: calc(100% + 0.6rem); inset-inline-start: 0;
  width: min(21rem, calc(100vw - 2rem));
  padding: clamp(1rem, 2vw, 1.35rem);
  background: var(--matte-2);
  border: 1px solid rgba(244, 243, 240, 0.2);
  box-shadow: 0 26px 60px -30px rgba(0, 0, 0, 0.95);
}
.utility__panel[hidden] { display: none; }

.utility__bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  margin-bottom: clamp(0.9rem, 2vw, 1.25rem); }
.utility__title { margin: 0; font-family: var(--display); font-size: 1.1rem; font-weight: 800;
  letter-spacing: -0.01em; color: var(--bone); }
.utility__title--sub { margin-top: 1.25rem; font-size: var(--fs-micro); letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--concrete-2); }
.utility__close { display: grid; place-items: center; width: 2rem; height: 2rem; color: var(--bone); }
.utility__close svg { width: 1.05rem; height: 1.05rem; }
.utility__close:hover { color: var(--white); }
.utility__close:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

.utility__field { display: grid; gap: 0.4rem; margin-bottom: 1rem; }
.utility__field label { font-size: 0.95rem; color: var(--bone); }
.utility__field select {
  width: 100%; padding: 0.6rem 0.7rem;
  background: var(--matte); color: var(--bone);
  border: 1px solid rgba(244, 243, 240, 0.24);
  font: inherit; font-size: 0.95rem;
}
.utility__field select:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

/* Switches. The knob is decorative; aria-pressed on the button carries the
   state, so a screen reader hears "pressed" rather than nothing. */
.utility__switch {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0.6rem 0; color: var(--bone); font-size: 0.95rem; text-align: left;
}
.utility__knob {
  position: relative; flex: none; width: 2.9rem; height: 1.6rem; border-radius: 1rem;
  background: rgba(244, 243, 240, 0.2);
  transition: background var(--t-fast) var(--ease);
}
.utility__knob::after {
  content: ''; position: absolute; top: 0.2rem; left: 0.2rem;
  width: 1.2rem; height: 1.2rem; border-radius: 50%; background: var(--bone);
  transition: transform var(--t-fast) var(--ease);
}
.utility__switch[aria-pressed='true'] .utility__knob { background: var(--red); }
.utility__switch[aria-pressed='true'] .utility__knob::after { transform: translateX(1.3rem); }
.utility__switch:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

.utility__reset {
  width: 100%; margin-top: 0.8rem; padding: 0.7rem;
  border: 1.5px solid rgba(244, 243, 240, 0.3); color: var(--bone);
  font-family: var(--display); font-size: var(--fs-micro); font-weight: 800;
  letter-spacing: 0.12em; text-transform: uppercase;
}
.utility__reset:hover { border-color: var(--bone); }
.utility__reset:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

.utility__note a { color: var(--bone); text-decoration: underline; }

/* ---- the preferences themselves ---- */

html.ut-font body,
html.ut-font :is(h1, h2, h3, h4, p, a, span, li, td, th, label, button, input, select) {
  font-family: Verdana, Tahoma, 'DejaVu Sans', sans-serif !important;
  letter-spacing: 0.01em;
  word-spacing: 0.06em;
}
html.ut-font { line-height: 1.75; }

html.ut-underline a { text-decoration: underline; text-underline-offset: 0.18em; }

/* Google's widget ships its own markup and its own styling. These rules stop it
   fighting the page: no banner, no inherited font surprises, and a select that
   matches everything else in the panel. */
.utility__translate { min-height: 2.2rem; }
.goog-te-banner-frame, .skiptranslate iframe { display: none !important; }
body { top: 0 !important; }
.goog-te-gadget { font-family: var(--body) !important; font-size: 0 !important; color: transparent !important; }
.goog-te-gadget .goog-te-combo {
  margin: 0 !important; width: 100%;
  padding: 0.55rem 0.6rem;
  background: var(--matte); color: var(--bone);
  border: 1px solid rgba(244, 243, 240, 0.2);
  font-family: var(--body); font-size: 0.9375rem;
}
.goog-logo-link, .goog-te-gadget span { display: none !important; }

/* ---- reader preferences ---- */

html.ut-text { font-size: calc(100% * var(--ut-scale, 1)); }

/* High contrast: lift the type and the rules rather than repainting the page,
   so the design survives and the text simply gets further from its ground. */
html.ut-contrast body { --muted: #E4E5E2; --concrete: #C9CBC8; --concrete-2: #EDEDEA;
  --rule: rgba(244, 243, 240, 0.42); --rule-soft: rgba(244, 243, 240, 0.22); }
html.ut-contrast .btn--ghost { box-shadow: inset 0 0 0 2px var(--bone); }

html.ut-motion *, html.ut-motion *::before, html.ut-motion *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}

/* ---- partner strip ---- */

/* The supplied artwork is dark, drawn for a light page, so on this ground it
   disappeared. Inverting makes it read; it does not make it colour, which
   would need the brands' own colour files. */
.partners__strip { filter: invert(1) brightness(1.6) contrast(1.1); opacity: 0.9; }
.partners.marquee { border: 0; background: transparent; padding-block: 0; }

/* --------------------------------------------------- 31. PROSE THAT FILLS */

/* A prose block spanning a wide row was capped at a 34rem measure, so roughly
   sixty per cent of every one of those rows was empty. The cap is right: long
   lines are hard to read. The answer is a second column, not a longer line, so
   the text fills the row and each column keeps a comfortable measure.

   Scoped to blocks that are a direct child of a wide wrap, which is exactly the
   case that was leaving a void. Prose already inside a two-column grid is
   untouched, because there a second column would be too narrow to read. */
.wrap--wide > .u-flow,
.wrap--wide > .u-body + .u-body {
  columns: 2 22rem;
  column-gap: clamp(2rem, 5vw, 4.5rem);
}
.wrap--wide > .u-flow > * { break-inside: avoid; margin-top: 0; }
.wrap--wide > .u-flow > * + * { margin-top: 1rem; }
.wrap--wide > .u-flow .u-body,
.wrap--wide > .u-flow p { max-width: none; }

/* A heading inside such a block should not be stranded at the foot of the
   first column with its paragraph in the second. */
.wrap--wide > .u-flow > :is(h2, h3, h4) { break-after: avoid; }

@media (max-width: 820px) {
  .wrap--wide > .u-flow,
  .wrap--wide > .u-body + .u-body { columns: 1; }
}

/* Media followed straight into its caption with no room to breathe. */
.feature__media + *,
.gitem + .gitem__body,
.vidslot + * { margin-top: clamp(1rem, 2.2vw, 1.6rem); }

/* --------------------------------------------------------- 32. SEAM BLENDS */

/* Each band opens with a short gradient down from the colour of the band above
   it. The pairing differs per page, so the build records it: on the homepage
   the hero meets near-black, on a colour page it meets the matte ground, and a
   single stylesheet rule cannot know which.

   A real element rather than a pseudo: several of these bands already use
   ::before for their drawn grid and ::after for their grain, and scoping the
   blend to a pseudo silently skipped exactly the seams that needed it most. */
[data-from] { position: relative; }
.seam {
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: clamp(3.5rem, 10vh, 9rem);
  z-index: 2;
  pointer-events: none;
}
[data-from='ink']   > .seam { background: linear-gradient(to bottom, #0A0B0C, rgba(10, 11, 12, 0)); }
[data-from='umber'] > .seam { background: linear-gradient(to bottom, #14100E, rgba(20, 16, 14, 0)); }
[data-from='matte'] > .seam { background: linear-gradient(to bottom, #262A29, rgba(38, 42, 41, 0)); }
[data-from='hero']  > .seam { background: linear-gradient(to bottom, #262A29, rgba(38, 42, 41, 0)); }

/* The CTA band centres as a whole when its title is centred, rather than
   leaving the button ranged right against centred copy. */
.ctaband__inner:has(.ctaband__title--center) {
  grid-template-columns: 1fr;
  justify-items: center;
  text-align: center;
}
.ctaband__inner:has(.ctaband__title--center) .ctaband__actions { justify-content: center; }

/* -------------------------------------------------- 33. LANGUAGE PICKER */

/* In the header, so translation is one click from any page rather than buried
   in a preferences panel. */
.langpick { position: relative; }
.langpick__btn {
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding: 0.6rem 0.85rem;
  color: var(--bone);
  font-family: var(--display); font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase;
  box-shadow: inset 0 0 0 1.5px rgba(244, 243, 240, 0.26);
  transition: box-shadow var(--t-fast) var(--ease);
}
.langpick__btn svg { width: 1.05em; height: 1.05em; flex: none; }
.langpick__btn:hover { box-shadow: inset 0 0 0 1.5px var(--bone); }
.langpick__btn:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
@media (max-width: 1080px) { .langpick__btn span { display: none; } .langpick__btn { padding: 0.6rem; } }

.langpick__menu {
  position: absolute; top: calc(100% + 0.5rem); inset-inline-end: 0;
  width: min(17rem, calc(100vw - 2rem));
  padding: 0.9rem;
  background: var(--matte-2);
  border: 1px solid rgba(244, 243, 240, 0.2);
  box-shadow: 0 24px 50px -26px rgba(0, 0, 0, 0.95);
  z-index: 60;
}
.langpick__menu[hidden] { display: none; }
.langpick__note { display: block; margin-top: 0.6rem; font-size: var(--fs-micro); color: var(--concrete); }

/* The last two seams sit between bands that live in the layout rather than in a
   page body, so the build-time blend does not reach them. */
.ctaband { position: relative; }
.ctaband::after {
  content: '';
  position: absolute; inset-inline: 0; top: 0;
  height: clamp(3.5rem, 10vh, 9rem);
  background: linear-gradient(to bottom, #262A29, rgba(38, 42, 41, 0));
  pointer-events: none; z-index: 0;
}
.ctaband > * { position: relative; z-index: 1; }
.footer { position: relative; }
.footer::before {
  content: '';
  position: absolute; inset-inline: 0; top: 0;
  height: clamp(3rem, 8vh, 7rem);
  background: linear-gradient(to bottom, #0A0B0C, rgba(10, 11, 12, 0));
  pointer-events: none; z-index: 0;
}
.footer > * { position: relative; z-index: 1; }

/* ------------------------------------------------ 34. SUBORDINATE HEADINGS */

/* A section that already has a head, followed by a spread with its own h2, was
   showing two headings at the same scale with a gap between them. The first
   reads as the section, so the second has to read as a part of it: same family,
   smaller, and marked with a rule so it is plainly a subheading rather than a
   rival. */
.section__head ~ .spread > :first-child :is(h2, h3),
.section__head ~ .spread > :first-child.u-h2,
.section__head + .spread > :first-child :is(h2, h3) {
  font-size: clamp(1.35rem, 2.4vw, 2.1rem);
  line-height: 1.05;
  letter-spacing: -0.015em;
  padding-top: clamp(0.9rem, 1.8vw, 1.35rem);
  /* Full width on purpose: as a grid item this element is blockified, so
     inline-block would not shrink it anyway, and the rule reads better as a
     divider between the section head and the part beneath it. */
  border-top: 2px solid var(--red-text-dark);
}

/* And the two no longer sit a full section apart. */
.section__head ~ .spread,
.section__head + .spread { margin-top: clamp(1.5rem, 3.5vw, 3rem); }

/* Consecutive spreads in one section are siblings of the same rank, so they
   get a consistent rhythm between them rather than the head's larger gap. */
.spread + .spread { margin-top: clamp(2.5rem, 6vw, 5rem); }

/* ------------------------------------------------------- 35. SCROLL CUE */

/* Points at the form from the empty half of the contact hero. It is a real
   link, so it works without script and lands on the form rather than just
   scrolling an arbitrary distance. */
.scrollcue {
  position: absolute;
  inset-inline-end: clamp(2rem, 12vw, 12rem);
  inset-block-end: clamp(3rem, 10vh, 8rem);
  z-index: 4;
  display: grid;
  justify-items: center;
  gap: 0.9rem;
  color: var(--bone);
  text-decoration: none;
}
@media (max-width: 900px) { .scrollcue { display: none; } }

.scrollcue__text {
  font-family: var(--display);
  font-size: var(--fs-micro);
  font-weight: 800;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.scrollcue__arrow {
  display: grid;
  place-items: center;
  width: 3.4rem;
  height: 3.4rem;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px rgba(244, 243, 240, 0.35);
  animation: cue-bob 2.1s ease-in-out infinite;
}
.scrollcue__arrow svg { width: 1.15rem; height: 1.9rem; }
.scrollcue:hover .scrollcue__arrow { box-shadow: inset 0 0 0 1.5px var(--bone); background: rgba(244, 243, 240, 0.08); }
.scrollcue:focus-visible { outline: 2px solid var(--red); outline-offset: 6px; }

@keyframes cue-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(10px); }
}

@media (prefers-reduced-motion: reduce) {
  .scrollcue__arrow { animation: none; }
}

/* ------------------------------------------------------ 36. MOTION, MORE */

/* ---- table rows ---- */

.ctable.rows-armed tbody tr { opacity: 0; transform: translateY(14px); }
.ctable.rows-in tbody tr {
  opacity: 1;
  transform: none;
  transition: opacity 0.45s linear, transform 0.6s var(--ease);
  transition-delay: calc(var(--r, 0) * 60ms);
}

/* ---- tilt ---- */

.gitem, .steps__card, .forceband__cell, .sheet__cell, .picker__panel { will-change: transform; }

/* ---- progress ring ---- */

/* Drawn with a conic gradient masked to a ring, so it costs one element and no
   script beyond setting the angle. */
.utility__toggle { position: relative; }
.utility__ring {
  position: absolute;
  inset: -5px;
  border-radius: 50%;
  pointer-events: none;
  background: conic-gradient(var(--red) var(--p, 0deg), rgba(244, 243, 240, 0.16) 0);
  -webkit-mask: radial-gradient(circle, transparent 0 calc(50% - 2.5px), #000 calc(50% - 2.5px));
          mask: radial-gradient(circle, transparent 0 calc(50% - 2.5px), #000 calc(50% - 2.5px));
}

/* ---- eyebrow rules ---- */

.u-eyebrow.eyebrow-armed::before { transform: scaleX(0); transform-origin: left center; }
.u-eyebrow.eyebrow-in::before {
  transform: scaleX(1);
  transition: transform 0.7s var(--ease) 0.05s;
}

@media (prefers-reduced-motion: reduce) {
  .ctable.rows-armed tbody tr { opacity: 1; transform: none; }
  .u-eyebrow.eyebrow-armed::before { transform: none; }
  .utility__ring { display: none; }
}

/* The header call to action was 250x57 beside a 133x39 translate control, which
   made the bar top-heavy. Scoped to the header, so the hero and the CTA band
   keep their full-size buttons. */
.header__cta .btn {
  padding: 0.62rem 1.05rem;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  gap: 0.6rem;
}
.header__cta .btn .btn__arrow { width: 0.9em; height: 0.9em; }
@media (max-width: 1200px) {
  .header__cta .btn { padding: 0.55rem 0.9rem; font-size: 0.7rem; }
}
