/* ─────────────────────────────────────────────────────────────────────────────
   sandbeach — components (BEM, token-fed)
   Layers: base < layout < components < utilities. Every color/size comes from
   tokens.css; context colors via --_bg/--_text/--_muted/--_line so recoloring
   or flipping a slab is a token edit, never a component edit.
   ──────────────────────────────────────────────────────────────────────────── */

@layer base, layout, components, utilities;

/* ═══ base ═══════════════════════════════════════════════════════════════ */
@layer base {

@font-face {
  font-family: "BDO Grotesk";
  src: url("BDOGrotesk-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

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

body {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: 500;
  line-height: var(--lh-body);
  letter-spacing: var(--ls-1);
  color: var(--color-grey-950);
  background-color: var(--bg-under);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6, p, ul, ol, figure {
  margin: 0;
  font-weight: 500;
  overflow-wrap: break-word;
}
h1, h2, h3 { text-wrap: balance; }
p { text-wrap: pretty; }

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

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

button, input, textarea, select { font: inherit; letter-spacing: inherit; color: inherit; }

::selection { background: var(--accent); color: var(--color-grey-950); }

/* One authored focus ring for the whole site. The browser default is a 1px
   system blue that all but disappears on the dark slabs. */
:focus-visible {
  outline: 2px solid var(--_focus, var(--accent));
  outline-offset: 3px;
  border-radius: 2px;
}
:focus:not(:focus-visible) { outline: none; }

} /* base */

/* ═══ layout ═════════════════════════════════════════════════════════════ */
@layer layout {

.container {
  padding-inline: var(--container-padding);
}

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 0 var(--gutter);
  width: 100%;
}
.grid > * { min-width: 0; }

@media screen and (max-width: 47.94em) {
  .grid { grid-template-columns: repeat(6, 1fr); }
}

} /* layout */

/* ═══ components ═════════════════════════════════════════════════════════ */
@layer components {

/* ── page shell ─────────────────────────────────────────────────────────── */
.page { position: relative; }

/* Viewport-bounded, not page-bounded: as `absolute inset:0` on .page this was a
   5000px+ opaque composited layer being opacity-animated over the hero stagger. */
.page-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background-color: var(--bg-under);
  pointer-events: none;
}

/* ── type roles (Ollef text-style-*) ────────────────────────────────────── */
.t-body      { font-size: var(--text-m); }
.t-heading-s { font-size: var(--h5); line-height: var(--lh-body);    letter-spacing: var(--ls-1); }
.t-heading-m { font-size: var(--h4); line-height: var(--lh-heading); letter-spacing: var(--ls-1); }
.t-heading-l { font-size: var(--h1); line-height: var(--lh-heading); letter-spacing: var(--ls-2); }
.t-heading-xl {
  font-size: var(--display-2);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-3);
  /* SplitText mask breathing room, Ollef does the same */
  margin-inline: -0.1em;
  padding-inline: 0.1em;
}
.t-display { font-size: var(--display); line-height: var(--lh-tight); letter-spacing: var(--ls-4); }

/* ── nav (blend-difference trick: dark ink auto-inverts over any slab) ──── */
.site-nav {
  position: sticky;
  top: 0;
  z-index: 100;
  mix-blend-mode: difference;
}
/* The trick only works if EVERY child is drawn in dark ink. Setting it on the
   wrapper (not just the brand) is what makes the links and CTA invert too —
   without it they inherit --_text and wash out over the light slab. */
.site-nav__invert {
  position: relative;
  z-index: 1;            /* above the scrim: a positioned ::before would
                            otherwise paint over the in-flow nav content */
  filter: invert(1);
  color: var(--color-grey-950);
}
.site-nav__pad { height: var(--container-padding); }
.site-nav__inner { align-items: start; }
.site-nav__brand {
  grid-column: 1 / span 3;
  font-size: var(--text-m);
  padding-block: var(--link-pad);
  margin-block: calc(-1 * var(--link-pad));
}

/* Over the photo band, difference-against-a-photograph is mud. Hand the nav
   over to solid white ink on a short scrim; the handoff also reads as the nav
   belonging to whichever slab it is currently on. */
.site-nav::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 9em;
  /* holds its density across the nav row before falling off — a plain two-stop
     ramp left the brand at ~3:1 over the bright wall in the photo */
  background: linear-gradient(to bottom,
    rgb(0 0 0 / 0.7) 0%, rgb(0 0 0 / 0.55) 45%, rgb(0 0 0 / 0) 100%);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-med) var(--ease-out);
}
.site-nav.is-over-media {
  mix-blend-mode: normal;
}
.site-nav.is-over-media::before { opacity: 1; }
.site-nav.is-over-media .site-nav__invert {
  filter: none;
  color: var(--color-white);
}
.site-nav__links {
  grid-column: 4 / span 6;
  display: flex;
  gap: var(--space-m);
}
.site-nav__cta { grid-column: 10 / span 3; justify-self: end; }
.site-nav__toggle {
  display: none;
  grid-column: 5 / span 2;
  justify-self: end;
  cursor: pointer;
  background: none;
  border: 0;
  padding: var(--container-padding);
  margin: calc(-1 * var(--container-padding));
}
.site-nav__toggle-track { position: relative; display: block; overflow: hidden; }
.site-nav__toggle-open { display: block; transition: transform var(--dur-fast) var(--ease-out); }
.site-nav__toggle-close {
  position: absolute;
  inset: 0;
  display: block;
  transform: translateY(100%);
  transition: transform var(--dur-fast) var(--ease-out);
}
.site-nav__toggle[aria-expanded="true"] .site-nav__toggle-open { transform: translateY(-100%); }
.site-nav__toggle[aria-expanded="true"] .site-nav__toggle-close { transform: translateY(0); }

@media screen and (max-width: 61.94em) {
  .site-nav__links, .site-nav__cta { display: none; }
  .site-nav__toggle { display: block; }
}

/* ── mobile menu (sticky panel under the nav) ───────────────────────────── */
.mobile-menu {
  position: sticky;
  top: 0;
  z-index: 90;
  display: none;
}
@media screen and (max-width: 61.94em) {
  .mobile-menu:not([hidden]) { display: block; }
}
.mobile-menu__panel {
  position: absolute;
  inset: 0;
  z-index: 89;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 100svh;
  padding-top: calc(4.13em + var(--space-2xl));
  background-color: var(--_bg);
}
.mobile-menu__link {
  display: block;
  width: 100%;
  padding: var(--space-m) var(--space-l);
  border-top: var(--hairline) solid var(--_line);
  color: var(--_text);
}
.mobile-menu__cta { padding: 0 var(--space-l) var(--space-2xl); }

/* ── links with hairline underline ──────────────────────────────────────── */
/* Padding (cancelled by an equal negative margin) lifts a 16px text link to a
   ~28px tap target without moving a single pixel of the layout. */
.link-underline {
  position: relative;
  display: inline-block;
  font-size: var(--text-m);
  padding-block: var(--link-pad);
  margin-block: calc(-1 * var(--link-pad));
}
.link-underline::after {
  content: "";
  position: absolute;
  inset: auto 0 var(--link-pad);
  border-top: var(--hairline) solid currentColor;
  transform-origin: right;
  transition: transform var(--dur-fast) var(--ease-out);
}
.link-underline:hover::after { transform: scaleX(0); }
.link-underline--bare::after { transform: scaleX(0); transform-origin: left; }
.link-underline--bare:hover::after { transform: scaleX(1); }
.link-underline--muted { color: var(--_muted); transition: color var(--dur-fast) var(--ease-out); }
.link-underline--muted:hover { color: var(--_text); }
.link-underline--muted::after { display: none; }

/* ── atmosphere: sand haze + film grain on the dark slabs ───────────────── */
/* Beach light on a near-black ground, in two layers on one host:
   ::before — two soft sand blobs, so no dark slab is ever a flat fill;
   ::after  — a tiled fractal-noise film, OVERLAY-blended on purpose. Overlay
              is mean-preserving (mid-grey noise leaves the ground where it
              was), so the grain reads as texture without lifting the black.
              A normal-blend grain at the same strength raised #0d0d0d by ~4%
              and ate the muted-text contrast margin (grey-500 5.6:1 → 4.9:1).
   Both layers sit at z-index -1: painted over the host's own background, under
   its content. Every host below is already a stacking context, which is what
   makes that work — do not add this to an unpositioned element.
   The blob geometry is a variable so each slab gets a different sky; the
   ordering is deliberate, not random (light falls from the hero's top-left,
   the footer answers it from the bottom-right). */
.atmos { position: relative; }
.atmos::before,
.atmos::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}
.atmos::before {
  --haze-1: 68% 52% at 8% -8%;
  --haze-2: 52% 46% at 92% 104%;
  background-image:
    radial-gradient(var(--haze-1),
      color-mix(in oklab, var(--color-sand) var(--haze-strength), transparent),
      transparent 72%),
    radial-gradient(var(--haze-2),
      color-mix(in oklab, var(--color-sand) calc(var(--haze-strength) * 0.55), transparent),
      transparent 70%);
}
.atmos::after {
  /* Three things in the filter are load-bearing: sRGB interpolation (the
     linearRGB default washes the noise out and shifts its mean), the linear
     transfer that stretches turbulence around 0.5 so overlay has something to
     work with on a 5%-luminance ground, and pinning alpha to 1 — turbulence
     randomises alpha too, which would modulate the layer twice. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3.3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3.3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3.3' intercept='-1'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: var(--grain-tile) var(--grain-tile);
  opacity: var(--grain-strength);
  mix-blend-mode: overlay;
}
/* per-slab skies: hero opens top-left, the statement drifts right, the footer
   closes bottom-left so the page doesn't end where it started */
.atmos--statement::before { --haze-1: 60% 44% at 88% -6%; --haze-2: 56% 48% at 4% 96%; }
.atmos--footer::before    { --haze-1: 72% 50% at 12% 108%; --haze-2: 48% 42% at 96% -4%; }

/* The nav sits IN FLOW above the first slab, so the strip behind it is page
   ground, not section ground. Hosting the hero sky on .page instead of .intro
   is what removes the hard line the grain drew along the nav's bottom edge —
   the strip and the first slab are now one surface. The haze is capped at the
   first viewport (the page box is 5000px+ tall, so a percentage radial would
   smear); the grain runs the whole height, harmless where slabs cover it. */
.page { z-index: 0; }   /* stacking context: the -1 layers need one to sit in */
.atmos--page::before { inset: 0 0 auto; height: 100vh; }

/* whichever slab lands under the nav gives up its own fill and shows that sky */
main > .theme-dark:first-child { background-color: transparent; }

/* ── intro (hero) ───────────────────────────────────────────────────────── */
.intro { position: relative; z-index: 1; background-color: var(--_bg); }
.intro__top { padding-top: var(--space-2xl); }
.intro__statement { grid-column: 1 / span 6; max-width: 24em; }
.intro__heading { font-size: var(--h4); line-height: var(--lh-heading); letter-spacing: var(--ls-1); text-wrap: balance; }
.intro__heading em { font-style: normal; color: var(--_muted); display: block; }
.intro__sub { margin-top: var(--space-m); max-width: 26em; color: var(--_muted); }
.intro__now {
  margin-top: var(--space-m);
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2xs);
  color: var(--_text);
}
.intro__now::before {
  content: "";
  align-self: center;
  width: var(--space-2xs);
  height: var(--space-2xs);
  border-radius: var(--radius-pill);
  background-color: var(--accent);
}
/* The availability line is the page's one live claim. A slow breath makes it
   read as current rather than as printed copy. Runs only while on screen. */
.intro__now.is-live::before { animation: sb-breathe 3.2s ease-in-out infinite; }
@keyframes sb-breathe {
  0%, 100% { opacity: 1;    transform: scale(1); }
  50%      { opacity: 0.45; transform: scale(0.8); }
}

/* the band below the fold is a full viewport of photograph with no other
   affordance saying it moves — the cue is the only hint, so it drifts */
.intro__cue .link-underline.is-live { animation: sb-drift 2.6s ease-in-out infinite; }
.intro__cue .link-underline:hover { animation-play-state: paused; }
@keyframes sb-drift {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, 0.35em, 0); }
}
.intro__form { grid-column: 8 / span 5; align-self: start; }
.intro__brand { grid-column: 1 / -1; margin-top: var(--space-3xl); }
.intro__cue {
  grid-column: 1 / -1;
  justify-self: end;
  margin-top: var(--space-l);
  overflow: hidden;
  padding-bottom: var(--space-2xl);
}

/* giant text logotype, the Ollef "large brand" moment */
.brand-mark {
  font-size: var(--brand-mark-size);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-4);
  white-space: nowrap;
  color: var(--_text);
}

@media screen and (max-width: 61.94em) {
  .intro__statement { grid-column: 1 / -1; max-width: 100%; }
  .intro__form { grid-column: 1 / -1; margin-top: var(--space-xl); }
}

/* ── media band (sticky parallax, full-bleed) ───────────────────────────── */
.media-band { position: relative; }
.media-band__sticky {
  position: sticky;
  inset: 0;
  height: 100vh;
  margin-bottom: -100vh;
  overflow: hidden;
}
.media-band__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 150%;
}
.media-band__image img { width: 100%; height: 100%; object-fit: cover; object-position: 40% 25%; }
.media-band__trigger { height: 100vh; }
.media-band__overlay {
  position: absolute;
  inset: 0;
  z-index: 10;
  background-color: var(--bg-page);
  pointer-events: none;
}
@media screen and (max-width: 47.94em) {
  .media-band__sticky { height: 100vw; margin-bottom: -100vw; }
  .media-band__trigger { height: 100vw; }
}

/* ── statement (Minust) ─────────────────────────────────────────────────── */
.statement { position: relative; z-index: 1; background-color: var(--_bg); }
.statement__lead { grid-column: 1 / span 8; max-width: 40em; padding-block: var(--space-3xl); }
.statement__lead p + p { margin-top: var(--space-l); }
.statement__divider { grid-column: 1 / -1; border-top: var(--hairline) solid var(--_line); }
.statement__label { grid-column: 1 / span 2; padding-block: var(--space-xl); }
.statement__stats {
  grid-column: 4 / span 6;
  padding-block: var(--space-xl);
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
}
.stat__num { font-size: var(--h1); line-height: var(--lh-tight); letter-spacing: var(--ls-2); }
.stat__text { margin-top: var(--space-2xs); color: var(--_muted); }
.statement__foot { grid-column: 11 / span 2; padding-block: var(--space-xl); justify-self: end; }
/* The section opens with the lead's 6em and has to close on the same 6em. The
   last row already carries 3em of its own padding-bottom, so the spacer only
   completes it — at --section-space-m the tail measured 207px against a 108px
   head and the whole slab sat high in its own space. */
.statement__bottom { grid-column: 1 / -1; height: calc(var(--space-3xl) - var(--space-xl)); }

@media screen and (max-width: 61.94em) {
  .statement__lead { grid-column: 1 / -1; max-width: 100%; }
  .statement__label { grid-column: 1 / span 2; }
  .statement__stats { grid-column: 1 / -1; }
  .statement__foot { grid-column: 1 / -1; justify-self: start; padding-top: 0; }
}

/* ── pillars (the light slab; service rows, Ollef signature) ────────────── */
.slab { position: relative; z-index: 2; background-color: var(--_bg); color: var(--_text); }
.slab__overlay {
  position: absolute;
  inset: 0;
  z-index: 20;
  background-color: var(--bg-page);
  pointer-events: none;
}

.pillars__head { padding-top: var(--section-space-s); }
.pillars__label { grid-column: 1 / span 3; }
.pillars__title-wrap { grid-column: 1 / -1; overflow: hidden; margin-top: var(--space-2xl); }
.pillars__title { font-size: var(--display-2); }
.pillars__list { grid-column: 1 / span 8; margin-top: var(--space-2xl); align-self: start; }

/* the heading is structure only — it must not resize the display type, whose
   em value resolves against this element's font-size */
.pillar-row-heading { font-size: inherit; line-height: inherit; }

/* A real button: activating a row swaps the panel beside it, so it is a
   control, not decoration — and that is what makes it keyboard-reachable.
   Without it the two inactive services were mouse-only on desktop. */
.pillar-row {
  display: block;
  width: 100%;
  padding: 0.375em 0;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  color: inherit;
}
.pillar-row__title {
  opacity: 0.12;
  transform: translate3d(0, 0, 0);
  transition: opacity var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}
.pillar-row.is-active .pillar-row__title {
  opacity: 1;
  transform: translate3d(0.06em, 0, 0);
}
.pillar-row:focus-visible { outline-offset: -2px; }

/* media column: a real grid item beside the list — sticky inner, cards
   stacked in one cell and crossfaded. Normal flow = it can only grow the
   section, never overflow it; links stay clickable (no pointer-events hacks). */
.pillars__media-col { grid-column: 10 / span 3; margin-top: var(--space-2xl); }
.pillars__media-sticky {
  position: sticky;
  top: var(--space-2xl);
  display: grid;
}
.pillar-media {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-fast) var(--ease-out), visibility 0s var(--dur-fast);
}
.pillar-media.is-active {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur-fast) var(--ease-out), visibility 0s;
}
.pillar-media__image {
  aspect-ratio: 1;
  position: relative;
  overflow: hidden;
}
/* the incoming frame settles rather than cutting in — makes it read as one
   panel changing contents, not two images swapping */
.pillar-media__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.04);
  transition: transform var(--dur-med) var(--ease-out);
}
.pillar-media.is-active .pillar-media__image img { transform: scale(1); }
.pillar-media__text { margin-top: var(--space-s); }

/* the small-screen form of the service list: name at display size, then its
   own text, so nothing is announced or printed twice */
.pillar-cards { grid-column: 1 / -1; margin-top: var(--space-2xl); display: none; }
.pillar-card + .pillar-card { margin-top: var(--space-xl); padding-top: var(--space-xl); border-top: var(--hairline) solid var(--_line); }
.pillar-card__title { line-height: var(--lh-tight); }
.pillar-card__text { margin-top: var(--space-s); color: var(--_muted); }
.pillar-card__text + .pillar-card__text { margin-top: var(--space-xs); }

/* the head padding is --section-space-s; the tail matches it. --section-space-l
   was runway for a longer service list than this page has, and read as a void. */
.pillars__bottom { height: var(--section-space-s); }

@media screen and (max-width: 61.94em) {
  .pillars__list { display: none; }
  .pillars__media-col { display: none; }
  .pillar-cards { display: block; }
}

/* ── references slot (held back; ships hidden until Tom OKs names) ──────── */
.refs { padding-bottom: var(--section-space-s); }
.refs__label { grid-column: 1 / span 3; }
.refs__list {
  grid-column: 4 / span 9;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-m);
  color: var(--_muted);
}
@media screen and (max-width: 61.94em) {
  .refs__label { grid-column: 1 / -1; margin-bottom: var(--space-m); }
  .refs__list { grid-column: 1 / -1; }
}

/* ── lead form ──────────────────────────────────────────────────────────── */
.lead-form__title { margin-bottom: var(--space-m); }
.lead-form__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-m) var(--gutter);
}
.lead-form__field { display: flex; flex-direction: column; }
.lead-form__field--full { grid-column: 1 / -1; }
.lead-form__input {
  height: 3.8em;
  padding: 0 1.3em;
  border: var(--hairline) solid var(--_line);
  border-radius: var(--radius-field);
  background: transparent;
  color: var(--_text);
  font-size: var(--text-m);
  width: 100%;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.lead-form__input::placeholder { color: var(--_muted); }
/* a border-color nudge is not a focus indicator — WCAG 2.4.11 wants 3:1
   against the adjacent field, which only a real ring delivers here */
.lead-form__input:focus-visible {
  outline: 2px solid var(--_focus);
  outline-offset: 2px;
  border-color: var(--_muted);
}
.lead-form__input:focus { border-color: var(--_muted); }
.lead-form__input[aria-invalid="true"] { border-color: var(--accent); }
textarea.lead-form__input { height: auto; min-height: 6.5em; padding-block: 1em; resize: vertical; }
.lead-form__actions {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--space-m);
  flex-wrap: wrap;
}
.lead-form__note { color: var(--_muted); }
/* the reply opens the row it needs instead of snapping into existence */
.lead-form__status {
  grid-column: 1 / -1;
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  color: var(--_muted);
  transition: grid-template-rows var(--dur-fast) var(--ease-out),
              opacity var(--dur-fast) var(--ease-out);
}
.lead-form__status > span { overflow: hidden; }
.lead-form__status.is-visible { grid-template-rows: 1fr; opacity: 1; }
.lead-form__status.is-ok { color: var(--_text); }
.lead-form__status.is-error { color: var(--accent); }
/* honeypot: visually gone, still in the DOM for bots */
.lead-form__hp { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

.lead-form--stack .lead-form__grid { grid-template-columns: 1fr; gap: var(--space-s); }

@media screen and (max-width: 47.94em) {
  .lead-form__grid { grid-template-columns: 1fr; }
}

/* ── button (pill) ──────────────────────────────────────────────────────── */
.button {
  display: inline-block;
  padding: 1em 2.5em;
  border: none;
  border-radius: var(--radius-pill);
  background-color: var(--accent);
  color: var(--color-grey-950);
  font-size: var(--text-m);
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}
.button:hover { transform: scale(0.97); }
.button:active { transform: scale(0.94); }
.button:disabled { opacity: 0.5; cursor: wait; transform: none; }
/* in-flight: the button says what is happening, so the wait is legible */
.button[data-pending] { animation: sb-pending 1.2s ease-in-out infinite; }
@keyframes sb-pending {
  0%, 100% { opacity: 0.5; }
  50%      { opacity: 0.75; }
}

/* ── footer CTA (slide-over reveal) ─────────────────────────────────────── */
.site-footer {
  position: relative;
  z-index: 0;
  background-color: var(--_bg);
}
.site-footer__head { padding-top: var(--section-space-s); }
.site-footer__heading { grid-column: 1 / span 6; max-width: 35em; }
.site-footer__form { grid-column: 8 / span 5; }
.site-footer__divider { grid-column: 1 / -1; margin-top: var(--space-2xl); border-top: var(--hairline) solid var(--_line); }
.site-footer__meta { padding-block: var(--space-2xl); }
.site-footer__col { grid-column: span 3; }
.site-footer__col-label { color: var(--_muted); margin-bottom: var(--space-s); }
/* stacked links: let --link-pad be the spacing so tap areas sit flush, never
   overlapping (a negative margin here would make them intersect) */
.site-footer__list { display: flex; flex-direction: column; gap: 0; align-items: flex-start; }
.site-footer__list .link-underline { margin-block: 0; }
.site-footer__brand { grid-column: 1 / -1; margin-top: var(--space-2xl); overflow: hidden; }
.site-footer__legal {
  grid-column: 1 / -1;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-m);
  flex-wrap: wrap;
  padding-block: var(--space-l);
  color: var(--_muted);
}

@media screen and (max-width: 61.94em) {
  .site-footer__heading { grid-column: 1 / -1; max-width: 100%; }
  .site-footer__form { grid-column: 1 / -1; margin-top: var(--space-xl); }
  .site-footer__col { grid-column: span 3; margin-bottom: var(--space-l); }
}

} /* components */

/* ═══ utilities ══════════════════════════════════════════════════════════ */
@layer utilities {

.u-muted { color: var(--_muted); }
.u-overflow-hidden { overflow: hidden; }
.u-nowrap { white-space: nowrap; }

/* Visually gone, still announced. `hidden` removes a label from the
   accessibility tree entirely, which leaves the input with no name at all. */
.u-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

} /* utilities */

/* ═══ animation initial states (JS only — no-JS shows everything) ════════ */
html.js [data-reveal],
html.js [data-reveal-group] > *,
html.js [data-hero-in],
html.js [data-hero-split],
html.js [data-hero-brand],
html.js [data-title-reveal],
html.js [data-split-reveal] { opacity: 0; }
html.js .media-band__overlay[data-band-overlay] { opacity: 1; }
html.js .page-overlay { opacity: 1; }
html:not(.js) .page-overlay,
html:not(.js) .media-band__overlay { display: none; }

/* Reduced motion keeps every state change and its hierarchy — it only removes
   the travel. Loops stop; hover/focus feedback stays legible. */
@media (prefers-reduced-motion: reduce) {
  html.js [data-reveal],
  html.js [data-reveal-group] > *,
  html.js [data-hero-in],
  html.js [data-hero-split],
  html.js [data-hero-brand],
  html.js [data-title-reveal],
  html.js [data-split-reveal] { opacity: 1 !important; transform: none !important; }
  html.js .page-overlay,
  html.js .media-band__overlay { display: none; }

  .intro__now.is-live::before,
  .intro__cue .link-underline.is-live,
  .button[data-pending] { animation: none; }
  .button[data-pending] { opacity: 0.6; }
  .pillar-media__image img,
  .pillar-media.is-active .pillar-media__image img { transform: none; }
  .pillar-row.is-active .pillar-row__title { transform: none; }
  .button:hover, .button:active { transform: none; opacity: 0.85; }
}
