/* ==========================================================================
   ENERGEX — site.css
   Design system, layout, components and motion for newenergex.com
   Palette: black · white · blue. Nothing else.
   ========================================================================== */

/* ---------- Fonts (self-hosted: no third-party requests, GDPR-clean) ------ */
@font-face {
  font-family: 'Inter';
  src: url('../fonts/inter.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-display: swap;
  font-style: normal;
}
@font-face {
  font-family: 'Space Grotesk';
  src: url('../fonts/space-grotesk.woff2') format('woff2-variations');
  font-weight: 300 700;
  font-display: swap;
  font-style: normal;
}
/* Metric-matched stand-ins, used only for the moment before the real fonts
   arrive. Arial scaled to the width of each face (measured on this site's own
   copy), so when the swap happens the text does not reflow and nothing on the
   page jumps. */
@font-face {
  font-family: 'Inter Fallback';
  src: local('Arial'), local('ArialMT'), local('Helvetica');
  size-adjust: 107.03%; ascent-override: 90.63%; descent-override: 22.42%; line-gap-override: 0%;
}
@font-face {
  font-family: 'Space Grotesk Fallback';
  src: local('Arial'), local('ArialMT'), local('Helvetica');
  size-adjust: 108.8%; ascent-override: 90.08%; descent-override: 26.66%; line-gap-override: 0%;
}

/* ---------- Tokens -------------------------------------------------------- */
:root {
  /* surfaces */
  --ink:        #05070b;
  --ink-2:      #080b12;
  --panel:      #0b1019;
  --panel-2:    #101724;
  --paper:      #f2f5fa;
  --paper-2:    #e6ebf3;
  --paper-ink:  #070a10;

  /* lines */
  --line:       rgba(var(--up-rgb),.075);
  --line-2:     rgba(var(--up-rgb),.14);
  --line-dark:  rgba(var(--pink-rgb),.10);

  /* text */
  --text:       #e9edf4;
  --dim:        #98a2b3;
  --faint:      #7b8496;

  /* the three colours a scheme actually changes, as triplets so any
     transparency in the sheet follows them */
  --accent-rgb: 46,123,255;
  --ink-rgb:    5,7,11;
  --pink-rgb:   7,10,16;
  --up-rgb:     255,255,255;
  --up:         #ffffff;
  --card-hi:    #ffffff;
  --nav-light:  #eef1f6;
  --btn-ink:    #ffffff;
  --accent-pale: #cfe0ff;
  --accent-lt2:  #7fb0ff;
  --wire:       122,168,255;
  --particle-a: 46,123,255;
  --particle-b: 206,224,255;

  /* accent */
  --blue:       #2e7bff;
  --blue-lt:    #74a8ff;
  --blue-dk:    #1a56c4;
  --blue-btn:   #2468e0;   /* deeper blue wherever white text sits on it (AA 5.1:1) */
  --blue-wash:  rgba(var(--accent-rgb),.12);
  --blue-glow:  rgba(var(--accent-rgb),.38);

  /* type */
  --f-display: 'Space Grotesk', 'Space Grotesk Fallback', 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --f-body:    'Inter', 'Inter Fallback', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  --t-hero:  clamp(2.85rem, 7.4vw, 6.5rem);
  --t-h1:    clamp(2.25rem, 5.4vw, 4.35rem);
  --t-h2:    clamp(1.8rem,  3.6vw, 3.05rem);
  --t-h3:    clamp(1.18rem, 1.05vw + .9rem, 1.6rem);
  --t-body:  clamp(1rem, .3vw + .93rem, 1.125rem);
  --t-lead:  clamp(1.08rem, .6vw + .95rem, 1.35rem);
  --t-micro: .74rem;

  /* layout — one column width for the whole site, so every section's left
     edge lines up with the logo. Reading measure is set per component in ch. */
  --wrap:   1400px;
  --wrap-n: 1400px;
  --gut:    clamp(20px, 5vw, 68px);
  --nav-h:  76px;
  --sec-y:  clamp(76px, 9.5vw, 146px);

  /* motion */
  --ease:      cubic-bezier(.16, 1, .3, 1);
  --ease-soft: cubic-bezier(.33, 1, .68, 1);
  --dur:       .8s;

  color-scheme: dark;
}
@media (max-width: 780px) { :root { --nav-h: 64px; } }
/* The pages draw edge to edge on a phone with a notch (viewport-fit=cover in
   the viewport tag), so the gutter also has to clear the notch and the rounded
   corners when an iPhone is turned sideways. Upright, the insets are zero and
   nothing changes. */
@supports (padding: max(env(safe-area-inset-left), 0px)) {
  :root { --gut: max(clamp(20px, 5vw, 68px), env(safe-area-inset-left), env(safe-area-inset-right)); }
}

/* ---------- Reset --------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-padding-top: calc(var(--nav-h) + 16px); }
body {
  margin: 0;
  background: var(--ink);
  color: var(--text);
  font-family: var(--f-body);
  font-size: var(--t-body);
  line-height: 1.62;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;   /* Safari before 16 does not know clip */
  overflow-x: clip;
}
img, svg, canvas { display: block; max-width: 100%; }
h1, h2, h3, h4 { font-family: var(--f-display); font-weight: 600; line-height: 1.06; letter-spacing: -.024em; margin: 0; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }
a { color: inherit; text-decoration: none; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
/* No grey flash on tap: every control here has its own pressed state. */
a, button, summary, label { -webkit-tap-highlight-color: transparent; }
::selection { background: var(--blue-btn); color: var(--btn-ink); }

:focus-visible {
  outline: 2px solid var(--blue-lt);
  outline-offset: 3px;
  border-radius: 3px;
}
/* On the light board and bands the pale accent would not show; the deep one
   clears 3:1 against paper in every scheme. */
.light :focus-visible { outline-color: var(--blue-dk); }
/* Targets focused by script (the skip link, a revealed panel) are not
   controls, so they get no ring. */
[tabindex="-1"]:focus { outline: none; }

/* Scrollbar */
* { scrollbar-width: thin; scrollbar-color: #1d2634 transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--ink); }
::-webkit-scrollbar-thumb { background: #1d2634; border-radius: 99px; border: 3px solid var(--ink); }
::-webkit-scrollbar-thumb:hover { background: #2b3648; }

/* Lenis */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

/* ---------- Utilities ----------------------------------------------------- */
[hidden] { display: none !important; }
.wrap  { width: 100%; max-width: var(--wrap);   margin-inline: auto; padding-inline: var(--gut); }
.wrap-n{ width: 100%; max-width: var(--wrap-n); margin-inline: auto; padding-inline: var(--gut); }
.section { padding-block: var(--sec-y); position: relative; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip {
  position: fixed; top: 8px; left: 8px; z-index: 460;
  background: var(--blue-btn); color: var(--btn-ink); padding: .7em 1.2em; border-radius: 8px;
  transform: translateY(-160%); transition: transform .25s var(--ease);
}
.skip:focus { transform: none; }

.eyebrow {
  display: inline-flex; align-items: center; gap: .7em;
  font-size: var(--t-micro); font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--dim);
}
.eyebrow::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--blue); box-shadow: 0 0 12px var(--blue-glow);
  flex: none;
}
.lead { font-size: var(--t-lead); color: var(--dim); line-height: 1.55; max-width: 62ch; }
.muted { color: var(--dim); }
.faint { color: var(--faint); }

/* Buttons. Hover effects live behind (hover: hover) throughout the sheet, so
   a tap on a phone does not leave a button stuck in its lifted state. */
.btn {
  --bg: var(--blue-btn); --fg: var(--btn-ink); --bd: var(--blue-btn);
  position: relative; display: inline-flex; align-items: center; gap: .7em;
  padding: .95em 1.6em; border-radius: 999px;
  background: var(--bg); color: var(--fg); border: 1px solid var(--bd);
  font-size: .95rem; font-weight: 500; letter-spacing: -.005em;
  transition: transform .45s var(--ease), background .3s var(--ease), border-color .3s var(--ease), box-shadow .45s var(--ease), color .3s var(--ease);
}
.btn .arw { transition: transform .45s var(--ease); }
.btn:active { transform: translateY(1px) scale(.985); transition-duration: .12s; }
@media (hover: hover) {
  .btn:hover { transform: translateY(-2px); box-shadow: 0 12px 34px -12px var(--blue-glow); --bg: var(--blue); --bd: var(--blue); }
  .btn:hover .arw { transform: translateX(4px); }
  .btn:active { transform: translateY(0); }
}
.btn--ghost { --bg: transparent; --fg: var(--text); --bd: var(--line-2); }
@media (hover: hover) {
  .btn--ghost:hover { --bg: transparent; --bd: rgba(var(--up-rgb),.34); background: rgba(var(--up-rgb),.045); box-shadow: none; }
}
.btn--sm { padding: .72em 1.25em; font-size: .875rem; }

.btn-row { display: flex; flex-wrap: wrap; gap: .75rem; }

/* Text link with animated underline */
.tlink {
  display: inline-flex; align-items: center; gap: .5em;
  color: var(--blue-lt); font-weight: 500;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px; background-position: 0 100%; background-repeat: no-repeat;
  transition: background-size .5s var(--ease);
  padding-bottom: 2px;
}
.tlink:focus-visible { background-size: 100% 1px; }
@media (hover: hover) { .tlink:hover { background-size: 100% 1px; } }

/* ---------- Navigation ---------------------------------------------------- */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 120; height: var(--nav-h);
  display: flex; align-items: center;
  transition: background .5s var(--ease), border-color .5s var(--ease), backdrop-filter .5s;
  border-bottom: 1px solid transparent;
}
.nav.is-stuck {
  background: rgba(var(--ink-rgb),.72);
  backdrop-filter: saturate(160%) blur(16px);
  -webkit-backdrop-filter: saturate(160%) blur(16px);
  border-bottom-color: var(--line);
}
.nav.on-light { color: var(--paper-ink); }
/* Opaque: the light section it sits over may be an inset board, and a
   translucent bar would show the dark page through at the margins. */
.nav.on-light.is-stuck { background: var(--nav-light); border-bottom-color: var(--line-dark); }
.nav__in {
  width: 100%; max-width: var(--wrap-n); margin-inline: auto; padding-inline: var(--gut);
  display: flex; align-items: center; justify-content: space-between; gap: 2rem;
}
.brand { display: inline-flex; align-items: center; gap: .72rem; }
.brand img { height: 30px; width: auto; transition: filter .5s var(--ease); }
.nav.on-light .brand img { filter: invert(1); }
.brand__txt {
  font-family: var(--f-display); font-weight: 600; font-size: 1.02rem;
  letter-spacing: .18em; text-transform: uppercase;
}



.nav__links { display: flex; align-items: center; gap: clamp(1.1rem, 2.2vw, 2.3rem); }
.nav__link {
  position: relative; font-size: .93rem; color: var(--dim);
  padding: .4em 0; transition: color .35s var(--ease);
}
.nav.on-light .nav__link { color: rgba(var(--pink-rgb),.68); }
.nav__link[aria-current="page"] { color: var(--text); }
.nav.on-light .nav__link[aria-current="page"] { color: var(--paper-ink); }
.nav__link span { display: inline-block; transition: transform .45s var(--ease); }
.nav__link:focus-visible span { transform: translateY(-2px); }
@media (hover: hover) {
  .nav__link:hover { color: var(--text); }
  .nav.on-light .nav__link:hover { color: var(--paper-ink); }
  .nav__link:hover span { transform: translateY(-2px); }
}

/* One marker for the whole set. It travels to whichever link you point at and
   returns to the page you are on, so the nav reads as a single instrument
   rather than four links that each do a trick. It sits beside the list rather
   than inside it: a <ul> may only hold list items. */
.nav__in > nav { position: relative; }
.nav__ind {
  position: absolute; left: 0; bottom: .18em; height: 2px; width: 1px; border-radius: 2px;
  background: var(--blue); pointer-events: none; opacity: 0;
  transform: translateX(0) scaleX(1); transform-origin: 0 50%;
  transition: transform .55s var(--ease), width .55s var(--ease), opacity .35s var(--ease), background .35s var(--ease);
}
.nav__ind.is-ready { opacity: 1; }
.nav__ind::after {
  content: ''; position: absolute; left: 50%; top: -5px; width: 3px; height: 3px;
  margin-left: -1.5px; border-radius: 50%; background: inherit; opacity: .0;
  transition: opacity .4s var(--ease);
}
.nav__links.is-hovered + .nav__ind::after { opacity: .9; }
html:not(.js) .nav__ind { display: none; }
html:not(.js) .nav__link[aria-current="page"] { text-decoration: underline; text-underline-offset: 6px; }
@media (prefers-reduced-motion: reduce) { .nav__ind { transition: opacity .2s linear; } }
.nav__cta { margin-left: .6rem; }

.nav__burger {
  display: none; width: 44px; height: 44px; margin-right: -10px;
  align-items: center; justify-content: center; border-radius: 10px;
}
.nav__burger span {
  display: block; position: relative; width: 22px; height: 1.5px;
  background: currentColor; border-radius: 2px;
  transition: transform .5s var(--ease), background .2s;
}
.nav__burger span::before, .nav__burger span::after {
  content: ''; position: absolute; left: 0; width: 22px; height: 1.5px;
  background: currentColor; border-radius: 2px;
  transition: transform .5s var(--ease), top .3s var(--ease);
}
.nav__burger span::before { top: -6.5px; }
.nav__burger span::after  { top:  6.5px; }
body.menu-open .nav__burger span { background: transparent; }
body.menu-open .nav__burger span::before { top: 0; transform: rotate(45deg); }
body.menu-open .nav__burger span::after  { top: 0; transform: rotate(-45deg); }

/* Scroll progress */
.progress {
  position: fixed; top: 0; left: 0; height: 2px; z-index: 130;
  width: 100%; transform: scaleX(0); transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--blue-dk), var(--blue), var(--blue-lt));
  pointer-events: none; will-change: transform;
}

/* Mobile menu */
.menu {
  position: fixed; inset: 0; z-index: 115;
  background: var(--ink);
  display: flex; flex-direction: column; justify-content: center;
  padding: var(--nav-h) var(--gut) calc(var(--gut) + 12px);
  clip-path: inset(0 0 100% 0);
  transition: clip-path .8s var(--ease);
  visibility: hidden;
}
.menu::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(60% 55% at 78% 12%, rgba(var(--accent-rgb),.20), transparent 70%);
  pointer-events: none;
}
body.menu-open .menu { clip-path: inset(0 0 0 0); visibility: visible; }
.menu__list { display: grid; gap: .1rem; position: relative; }
.menu__item { overflow: hidden; }
.menu__item a {
  display: flex; align-items: baseline; gap: 1rem;
  font-family: var(--f-display); font-size: clamp(2.1rem, 11vw, 3.4rem);
  font-weight: 500; letter-spacing: -.03em; padding: .28em 0;
  transform: translateY(105%);
  transition: transform .8s var(--ease), color .3s;
  border-bottom: 1px solid var(--line);
}
.menu__item a i {
  font-style: normal; font-size: .7rem; letter-spacing: .12em;
  color: var(--faint); font-family: var(--f-body);
}
body.menu-open .menu__item a { transform: none; }
body.menu-open .menu__item:nth-child(1) a { transition-delay: .10s; }
body.menu-open .menu__item:nth-child(2) a { transition-delay: .17s; }
body.menu-open .menu__item:nth-child(3) a { transition-delay: .24s; }
body.menu-open .menu__item:nth-child(4) a { transition-delay: .31s; }
.menu__item a:active { color: var(--blue-lt); }
.menu__item a[aria-current="page"] i { color: var(--blue-lt); }

@media (max-width: 880px) {
  .nav__links, .nav__ind { display: none; }
  .nav__burger { display: inline-flex; }
}

/* ---------- Page transition veil ------------------------------------------ */
.veil {
  position: fixed; inset: 0; z-index: 400; background: var(--ink);
  pointer-events: none; transform: translateY(0);
}
.veil::after {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(50% 50% at 50% 50%, rgba(var(--accent-rgb),.14), transparent 70%);
}
html.js .veil { transition: transform .85s var(--ease); }
html.js .veil.is-out { transform: translateY(-101%); }
html.js .veil.is-in  { transform: translateY(0); transition-duration: .55s; }
html.js .veil.is-below { transform: translateY(101%); }
html:not(.js) .veil { display: none; }

/* ---------- Reveal motion (progressive enhancement) ----------------------- */
html.js [data-reveal] {
  opacity: 0; transform: translateY(26px);
  transition: opacity .95s var(--ease), transform .95s var(--ease);
}
html.js [data-reveal].is-in { opacity: 1; transform: none; }
html.js [data-reveal="fade"] { transform: none; }
html.js [data-reveal="left"]  { transform: translateX(-28px); }
html.js [data-reveal="right"] { transform: translateX(28px); }
html.js [data-reveal="zoom"]  { transform: scale(.96); }

/* word-by-word heading reveal */
.rw { display: inline-block; overflow: hidden; vertical-align: bottom; padding-bottom: .04em; }
.rw > span { display: inline-block; }
html.js .rw > span { transform: translateY(105%); transition: transform 1.05s var(--ease); }
html.js .is-in .rw > span, html.js .rw.is-in > span { transform: none; }

@media (prefers-reduced-motion: reduce) {
  html.js [data-reveal], html.js .rw > span { opacity: 1 !important; transform: none !important; transition: none !important; }
  html.js .veil { display: none; }
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
}

/* Page header (inner pages) */
.phead {
  position: relative; padding-top: calc(var(--nav-h) + clamp(44px, 7vw, 92px));
  padding-bottom: clamp(30px, 4vw, 56px); overflow: hidden;
  /* clip, where supported: the ring hangs off the right edge, and a box that
     is merely hidden can still be scrolled — moving focus to a control in
     it slid the whole header sideways */
  overflow: clip;
}
.phead::before {
  content: ''; position: absolute; z-index: -1; inset: -40% -10% auto -10%; height: 130%;
  background: radial-gradient(48% 52% at 76% 6%, rgba(var(--accent-rgb),.20), transparent 66%);
  pointer-events: none;
}
.phead__title { font-size: var(--t-h1); font-weight: 500; letter-spacing: -.035em; max-width: 18ch; margin-top: 0; }
.phead__sub { margin-top: 1.5rem; }
.phead__ring {
  position: absolute; top: -14%; right: -8%; width: min(46vw, 560px); aspect-ratio: 1;
  border: 1px solid var(--line); border-radius: 50%; pointer-events: none; z-index: -1;
}
.phead__ring::after {
  content: ''; position: absolute; inset: 16%; border: 1px solid var(--line); border-radius: 50%;
}

/* ==========================================================================
   Layout blocks
   ========================================================================== */
.grid { display: grid; gap: clamp(1rem, 2vw, 1.5rem); }
.g-3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
@media (max-width: 980px) { .g-3 { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 640px)  { .g-3 { grid-template-columns: 1fr; } }

.sec-title { font-size: var(--t-h2); font-weight: 500; margin-top: 1rem; max-width: 17ch; }
.card__foot { margin-top: auto; padding-top: 1.6rem; }

/* ---------- Light band ---------------------------------------------------- */
.light {
  background: var(--paper); color: var(--paper-ink);
  --line: var(--line-dark); --line-2: rgba(var(--pink-rgb),.2);
  --dim: rgba(var(--pink-rgb),.70); --faint: rgba(var(--pink-rgb),.60); --text: var(--paper-ink);
  position: relative;
}
.light .tlink { color: var(--blue-dk); }

/* ==========================================================================
   MAP
   ========================================================================== */
.mapwrap { display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: clamp(1.6rem, 3vw, 2.6rem); align-items: start; }
@media (max-width: 1040px) { .mapwrap { grid-template-columns: 1fr; } }

.mapfilters { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.4rem; }
.chip {
  display: inline-flex; align-items: center; gap: .55em;
  padding: .5em 1.05em; border-radius: 999px; border: 1px solid var(--line);
  font-size: .84rem; color: var(--dim); background: rgba(var(--up-rgb),.015);
  transition: color .35s var(--ease), border-color .35s var(--ease), background .35s var(--ease);
}
.chip__dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
@media (hover: hover) { .chip:hover { color: var(--text); border-color: var(--line-2); } }
.chip:active { transform: scale(.97); }
.chip.is-on { color: var(--up); border-color: var(--blue); background: var(--blue-wash); }
.chip__c { font-variant-numeric: tabular-nums; opacity: .55; font-size: .78rem; }

.mapstage {
  position: relative; border: 1px solid var(--line); border-radius: 18px;
  background:
    radial-gradient(70% 70% at 50% 40%, rgba(var(--accent-rgb),.08), transparent 70%),
    linear-gradient(168deg, var(--panel-2), var(--ink) 78%);
  padding: clamp(.8rem, 2vw, 1.6rem);
  overflow: hidden;
}
.mapstage__inner { position: relative; width: 100%; aspect-ratio: 1000 / 650; }
.mapstage svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
/* The map takes its colour from the scheme like everything else, rather than
   staying navy when the rest of the page has turned amber or green. */
.bgcountry { fill: url(#bgFill); stroke: rgba(var(--accent-rgb),.45); stroke-width: 1.6; stroke-linejoin: round; }
.bgdots { fill: url(#bgDots); }
.mapstage stop:first-child { stop-color: var(--panel-2); }
.mapstage stop:last-child  { stop-color: var(--panel); }
.mapstage pattern circle   { fill: rgba(var(--accent-rgb),.22); }

.pin {
  position: absolute; width: 30px; height: 30px; margin: -15px 0 0 -15px;
  display: grid; place-items: center; border-radius: 50%;
  transition: opacity .45s var(--ease), transform .45s var(--ease);
  z-index: 2;
}
.pin--done  { --c: #eef2f8; }
.pin--dev   { --c: #8794a8; }
.pin--avail { --c: var(--blue-lt); }
.pin__d {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--c, var(--blue-lt)); box-shadow: 0 0 0 3px rgba(var(--ink-rgb),.65), 0 0 14px var(--c, var(--blue));
  transition: transform .45s var(--ease);
}
.pin:focus-visible { z-index: 6; }
.pin:focus-visible .pin__d, .pin.is-sel .pin__d { transform: scale(1.65); }
@media (hover: hover) {
  .pin:hover { z-index: 6; }
  .pin:hover .pin__d { transform: scale(1.65); }
}
.pin.is-sel { z-index: 5; }
.pin.is-dim { opacity: .14; pointer-events: none; }
/* Markers arrive one after another once the map has faded in. Backwards fill
   only, so once they have landed the filters are free to dim them again. */
html.js .mapstage.is-in .pin { animation: pinIn .7s var(--ease) backwards; animation-delay: calc(.25s + var(--i, 0) * 38ms); }
@keyframes pinIn { from { opacity: 0; transform: translateY(-10px) scale(.6); } }
.pin--avail { width: 44px; height: 44px; margin: -22px 0 0 -22px; z-index: 4; }
.pin--avail .pin__d { width: 13px; height: 13px; }
.pin--avail::before, .pin--avail::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  border: 1px solid var(--c); opacity: 0;
  animation: ping 3.1s var(--ease-soft) infinite;
}
.pin--avail::after { animation-delay: 1.55s; }
@keyframes ping {
  0%   { transform: scale(.28); opacity: .85; }
  70%  { opacity: 0; }
  100% { transform: scale(1); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .pin--avail::before, .pin--avail::after { animation: none; opacity: .35; transform: scale(.7); } }

.tip {
  position: absolute; z-index: 20; left: 50%; bottom: calc(100% + 10px);
  transform: translate(-50%, 6px); width: max-content; max-width: 220px;
  padding: .6rem .8rem; border-radius: 10px;
  background: rgba(var(--ink-rgb),.96); border: 1px solid var(--line-2);
  box-shadow: 0 18px 40px -18px #000;
  font-size: .78rem; line-height: 1.45; color: var(--text);
  opacity: 0; pointer-events: none; transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.pin:focus-visible .tip { opacity: 1; transform: translate(-50%, 0); }
@media (hover: hover) { .pin:hover .tip { opacity: 1; transform: translate(-50%, 0); } }
@media (max-width: 760px), (hover: none) {
  .tip { display: none; }
}
.tip b { display: block; font-family: var(--f-display); font-weight: 500; font-size: .84rem; }
.tip i { font-style: normal; color: var(--faint); }

.mapside {
  border: 1px solid var(--line); border-radius: 16px; padding: 1.5rem;
  background: linear-gradient(168deg, var(--panel-2), var(--panel) 62%);
  position: sticky; top: calc(var(--nav-h) + 30px);
}
.mapside__k { font-size: var(--t-micro); letter-spacing: .16em; text-transform: uppercase; color: var(--faint); }
.mapside__t { font-size: 1.25rem; font-weight: 500; margin: .7rem 0 .1rem; }
.mapside dl { display: grid; grid-template-columns: auto 1fr; gap: .55rem 1rem; margin: 1.3rem 0 0; font-size: .89rem; }
.mapside dt { color: var(--faint); }
.mapside dd { margin: 0; text-align: right; }
.mapside__badge {
  display: inline-flex; align-items: center; gap: .5em; margin-top: 1.2rem;
  font-size: .76rem; letter-spacing: .1em; text-transform: uppercase;
  padding: .4em .9em; border-radius: 999px; border: 1px solid var(--line-2); color: var(--dim);
}
.mapside__badge.is-avail { color: var(--accent-pale); border-color: rgba(var(--accent-rgb),.5); background: var(--blue-wash); }
.maplegend { margin-top: 1.4rem; font-size: .8rem; color: var(--faint); line-height: 1.55; }
.mapside__sub { font-size: .9rem; }
.lg { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: .5em; vertical-align: middle; background: var(--c); }
.lg--avail { --c: var(--blue-lt); }
.lg--done  { --c: #eef2f8; }
.lg--dev   { --c: #8794a8; }
@media (max-width: 1040px) { .mapside { position: static; } }

/* ---------- Asset cards (for sale) --------------------------------------- */
.asset {
  position: relative; overflow: hidden; overflow: clip;
  border: 1px solid rgba(var(--accent-rgb),.34); border-radius: 18px;
  background: linear-gradient(165deg, rgba(var(--accent-rgb),.10), rgba(var(--ink-rgb),.55) 46%), var(--panel);
  padding: clamp(1.5rem, 2.5vw, 2.15rem);
  display: flex; flex-direction: column;
  transition: transform .6s var(--ease), border-color .6s var(--ease), box-shadow .6s var(--ease);
}
@media (hover: hover) {
  .asset:hover { transform: translateY(-5px); border-color: rgba(var(--accent-rgb),.6); box-shadow: 0 28px 60px -34px rgba(var(--accent-rgb),.55); }
}
.asset::before {
  content: ''; position: absolute; top: -60%; right: -30%; width: 70%; aspect-ratio: 1;
  background: radial-gradient(circle, rgba(var(--accent-rgb),.22), transparent 66%);
  pointer-events: none;
}
.asset__badge {
  align-self: flex-start; font-size: var(--t-micro); letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent-pale); border: 1px solid rgba(var(--accent-rgb),.5); background: rgba(var(--accent-rgb),.14);
  padding: .4em .9em; border-radius: 999px;
  display: inline-flex; align-items: center; gap: .55em;
}
.asset__badge::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--accent-lt2);
  box-shadow: 0 0 10px var(--accent-lt2); animation: blip 2.4s ease-in-out infinite;
}
@keyframes blip { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
.asset__cap {
  font-family: var(--f-display); font-size: clamp(2rem, 3.4vw, 2.8rem); font-weight: 500;
  letter-spacing: -.04em; margin: 1.5rem 0 .3rem; line-height: 1; white-space: nowrap;
}
.asset__cap2 { font-family: var(--f-display); font-size: 1.05rem; font-weight: 500; color: var(--blue-lt); letter-spacing: -.02em; }
.asset__loc { color: var(--dim); font-size: .9rem; margin-top: .5rem; }
.asset dl { display: grid; margin: 1.6rem 0 0; padding-top: .4rem; border-top: 1px solid var(--line); }
.asset dl > div { display: grid; gap: .1rem; padding-block: .8rem; border-bottom: 1px solid var(--line); }
.asset dl > div:last-child { border-bottom: 0; }
.asset dt { font-size: .7rem; letter-spacing: .13em; text-transform: uppercase; color: var(--faint); }
.asset dd { margin: 0; color: var(--text); font-size: .92rem; line-height: 1.45; }

/* ==========================================================================
   CONTACT — one question, one address, and the two things people want to
   know before they write: why us, and the answers to what they would ask.
   No form: the whole page leads to a single email address, which is not in
   the HTML and appears only when someone asks for it (site.js).
   ========================================================================== */
/* The hero: the question on the left, the address on the right. Below 1100px
   they stack, address second. */
.ct { padding-bottom: clamp(40px, 5vw, 72px); }
/* close enough that the reasons show at the foot of the first screen, which
   is the only cue anyone needs that there is more below */
.ct + .why { padding-top: clamp(48px, 6vw, 96px); }
.ct__grid { display: grid; gap: clamp(2rem, 5vw, 2.8rem); }
@media (min-width: 1100px) {
  .ct__grid {
    grid-template-columns: minmax(0, .9fr) minmax(0, 1.22fr);
    column-gap: clamp(3rem, 6vw, 6.5rem); align-items: center;
  }
}
.ct__t { max-width: 11.5ch; }
.ct__tip { margin-top: 1rem; padding-inline: .15rem; font-size: .86rem; line-height: 1.55; color: var(--faint); max-width: 62ch; }

/* The card that holds the address. A container, so the address can be sized
   to the card rather than to the window: it is the one line on the page
   that must never break. */
.mx {
  position: relative; overflow: hidden; overflow: clip; isolation: isolate;
  container-type: inline-size;
  border: 1px solid var(--line-2); border-radius: 22px;
  background: linear-gradient(168deg, var(--panel-2), var(--panel) 64%);
  padding: clamp(1.35rem, 3.2vw, 2.5rem);
}
.mx::before {
  content: ''; position: absolute; z-index: -1; top: -58%; left: 50%; width: 84%; aspect-ratio: 1;
  transform: translateX(-50%); pointer-events: none;
  background: radial-gradient(circle, rgba(var(--accent-rgb), .17), transparent 66%);
}
.mx__k, .mx__tk { font-size: var(--t-micro); letter-spacing: .18em; text-transform: uppercase; color: var(--faint); }
.mx__addr {
  margin-top: .85rem; min-height: 1.2em;
  font-family: var(--f-display); font-weight: 500; letter-spacing: -.03em; line-height: 1.15;
  font-size: clamp(1.1rem, 4.4vw, 2.6rem);
  font-size: clamp(1.05rem, 7.4cqi, 3rem);
  overflow-wrap: anywhere;
}
/* Before it is asked for, the address is two redacted bars either side of
   an @: plainly an address, plainly hidden. A light passes over the bars now
   and then, as an invitation. Nothing here looks like an address to a
   harvester — there are no letters in it at all. */
.mx__mask { display: inline-flex; align-items: center; gap: .2em; vertical-align: middle; }
.mx__mask b { font-weight: 500; color: var(--faint); }
.mx__bar {
  position: relative; display: block; overflow: hidden;
  height: .66em; border-radius: .33em; background: rgba(var(--up-rgb), .1);
}
.mx__bar--a { width: 3.3em; }
.mx__bar--b { width: 6.9em; }
.mx__bar::after {
  content: ''; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(var(--up-rgb), .16), transparent);
}
html.js .mx__bar::after { animation: mxSweep 3.6s var(--ease-soft) infinite; }
html.js .mx__bar--b::after { animation-delay: .22s; }
@keyframes mxSweep { 0% { transform: translateX(-100%); } 45%, 100% { transform: translateX(100%); } }
/* ...and when it is asked for, it arrives a letter at a time. */
.mx__link {
  color: var(--text);
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 2px; background-position: 0 100%; background-repeat: no-repeat;
  transition: background-size .5s var(--ease), color .3s var(--ease);
}
.mx__link:focus-visible { background-size: 100% 2px; outline-offset: 6px; }
@media (hover: hover) { .mx__link:hover { background-size: 100% 2px; } }
.mx__ch { display: inline-block; white-space: pre; }
html.js .mx__ch { animation: mxIn .8s var(--ease) both; animation-delay: calc(var(--i, 0) * 17ms); }
@keyframes mxIn {
  from { opacity: 0; transform: translate3d(0, .5em, 0); color: var(--blue-lt); }
  55%  { color: var(--blue-lt); }
}
.mx__row { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin-top: clamp(1.3rem, 2.4vw, 1.8rem); }
.btn.is-done { --fg: var(--blue-lt); --bd: rgba(var(--accent-rgb), .6); }
.btn.is-done::before {
  content: ''; width: .42em; height: .8em; margin: 0 .1em 0 .05em; flex: none;
  border: solid currentColor; border-width: 0 1.6px 1.6px 0; transform: translateY(-.12em) rotate(45deg);
}
@media (max-width: 560px) {
  .mx__row .btn { flex: 1 1 auto; justify-content: center; }
}
.mx__topics {
  display: flex; flex-wrap: wrap; align-items: center; gap: .7rem 1.1rem;
  margin-top: clamp(1.4rem, 2.6vw, 1.9rem); padding-top: clamp(1.1rem, 2vw, 1.4rem);
  border-top: 1px solid var(--line);
}
.mx__chips { display: flex; flex-wrap: wrap; gap: .45rem; }
.ichip {
  border: 1px solid var(--line-2); border-radius: 99px; color: var(--dim);
  padding: .5rem 1.05rem; font-size: .86rem; cursor: pointer;
  transition: color .35s var(--ease), border-color .35s var(--ease), background .35s var(--ease);
}
@media (hover: hover) { .ichip:hover { color: var(--text); border-color: rgba(var(--accent-rgb),.5); background: var(--blue-wash); } }
.ichip:active { transform: scale(.97); }
.ichip.is-on { color: var(--up); border-color: rgba(var(--accent-rgb),.65); background: rgba(var(--accent-rgb),.24); }
/* Without JavaScript nothing can put the address together, so nothing
   pretends it can. */
html:not(.js) [data-mail-btn], html:not(.js) .mx__topics { display: none; }

/* The same address at the foot of the page, for whoever read to the end. */
.ct-end__mail { display: grid; justify-items: center; gap: 1.1rem; margin-top: clamp(1.8rem, 3vw, 2.4rem); }
.ct-end__mail .mx__row { justify-content: center; margin-top: 0; }
.mx__addr--sm { margin: 0; min-height: 0; font-size: clamp(1.2rem, 3.4vw, 2.1rem); }
.mx__addr--sm:empty { display: none; }

/* Why Energex — four reasons, all of them readable at once: a short title
   large enough to take in at a glance, and one plain sentence under it. */
.why .sec-title { margin-bottom: clamp(2.2rem, 4.4vw, 3.4rem); }
.why__list {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(2.2rem, 3.6vw, 2.8rem) clamp(1.4rem, 3vw, 3rem);
}
@media (max-width: 1080px) { .why__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px)  { .why__list { grid-template-columns: 1fr; gap: 2.1rem; } }
.why__i { position: relative; padding-top: clamp(1.2rem, 2vw, 1.6rem); border-top: 1px solid var(--line-2); }
.why__i::before {
  content: ''; position: absolute; left: 0; top: -1px; width: 44px; height: 1px;
  background: var(--blue); box-shadow: 0 0 10px var(--blue-glow);
  transition: width .7s var(--ease);
}
@media (hover: hover) { .why__i:hover::before { width: 100%; } }
.why__n { display: block; font-size: var(--t-micro); letter-spacing: .16em; color: var(--blue-lt); font-variant-numeric: tabular-nums; }
.why__t {
  margin-top: clamp(.8rem, 1.4vw, 1.05rem);
  font-family: var(--f-display); font-weight: 500; line-height: 1.1; letter-spacing: -.03em;
  font-size: clamp(1.5rem, 2.2vw, 1.95rem);
}
.why__p { margin-top: .7rem; color: var(--dim); font-size: .94rem; line-height: 1.62; max-width: 36ch; }
.why + .qa { padding-top: 0; }

/* Questions — each one shows its short answer without being opened, so the
   list can be read straight down like a spec sheet; opening one gives the
   whole answer. Plain <details>: it all works with JavaScript off, and the
   full answers are real text in the page for search engines to read. */
.qa .sec-title { margin-bottom: clamp(1.8rem, 3.6vw, 2.8rem); }
.qa__list { border-top: 1px solid var(--line-2); }
.qa__i { border-bottom: 1px solid var(--line); }
.qa__i > summary {
  list-style: none; cursor: pointer; position: relative;
  display: grid; grid-template-columns: 2.4rem minmax(0, 1fr) 1.3rem;
  column-gap: .9rem; row-gap: .3rem; align-items: baseline;
  padding: 1.15rem 0;
}
.qa__i > summary::-webkit-details-marker { display: none; }
.qa__i > summary:focus-visible { outline: 2px solid var(--blue-lt); outline-offset: 4px; border-radius: 6px; }
.qa__n {
  grid-row: 1 / span 2; font-size: var(--t-micro); letter-spacing: .14em; color: var(--faint);
  font-variant-numeric: tabular-nums; transition: color .3s var(--ease);
}
.qa__q {
  grid-column: 2; font-family: var(--f-display); font-weight: 500; letter-spacing: -.015em;
  font-size: clamp(1.02rem, 1.5vw, 1.18rem); line-height: 1.38; transition: color .3s var(--ease);
}
.qa__s { grid-column: 2; grid-row: 2; color: var(--dim); font-size: .92rem; line-height: 1.45; transition: color .3s var(--ease); }
/* level with the first line of the question, however many lines it runs to */
.qa__i > summary i {
  grid-column: 3; grid-row: 1; align-self: start; justify-self: end;
  position: relative; width: 13px; height: 13px; margin-top: .52em; opacity: .75;
}
.qa__i > summary i::before, .qa__i > summary i::after {
  content: ''; position: absolute; left: 0; top: 6px; width: 13px; height: 1.5px;
  background: currentColor; transition: transform .35s var(--ease);
}
.qa__i > summary i::after { transform: rotate(90deg); }
.qa__i[open] > summary i::after { transform: rotate(0deg); }
.qa__i[open] .qa__n, .qa__i[open] .qa__s { color: var(--blue-lt); }
@media (hover: hover) { .qa__i > summary:hover .qa__q { color: var(--blue-lt); } }
.qa__a { padding: 0 0 1.5rem calc(2.4rem + .9rem); }
.qa__a p { color: var(--dim); font-size: .97rem; line-height: 1.7; max-width: 66ch; }
@media (min-width: 900px) {
  .qa__i > summary {
    grid-template-columns: 3.2rem minmax(0, 1.2fr) minmax(0, 1fr) 1.3rem;
    column-gap: 1.6rem; padding: 1.4rem 0;
  }
  .qa__n { grid-row: 1; }
  .qa__s { grid-column: 3; grid-row: 1; }
  .qa__i > summary i { grid-column: 4; }
  .qa__a { padding-left: calc(3.2rem + 1.6rem); }
}
html.js .qa__i[open] > .qa__a { animation: faqIn .4s var(--ease) both; }
/* Opens smoothly where the browser can animate to a height of auto, and
   simply appears where it cannot. */
@supports (interpolate-size: allow-keywords) {
  .qa__list { interpolate-size: allow-keywords; }
  .qa__i::details-content {
    block-size: 0; overflow: clip;
    transition: block-size .5s var(--ease), content-visibility .5s allow-discrete;
  }
  .qa__i[open]::details-content { block-size: auto; }
}
@media (prefers-reduced-motion: reduce) {
  html.js .mx__bar::after { animation: none; }
  html.js .mx__ch { animation: none; }
  html.js .qa__i[open] > .qa__a { animation: none; }
  .qa__i::details-content { transition: none; }
  .why__i::before { transition: none; }
}

/* ---------- CTA band ------------------------------------------------------ */
.cta {
  position: relative; overflow: hidden; overflow: clip;
  border-top: 1px solid var(--line);
  padding-block: clamp(72px, 9vw, 132px);
  text-align: center;
}
.cta::before {
  content: ''; position: absolute; inset: auto 0 -60% 0; height: 150%;
  background: radial-gradient(45% 55% at 50% 100%, rgba(var(--accent-rgb),.20), transparent 68%);
  pointer-events: none;
}
.cta__t { font-size: var(--t-h2); font-weight: 500; max-width: 20ch; margin-inline: auto; }
.cta__p { margin: 1.4rem auto 0; max-width: 52ch; }
.cta .btn-row { justify-content: center; margin-top: 2.4rem; }

/* ---------- Footer -------------------------------------------------------- */
/* Positioned and opaque, so on the home page it sits above the fixed particle
   field instead of underneath its veil. */
.foot {
  position: relative; z-index: 3; background: var(--ink);
  border-top: 1px solid var(--line); padding-block: clamp(1.8rem, 3vw, 2.6rem);
}
.foot__bot {
  display: flex; flex-wrap: wrap; gap: 1.2rem 2.5rem; justify-content: space-between; align-items: center;
  font-size: .82rem; color: var(--faint);
}
.foot__nav { display: flex; flex-wrap: wrap; gap: 1.6rem; }
.foot__nav a { color: var(--dim); padding-block: .55rem; transition: color .35s var(--ease); }
.foot__nav a[aria-current="page"] { color: var(--text); }
@media (hover: hover) { .foot__nav a:hover, .foot__bot a:hover { color: var(--text); } }
@media (max-width: 640px) {
  .foot__bot { flex-direction: column; align-items: flex-start; gap: 1.4rem; }
  .foot__nav { gap: 1.1rem; }
}

/* ---------- 404 ----------------------------------------------------------- */
.nf { min-height: 100vh; min-height: 100svh; display: grid; place-items: center; text-align: center; padding: var(--nav-h) var(--gut); }
.nf__n {
  font-family: var(--f-display); font-size: clamp(5rem, 22vw, 14rem); font-weight: 500;
  letter-spacing: -.06em; line-height: .85;
  background: linear-gradient(180deg, var(--up), var(--blue) 150%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.nf__t { font-size: var(--t-h2); font-weight: 500; margin-top: 1.2rem; }
.nf .btn-row { justify-content: center; margin-top: 2rem; }

/* ---------- Legal / prose ------------------------------------------------- */
.prose { max-width: 74ch; }
.prose h2 { font-size: clamp(1.25rem, 2vw, 1.6rem); margin: 2.8rem 0 .9rem; }
.prose h2:first-child { margin-top: 0; }
.prose p { color: var(--dim); margin-bottom: 1rem; font-size: .97rem; }
.prose ul { display: grid; gap: .55rem; margin: 0 0 1.2rem; }
.prose li { color: var(--dim); font-size: .97rem; padding-left: 1.4rem; position: relative; }
.prose li::before { content: ''; position: absolute; left: 0; top: .72em; width: 7px; height: 1px; background: var(--blue); }
.prose strong { color: var(--text); font-weight: 500; }

/* ---------- Print --------------------------------------------------------- */
@media print {
  .nav, .menu, .veil, .progress, .intro, .stage, .beatnav, .cta { display: none !important; }
  body { background: #fff; color: #000; }
  html.js [data-reveal], html.js .rw > span, html.js .beat__in { opacity: 1 !important; transform: none !important; }
}


/* ==========================================================================
   THE SCENE — one fixed particle field the whole home page scrolls through
   ========================================================================== */
.stage { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
  isolation: isolate; }   /* keeps the glow layer's blending inside the scene */
.stage canvas { width: 100%; height: 100%; position: relative; z-index: 1; }

/* The particle glow. A canvas a sixth of the size, stretched over the scene
   and added to it by the compositor: the smooth stretch is the blur, and the
   GPU does it for free. Scaling it back up through the 2D context instead
   costs a full filtered copy of the frame, every frame, on the CPU. */
.stage__bloom {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 2; pointer-events: none; opacity: .62;
  mix-blend-mode: plus-lighter;
}
@supports not (mix-blend-mode: plus-lighter) {
  .stage__bloom { mix-blend-mode: screen; }
}
/* The field's halo. A composited layer the scene moves with a transform,
   rather than a large translucent circle repainted on the canvas each frame. */
.stage__glow {
  position: absolute; left: 0; top: 0; width: 200px; height: 200px;
  border-radius: 50%; pointer-events: none; transform-origin: 0 0; opacity: 0;
  background: radial-gradient(circle closest-side,
    rgba(var(--accent-rgb),.15) 0%, rgba(var(--accent-rgb),.05) 38%, rgba(var(--accent-rgb),0) 78%);
  will-change: transform, opacity;
}
/* The veil takes the ground colour through --veil-rgb rather than --ink-rgb
   directly. They hold the same value; the difference is that the palette walk
   moves this one in a few coarse steps instead of every step. Two gradients
   across the whole viewport are the most expensive thing on the page to
   rasterise, and this is a near-black wash over a near-black ground: five
   steps per scheme and twenty-eight look identical. Without JavaScript, or
   with a scheme pinned, it falls through to --ink-rgb and never moves. */
.stage__veil {
  position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(128% 62% at 50% 108%, rgba(var(--veil-rgb, var(--ink-rgb)),.86) 22%, transparent 70%),
    linear-gradient(180deg, rgba(var(--veil-rgb, var(--ink-rgb)),.72) 0%, transparent 22%, transparent 74%, rgba(var(--veil-rgb, var(--ink-rgb)),.72) 100%);
}
@media (max-width: 820px) {
  .stage__veil {
    background:
      radial-gradient(120% 44% at 50% 92%, rgba(var(--veil-rgb, var(--ink-rgb)),.86) 24%, transparent 78%),
      linear-gradient(180deg, rgba(var(--veil-rgb, var(--ink-rgb)),.6) 0%, transparent 16%, rgba(var(--veil-rgb, var(--ink-rgb)),.46) 44%, rgba(var(--veil-rgb, var(--ink-rgb)),.74) 100%);
  }
}
.track { position: relative; z-index: 2; }

.beat {
  min-height: 100vh; min-height: 100svh; display: grid; align-items: center;
  padding: calc(var(--nav-h) + 24px) 0 clamp(72px, 12vh, 128px);
  position: relative;
}
.beat__in { width: 100%; }
html.js .beat__in { will-change: opacity, transform; }
/* Below 900px the scene draws the map and the mark in the upper part of the
   screen, so on those two beats the words settle into the lower part rather
   than across the particles. */
@media (max-width: 899px) and (min-height: 600px) {
  .beat--wide, .beat--end { align-items: end; }
  .beat--end { padding-bottom: clamp(72px, 18vh, 240px); }   /* short block: lift it toward the mark */
}
@media (max-width: 899px) and (min-height: 1000px) {
  .beat--wide { padding-bottom: 20vh; }                        /* tall tablets: close the gap under the map */
}

.beat h1, .beat h2 { font-weight: 500; letter-spacing: -.04em; }
.beat__lead { font-size: var(--t-lead); color: var(--dim); max-width: 44ch; margin-top: 1.4rem; }

/* Beat 1 — the single line */
.beat--open .beat__in { text-align: left; }
.hero-line {
  font-size: clamp(2.5rem, 6.1vw, 5.5rem);
  line-height: 1.0; letter-spacing: -.042em; max-width: 16ch;
}
.hero-line em { font-style: normal; color: var(--blue-lt); }

/* Beat 3 — the four services. Below 900px they stack in reading order; above
   it they take the four points of a ring — Consult at nine, Develop at twelve,
   Equip at three, Build at six — which reads clockwise and leaves the four
   corners of the beat free for the scene behind them. */
.quad { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 1.8rem 2rem; }
@media (max-width: 560px)  { .quad { grid-template-columns: 1fr; gap: 0; } }
.quad__i {
  display: block; text-decoration: none; color: inherit;
  border-top: 1px solid var(--line-2); padding: 1.3rem 0 .4rem;
  position: relative; transition: border-color .4s var(--ease);
}
@media (max-width: 560px) { .quad__i { padding: 1.1rem 0 1.2rem; } }
.quad__i::after {
  content: ''; position: absolute; left: 0; top: -1px; height: 1px; width: 100%;
  background: var(--blue); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .5s var(--ease);
}
.quad__i:focus-visible::after, .quad__i:active::after { transform: scaleX(1); }
.quad__i:focus-visible { outline: 2px solid var(--blue); outline-offset: 6px; border-radius: 3px; }
.quad__k {
  display: flex; align-items: baseline; gap: .5rem;
  font-family: var(--f-display); font-weight: 500;
  font-size: clamp(1.5rem, 2.5vw, 2.15rem); letter-spacing: -.03em; line-height: 1;
  transition: color .35s var(--ease);
}
.quad__i:focus-visible .quad__k, .quad__i:active .quad__k { color: var(--blue-lt); }
.quad__a {
  display: inline-flex; opacity: 0; transform: translateX(-6px);
  transition: opacity .35s var(--ease), transform .35s var(--ease);
}
.quad__i:focus-visible .quad__a { opacity: 1; transform: none; }
/* No hover on a phone, so the arrow is simply there: it is what says these
   four are links. */
@media (hover: none) { .quad__a { opacity: .7; transform: none; } }
@media (hover: hover) {
  .quad__i:hover::after { transform: scaleX(1); }
  .quad__i:hover .quad__k { color: var(--blue-lt); }
  .quad__i:hover .quad__a { opacity: 1; transform: none; }
}
.quad__p { display: block; margin-top: .9rem; color: var(--dim); font-size: .95rem; max-width: 28ch; }

/* The four sit on a clock face from 900px up — nine, twelve, three and six —
   with nothing in the middle: the empty centre is what makes the ring read,
   and each of the four is already its own way through to the services page. */
@media (min-width: 900px) {
  .quad {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.06fr) minmax(0, 1fr);
    grid-template-rows: auto auto auto;
    row-gap: clamp(2rem, 6.4vh, 4.4rem);
    column-gap: clamp(1.4rem, 3vw, 3rem);
    align-items: center;
  }
  .quad__i { max-width: 31ch; }
  .quad__i:nth-child(1) { grid-column: 1; grid-row: 2; }                       /* Consult — nine */
  .quad__i:nth-child(2) { grid-column: 2; grid-row: 1; justify-self: center; text-align: center; }  /* Develop — twelve */
  .quad__i:nth-child(3) { grid-column: 3; grid-row: 2; justify-self: end; text-align: right; }      /* Equip — three */
  .quad__i:nth-child(4) { grid-column: 2; grid-row: 3; justify-self: center; text-align: center; }  /* Build — six */
  .quad__i:nth-child(2) .quad__k,
  .quad__i:nth-child(4) .quad__k { justify-content: center; }
  .quad__i:nth-child(3) .quad__k { justify-content: flex-end; }
  .quad__i:nth-child(2) .quad__p,
  .quad__i:nth-child(4) .quad__p { margin-inline: auto; }
  .quad__i:nth-child(3) .quad__p { margin-left: auto; }
  .quad__i:nth-child(3)::after,
  .quad__i:nth-child(2)::after,
  .quad__i:nth-child(4)::after { transform-origin: 50% 50%; }
}

/* Beat 2 — portfolio figures, sitting over the map */
.stats {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.4rem 2rem; max-width: 620px;
  margin-top: clamp(1.8rem, 3.5vw, 2.6rem);
}
.stat__n {
  display: block; white-space: nowrap;
  font-family: var(--f-display); font-weight: 500; line-height: 1;
  font-size: clamp(1.75rem, 3.2vw, 2.7rem); letter-spacing: -.045em;
  background: linear-gradient(180deg, var(--up) 25%, var(--accent-pale) 145%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.stat__u { font-size: max(11.5px, .38em); letter-spacing: .02em; margin-left: .22em; -webkit-text-fill-color: var(--dim); }
.stat__l { display: block; margin-top: .55rem; font-size: .8rem; line-height: 1.35; color: var(--faint); max-width: 22ch; }
@media (max-width: 760px) {
  .stats { grid-template-columns: 1fr; gap: .9rem; max-width: none; }
  .stat { display: flex; align-items: baseline; gap: .8rem; }
  .stat__n { font-size: 1.65rem; }
  .stat__l { margin-top: 0; max-width: none; }
}

/* Beat 4 / 5 */
.beat--wide h2, .beat--end h2 { max-width: 15ch; }
.beat--end .beat__lead { max-width: 34ch; }
.beat--wide .beat__lead { max-width: 42ch; }

/* Scroll cue */
.cue-wrap { position: absolute; left: 0; right: 0; bottom: clamp(26px, 5vh, 46px); }
.cue {
  display: inline-flex; align-items: center; gap: .8rem;
  font-size: var(--t-micro); letter-spacing: .2em; text-transform: uppercase; color: var(--faint);
}
.cue i { display: block; width: 46px; height: 1px; background: var(--line-2); position: relative; overflow: hidden; }
.cue i::after { content: ''; position: absolute; inset: 0; background: var(--blue); animation: cue 2.4s var(--ease) infinite; }
@keyframes cue { 0% { transform: translateX(-100%); } 55%,100% { transform: translateX(100%); } }

/* ==========================================================================
   Intro — the mark draws itself once, then the scene arrives
   ========================================================================== */
.intro {
  position: fixed; inset: 0; z-index: 450; background: var(--ink);
  display: grid; place-items: center;
}
.intro__mark { width: 74px; opacity: 0; }
html:not(.js) .intro { display: none; }
.intro.is-gone { opacity: 0; visibility: hidden; transition: opacity .7s var(--ease), visibility .7s; }
@media (prefers-reduced-motion: reduce) { .intro { display: none; } }

/* map: give it more room now that it carries the whole project list */
.mapwrap--tall .mapstage__inner { aspect-ratio: 1000 / 650; }

/* ---------- Beat indicator ------------------------------------------------ */
.beatnav {
  position: fixed; right: clamp(14px, 2vw, 26px); top: 50%; transform: translateY(-50%);
  right: max(clamp(14px, 2vw, 26px), env(safe-area-inset-right, 0px));
  z-index: 60; display: grid; gap: 8px;
}
.beatnav button {
  display: block; width: 24px; height: 24px; padding: 0; position: relative;
}
.beatnav button::after {
  content: ''; position: absolute; right: 7px; top: 50%; transform: translateY(-50%);
  width: 6px; height: 6px; border-radius: 99px;
  background: rgba(var(--up-rgb),.22);
  transition: background .5s var(--ease), height .5s var(--ease), width .5s var(--ease);
}
.beatnav button:hover::after { background: rgba(var(--up-rgb),.55); }
.beatnav button.is-on::after { background: var(--blue-lt); height: 18px; box-shadow: 0 0 10px var(--blue-glow); }
@media (max-width: 820px) { .beatnav { display: none; } }

/* ==========================================================================
   AN EXAMPLE PROJECT FROM START TO FINISH — the services page, drawn.
   One scene is the backdrop for the whole section: the four services float in
   its sky, and the project is built on its ground. The walkthrough below is a
   player rather than a scroll — journey.js says why.
   ========================================================================== */
.jr { position: relative; }
.jr__bg { position: relative; z-index: 0; }
html.js .jr__bg {
  position: sticky; top: 0; height: 100vh; margin-bottom: -100vh;
  height: 100svh; margin-bottom: -100svh;
  overflow: hidden; background: var(--ink); pointer-events: none;
}
.jr__canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: none; }
html.js .jr__canvas { display: block; }
.jr__wash {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(var(--ink-rgb), .72) 0%, rgba(var(--ink-rgb), .34) 22%,
    rgba(var(--ink-rgb), .46) 46%, rgba(var(--ink-rgb), .78) 80%, rgba(var(--ink-rgb), .9) 100%);
}
html:not(.js) .jr__bg { background: linear-gradient(180deg, var(--ink-2), var(--ink)); height: auto; }

.jr__intro, .jr__run { position: relative; z-index: 1; }
.jr__intro {
  padding-top: calc(var(--nav-h) + clamp(26px, 4vw, 54px));
  padding-bottom: clamp(22px, 3.4vw, 44px);
}
.jr__h1 {
  font-size: var(--t-h1); font-weight: 500; letter-spacing: -.035em; line-height: 1; margin: 0;
  text-shadow: 0 0 24px rgba(var(--ink-rgb), .85);
}
.jr-intro__t {
  font-family: var(--f-display); font-weight: 500; letter-spacing: -.035em; line-height: 1.05;
  font-size: clamp(1.55rem, 3.4vw, 2.9rem); margin: clamp(3.6rem, 7vw, 6rem) 0 0;
  /* one line wherever it fits; where it cannot, two even lines rather than a
     straggling last word */
  text-wrap: balance;
  text-shadow: 0 0 22px rgba(var(--ink-rgb), .9), 0 2px 6px rgba(var(--ink-rgb), .85);
}
/* an obvious, quiet way down — and a link straight to the walkthrough */
.jr__cue {
  display: inline-flex; align-items: center; gap: .8em; margin: clamp(1.6rem, 3vw, 2.6rem) 0 0;
  text-decoration: none; color: var(--dim);
  font-size: var(--t-micro); letter-spacing: .16em; text-transform: uppercase;
  transition: color .35s var(--ease);
}
.jr__cue-r {
  display: grid; place-items: center; width: 38px; height: 38px; flex: none;
  border-radius: 50%; border: 1px solid rgba(var(--accent-rgb), .45);
  background: rgba(var(--ink-rgb), .55); color: var(--blue-lt);
  transition: border-color .35s var(--ease), background-color .35s var(--ease), transform .35s var(--ease);
}
html.js .jr.is-live .jr__cue-r { animation: jrBob 2.6s var(--ease-soft) infinite; }
@keyframes jrBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(5px); }
}
@media (hover: hover) {
  .jr__cue:hover { color: var(--text); }
  .jr__cue:hover .jr__cue-r { border-color: rgba(var(--accent-rgb), .9); background: rgba(var(--accent-rgb), .16); }
}
.jr__cue:focus-visible { outline: 2px solid var(--blue); outline-offset: 6px; border-radius: 999px; }
@media (prefers-reduced-motion: reduce) {
  html.js .jr.is-live .jr__cue-r { animation: none; }
}

/* ---- the walkthrough: a pinned run of scroll ---- */
/* vh first for Safari before 15.4, which does not know svh; a custom property
   holding a unit it cannot parse would otherwise leave the run with no height */
.jr__run { position: relative; --jstep: 100vh; }
html.js .jr__run { height: calc(100vh + (9 - 1) * var(--jstep)); }
@supports (height: 100svh) {
  .jr__run { --jstep: 100svh; }
  html.js .jr__run { height: calc(100svh + (9 - 1) * var(--jstep)); }
}
.jr__stage { position: relative; }
html.js .jr__stage {
  position: sticky; top: 0; height: 100vh; height: 100svh; display: flex; flex-direction: column;
  padding-top: var(--nav-h); padding-bottom: clamp(18px, 3.4vh, 42px);
}
html.js .jr__stage > .wrap-n,
html.js .jr__stage > .wrap-n > .inset { flex: 1 1 auto; display: flex; flex-direction: column; }

.jr__deck { position: relative; flex: 1 1 auto; min-height: clamp(250px, 38vh, 370px); min-height: clamp(250px, 38svh, 370px); }
html.js .jr__deck > .jr__c {
  position: absolute; left: 0; right: 0; bottom: 0; pointer-events: none;
}
html.js .jr__deck > .jr__c.is-on { pointer-events: auto; }
/* the bottom padding is what keeps the last bullet off the rail */
.jr__c { padding: 0 0 clamp(1.15rem, 3vh, 2.2rem); width: min(34rem, 100%); }
html.js .jr__c::before {
  content: ""; position: absolute; inset: -20px -34px -24px -30px; z-index: -1; pointer-events: none;
  border-radius: 22px; opacity: var(--bed, 0);
  background: radial-gradient(128% 118% at 26% 58%,
    rgba(var(--ink-rgb), .94), rgba(var(--ink-rgb), .82) 46%,
    rgba(var(--ink-rgb), .5) 78%, rgba(var(--ink-rgb), 0) 100%);
  /* its own layer: the bed fades every frame of a hand-over, and without
     this each of those frames repainted the whole gradient */
  will-change: opacity;
}
/* On a phone the caption is as wide as the column, so the bed's overhang
   reached past the edge of the screen: the page grew wider than the phone
   and the menu button slid half out of view. Here it runs edge to edge. */
@media (max-width: 560px) {
  html.js .jr__c::before { left: calc(-1 * var(--gut)); right: calc(-1 * var(--gut)); }
}

/* The hand-over is painted straight from the scroll position by journey.js —
   opacity, offset and the wipe on the key line are all functions of where you
   are, not animations with their own clock. CSS only says where things rest,
   so nothing here can start running on its own and break the connection to
   your hand. */
html.js .jr__c > *:not(canvas) { will-change: opacity, transform; }
html.js .jr__key { will-change: clip-path; }

.jr__n {
  font-family: var(--f-body); font-size: var(--t-micro); letter-spacing: .18em; text-transform: uppercase;
  color: var(--faint); margin: 0 0 .8rem;
}
.jr__n b { color: var(--blue-lt); font-weight: 500; }
.jr__n--mile, .jr__n--sub { color: var(--blue-lt); letter-spacing: .26em; }
.jr__t {
  font-family: var(--f-display); font-weight: 500; letter-spacing: -.035em; line-height: 1;
  font-size: clamp(2rem, 4.4vw, 3.2rem); margin: 0;
}
.jr__t--mile { font-size: clamp(1.75rem, 3.6vw, 2.6rem); }
.jr__key {
  margin: .55rem 0 0; color: var(--blue-lt);
  font-size: var(--t-micro); letter-spacing: .17em; text-transform: uppercase;
}
.jr__pts { margin: 1rem 0 0; display: grid; gap: .45rem; list-style: none; padding: 0; }
.jr__pts li { position: relative; padding-left: 1.4rem; color: var(--dim); font-size: .94rem; }
.jr__pts li::before {
  content: ""; position: absolute; left: 0; top: .62em; width: 6px; height: 6px; border-radius: 50%;
  background: var(--blue-lt); box-shadow: 0 0 8px var(--blue-glow);
}
.jr__still { display: none; width: 100%; aspect-ratio: 16 / 9; border-radius: 14px; border: 1px solid var(--line); margin-bottom: 1.4rem; }
html.jr-still .jr__still { display: block; }

/* ---- the rail: every stage is a button ---- */
.jr__rail {
  position: relative; list-style: none; margin: 0 0 clamp(.8rem, 2vh, 1.4rem); padding: 0;
  display: flex; align-items: flex-start; justify-content: space-between; gap: 2px;
}
html.js .jr__rail::before {
  content: ""; position: absolute; left: 4px; right: 4px; top: 10px; height: 1px;
  background: linear-gradient(90deg, transparent, var(--line-2) 8%, var(--line-2) 92%, transparent);
}
html.js .jr__line { position: absolute; left: 4px; right: 4px; top: 10px; height: 1px; overflow: hidden; }
html.js .jr__line span {
  position: absolute; inset: 0; transform-origin: left; transform: scaleX(var(--f, 0));
  background: linear-gradient(90deg, var(--blue-lt), rgba(var(--accent-rgb), .3));
  transition: transform .5s var(--ease);
}
.jr__rail button {
  display: flex; flex-direction: column; align-items: center; gap: .55em;
  cursor: pointer; background: none; border: 0; padding: 6px 2px 0; color: inherit;
}
.jr__rail i {
  display: block; width: 9px; height: 9px; border-radius: 50%; flex: none;
  border: 1px solid var(--line-2); background: var(--ink);
  transition: background-color .4s var(--ease), border-color .4s var(--ease), box-shadow .4s var(--ease), transform .4s var(--ease);
}
.jr__r--mile i { border-radius: 2px; transform: rotate(45deg); width: 8px; height: 8px; }
.jr__rail span {
  font-size: .58rem; letter-spacing: .1em; text-transform: uppercase; color: var(--dim);
  white-space: nowrap; transition: color .4s var(--ease);
  text-shadow: 0 0 9px rgba(var(--ink-rgb), .95);
}
html.js .jr__rail .is-past i { border-color: rgba(var(--accent-rgb), .7); background: rgba(var(--accent-rgb), .25); }
html.js .jr__rail .is-now i { background: var(--blue-lt); border-color: var(--blue-lt); box-shadow: 0 0 14px var(--blue-glow); transform: scale(1.3); }
html.js .jr__r--mile.is-now i { transform: rotate(45deg) scale(1.25); }
html.js .jr__rail .is-now span { color: var(--blue-lt); }
@media (hover: hover) {
  .jr__rail button:hover span { color: var(--text); }
  .jr__rail button:hover i { border-color: rgba(var(--accent-rgb), .8); }
}
.jr__rail button:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; border-radius: 8px; }
/* On a touch screen the dots are small targets for a thumb, so each one's hit
   area is widened to about 40px square without moving anything you can see.
   Nine of them across a phone are 43px apart, so they never overlap. */
@media (pointer: coarse) {
  .jr__rail button { position: relative; }
  .jr__rail button::after { content: ""; position: absolute; inset: -12px -13px -14px; }
}

@media (max-width: 900px) {
  /* no room for the names under the dots, but they stay the buttons' names */
  .jr__rail span {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .jr-intro__t { font-size: clamp(1.55rem, 5.4vw, 1.9rem); }
  .jr__pts li { font-size: .9rem; }
}

/* ==========================================================================
   FOUR SERVICES — the page opens on them: what each one is, the slice of a
   project it covers, and the full scope for anyone who wants it. The journey
   below then shows the same four doing the work.
   ========================================================================== */
.svcs__grid {
  list-style: none; margin: clamp(2rem, 4vw, 3rem) 0 0; padding: 0;
  display: grid; gap: clamp(.8rem, 1.6vw, 1.1rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9.5rem), 1fr));
}
.svcs__c {
  border: 1px solid var(--line); border-radius: 14px;
  background: linear-gradient(168deg, var(--panel-2), var(--panel) 62%);
  padding: clamp(.95rem, 1.5vw, 1.2rem);
  display: flex; flex-direction: column;
}
.svcs__n { font-size: .62rem; letter-spacing: .18em; color: var(--blue-lt); margin: 0 0 .5rem; }
.svcs__t { font-family: var(--f-display); font-size: clamp(1.05rem, 1.5vw, 1.28rem); font-weight: 500; letter-spacing: -.02em; margin: 0; }
.svcs__p { color: var(--dim); font-size: .86rem; line-height: 1.5; margin: .45rem 0 0; }
.svcs__cov {
  display: flex; align-items: center; gap: .6em; margin-top: auto; padding-top: .9rem;
  font-size: .6rem; letter-spacing: .12em; text-transform: uppercase; color: var(--faint);
}
.svcs__bar {
  position: relative; display: block; flex: none; width: 60px; height: 5px; border-radius: 3px;
  background: rgba(var(--up-rgb), .1);
}
.svcs__bar i {
  position: absolute; top: 0; bottom: 0; border-radius: 3px;
  left: calc(var(--from) / 6 * 100%); width: calc((var(--to) - var(--from)) / 6 * 100%);
  background: var(--blue-lt); box-shadow: 0 0 10px var(--blue-glow);
}
.svcs__more { padding-top: .75rem; }
/* On a phone the four go two by two and drop to the essentials, so that the
   journey's title is on the first screen with them. The fuller wording is a
   tap away in the scope, where it was going to live anyway. */
@media (max-width: 620px) {
  .svcs__p { display: none; }
  .svcs__c { padding: .85rem .9rem; }
  .svcs__cov { padding-top: .8rem; }
}
.svcs__more > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding-top: .75rem; border-top: 1px solid var(--line);
  font-size: .74rem; color: var(--faint); transition: color .3s var(--ease);
}
.svcs__more > summary::-webkit-details-marker { display: none; }
.svcs__more > summary::after {
  content: ''; width: 9px; height: 9px; flex: none; border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor; transform: translateY(-2px) rotate(45deg);
  transition: transform .35s var(--ease);
}
.svcs__more[open] > summary::after { transform: translateY(1px) rotate(-135deg); }
@media (hover: hover) { .svcs__more > summary:hover { color: var(--text); } }
.svcs__more ul { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .5rem; }
.svcs__intro { color: var(--dim); font-size: .86rem; line-height: 1.55; margin: .9rem 0 0; }
.svcs__more li { position: relative; padding-left: 1.4rem; color: var(--dim); font-size: .86rem; }
.svcs__more li::before {
  content: ''; position: absolute; left: 0; top: .6em; width: 5px; height: 5px; border-radius: 50%;
  background: var(--blue-lt);
}
.svcs__note { font-size: .82rem; color: var(--faint); margin: 1rem 0 0; }
/* Opens the way the FAQ does: smoothly where the browser can animate to a
   height of auto, and simply where it cannot. */
html.js .svcs__more[open] > ul { animation: faqIn .4s var(--ease) both; }
@supports (interpolate-size: allow-keywords) {
  .svcs__grid { interpolate-size: allow-keywords; }
  .svcs__more::details-content {
    block-size: 0; overflow: clip;
    transition: block-size .5s var(--ease), content-visibility .5s allow-discrete;
  }
  .svcs__more[open]::details-content { block-size: auto; }
}

/* ---- less motion, by request: nothing plays, nothing pins, the nine stages
   are an ordinary list with a still drawing of each ---- */
@media (prefers-reduced-motion: reduce) {
  html.js .jr__bg { position: static; height: auto; margin-bottom: 0; }
  html.js .jr__canvas { display: none; }
  html.js .jr__wash { display: none; }
  html.js .jr__run { height: auto; }
  html.js .jr__stage { position: static; height: auto; display: block; padding-top: 3vh; }
  html.js .jr__stage > .wrap-n, html.js .jr__stage > .wrap-n > .inset { display: block; }
  html.js .jr__deck { position: static; min-height: 0; }
  html.js .jr__deck > .jr__c {
    position: static; width: auto;
    padding: clamp(2.2rem, 6vh, 3.6rem) 0 0; pointer-events: auto;
  }
  html.js .jr__c > *:not(canvas) { opacity: 1 !important; transform: none !important; }
  html.js .jr__key { clip-path: none !important; }
  html.js .jr__c { visibility: visible !important; }
  html.js .jr__c::before { display: none; }
  html.js .jr__rail { flex-wrap: wrap; gap: 1rem; margin-top: clamp(1.8rem, 4vh, 2.8rem); }
  html.js .jr__rail::before, html.js .jr__line { display: none; }
  html.js .jr__rail button { flex-direction: row; }
  html.js .jr__rail span { display: block; position: static; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; }
  html.js .jr.is-live .jr__cue i { animation: none; }
  html.js .svcs__more[open] > ul { animation: none; }
  .svcs__more::details-content { transition: none; }
}

/* A disclosure's contents settle in as it opens: the services' full scope
   and the contact page's answers. */
@keyframes faqIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

/* A light board on the dark page rather than a full-bleed light band: the
   same lift, roughly half the glare, and it reads as one object. */
/* Anything outside the board that must line up with what is inside it. */
.inset { padding-inline: clamp(1.4rem, 3vw, 2.6rem); }
@media (max-width: 560px) { .inset { padding-inline: 0; } }

/* ---------- Portfolio figures: they count up once, the first time you scroll
   to them. The number carries its own gradient so it can hold its final width
   while it counts, and the unit beside it never moves. */
.stat__v {
  display: inline-block;
  background: inherit; -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* ==========================================================================
   Palette steps. When the walk in chameleon.js repaints the page it sets this
   class for a single frame. Every colour on the page moves at once, and
   without it each hover transition on color, background or border started
   animating that tiny step: dozens of elements repainting for half a second,
   twice a second, for as long as you scroll. Measured on the services page it
   was ten times the paint work of the scroll itself. Only colour is dropped
   from the transitions; movement (reveals, the menu, the nav marker) carries on.
   ========================================================================== */
html.pal-step, html.pal-step *, html.pal-step *::before, html.pal-step *::after {
  transition-property: transform, opacity, visibility, clip-path, width, block-size,
                       grid-template-rows, grid-template-columns, background-size,
                       content-visibility !important;
}
