/* ============================================================
   Wealthdoor — main.css
   Palette derived from the Wealthdoor Brand Guidelines:
   #0013A0 brand blue · #F05A29 ember · #FFE3DA blush
   #686868 grey · #FFFFFF · #000000
   Modern extensions are tints/shades of the brand blue only.
   ============================================================ */

/* ---------- 1. Tokens ---------- */
:root {
  /* brand */
  --brand:        #0013A0;
  --brand-lift:   #2B45E8;
  --brand-glow:   #5E7BFF;
  --azure:        #9DB8FF;
  --ember:        #F05A29;
  --ember-soft:   #FF8154;
  --blush:        #FFE3DA;
  --grey:         #686868;

  /* surfaces */
  --ink:          #04061A;
  --navy-900:     #01062B;
  --navy-800:     #030C3F;
  --navy-700:     #071561;
  --paper:        #FFFFFF;
  --mist:         #F3F5FC;
  --mist-2:       #E7ECF9;

  /* semantic (set per section by [data-theme]) */
  --bg:           var(--navy-900);
  --fg:           #FFFFFF;
  --fg-soft:      rgba(255,255,255,.62);
  --fg-faint:     rgba(255,255,255,.34);
  --rule:         rgba(255,255,255,.13);
  --card:         rgba(255,255,255,.045);
  --card-edge:    rgba(255,255,255,.10);

  /* type */
  /* Three voices, one system, and each one is doing a different job:

     --display  Newsreader, an editorial serif with optical sizes. Headlines only.
                A firm that describes itself as a fiduciary standard should not
                sound like a product launch, and a grotesk at 5rem does. The serif
                is what separates this page from every other advisory site built
                on a single geometric sans.
     --sans     Instrument Sans. Body copy, controls, navigation, forms. Narrower
                and more textured than the usual UI grotesk, so a paragraph holds
                colour instead of going grey, and it sits under the serif without
                competing with it.
     --mono     IBM Plex Mono. Eyebrows, labels, figures, regulatory codes — the
                platform half of the brand. Warmer and less code-editor than the
                mono it replaces, which matters when it is set in caps at 11px. */
  --display: "Newsreader", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --sans: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* rhythm */
  --shell: 1280px;
  --gutter: clamp(1.25rem, 4vw, 3.5rem);
  --sec-y: clamp(5.5rem, 12vh, 10rem);
  --r-sm: 8px;
  --r-md: 14px;
  --r-lg: 22px;

  /* motion */
  --e-out: cubic-bezier(.16,1,.3,1);
  --e-io:  cubic-bezier(.65,0,.35,1);
  --t-fast: .28s;
  --t-mid: .6s;
  --t-slow: 1.05s;
}

[data-theme="light"] {
  --bg:        var(--paper);
  --fg:        #0A0E27;
  --fg-soft:   rgba(10,14,39,.62);
  --fg-faint:  rgba(10,14,39,.36);
  --rule:      rgba(10,14,39,.12);
  --card:      rgba(10,14,39,.022);
  --card-edge: rgba(10,14,39,.10);
}
[data-theme="dark"] {
  --bg:        var(--navy-900);
  --fg:        #FFFFFF;
  --fg-soft:   rgba(255,255,255,.62);
  --fg-faint:  rgba(255,255,255,.34);
  --rule:      rgba(255,255,255,.13);
  --card:      rgba(255,255,255,.045);
  --card-edge: rgba(255,255,255,.10);
}

/* ---------- 2. Reset & base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 92px;
}
body {
  margin: 0;
  background: var(--navy-900);
  color: #fff;
  font-family: var(--sans);
  font-size: clamp(1rem, .95rem + .18vw, 1.0625rem);
  line-height: 1.62;
  font-weight: 400;
  letter-spacing: -.005em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg, canvas, video { display: block; max-width: 100%; }
h1, h2, h3, h4 { margin: 0; font-weight: 700; letter-spacing: -.032em; line-height: 1.06; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }
ul, ol, dl, dd { margin: 0; padding: 0; }
li { list-style: none; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }

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

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

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: fixed; left: 1rem; top: -6rem; z-index: 999;
  background: var(--ember); color: #fff; padding: .7rem 1.1rem; border-radius: var(--r-sm);
  font-weight: 600; transition: top .25s var(--e-out);
}
.skip-link:focus { top: 1rem; }

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

/* ---------- 3. Shared type ---------- */
.eyebrow, .section-tag, .stage-caption, .reg__code {
  font-family: var(--mono);
  font-size: .705rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  font-weight: 500;
}
.eyebrow {
  display: inline-flex; align-items: center; gap: .7rem;
  color: var(--fg-soft); margin-bottom: clamp(1.4rem, 3vw, 2.2rem);
  line-height: 1.5;
}
.eyebrow__dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--ember);
  box-shadow: 0 0 0 0 rgba(240,90,41,.55);
  animation: pulse 2.8s var(--e-io) infinite;
}
@keyframes pulse {
  0%, 70%, 100% { box-shadow: 0 0 0 0 rgba(240,90,41,.5); }
  35% { box-shadow: 0 0 0 9px rgba(240,90,41,0); }
}
.section-tag {
  color: var(--fg-faint); margin-bottom: 1.35rem;
}
.section-title {
  font-size: clamp(1.9rem, 1.1rem + 3.1vw, 3.6rem);
  max-width: 19ch;
  font-weight: 700;
}
.section-head { margin-bottom: clamp(2.5rem, 6vw, 4.5rem); }
.section-head--split {
  display: flex; flex-wrap: wrap; gap: 2rem 3rem;
  align-items: flex-end; justify-content: space-between;
}
.section-head--split .section-title { max-width: 16ch; }
.stage-caption { color: var(--fg-faint); margin-top: 1rem; line-height: 1.6; }

/* ---------- 4. Buttons ---------- */
.btn {
  position: relative;
  display: inline-flex; align-items: center; gap: .7rem;
  padding: .72rem 1.4rem;
  border-radius: var(--r-sm);
  font-weight: 600; font-size: .95rem; letter-spacing: -.01em;
  isolation: isolate; overflow: hidden;
  transition: transform .45s var(--e-out);
  will-change: transform;
}

.btn--primary {
  background: var(--ember); color: #fff;
  box-shadow: 0 10px 34px -12px rgba(240,90,41,.75);
}
.btn--quiet {
  border: 1px solid var(--card-edge); color: var(--fg);
  background: var(--card);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.btn--ghost {
  border: 1px solid var(--card-edge); padding: .62rem 1.15rem; font-size: .88rem;
  color: var(--fg);
}
.btn--block { width: 100%; justify-content: center; margin-top: .4rem; }

.btn__icon svg {
  width: 15px; height: 15px; fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
  transition: transform .45s var(--e-out);
}
.btn:hover .btn__icon svg { transform: translateX(4px); }

.link-arrow {
  display: inline-flex; align-items: baseline; gap: .4rem;
  font-family: var(--mono); font-size: .82rem; letter-spacing: .02em;
  color: var(--fg); padding-bottom: .25rem;
  background-image: linear-gradient(var(--ember), var(--ember));
  background-size: 0% 1px; background-repeat: no-repeat; background-position: 0 100%;
  transition: background-size .5s var(--e-out), color .3s;
}
.link-arrow:hover { background-size: 100% 1px; color: var(--ember); }

/* ---------- 6. Header ---------- */
/* Frosted white at every scroll position, on both pages. The bar used to start
   invisible over the hero and only materialise once the page moved, which meant
   the links changed colour under the cursor and each page had to carry its own
   logo crossfade for the two grounds. One white plate removes both: the footage
   still reads through the blur, and the mark and the nav never move. */
.site-header {
  position: fixed; inset: 0 0 auto; z-index: 90;
  border-bottom: 1px solid rgba(10,14,39,.07);
  transition: transform .5s var(--e-out), border-color .45s;
}
/* The frost is a layer behind the bar's contents rather than a property of the
   bar itself, and that is load-bearing on mobile: the drawer is a child of this
   element and carries its own backdrop-filter, and a backdrop-filter nested
   inside another one renders the inner element's plate as good as transparent —
   the hero headline read straight through the open menu. Sitting on ::before,
   the glass is a sibling of the drawer instead of its ancestor. */
.site-header::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  /* The bar read grey at the top of the page because the glass was doing the
     obvious thing: a white tint at .74 over the opening frame of the hero, which
     is nearly black, averages to grey. Raising the tint fixed the colour and took
     the glass with it — an opaque plate is not glass.

     The fix is in the backdrop rather than the tint: lift what is behind the bar
     *before* the white lays over it, so the footage arrives light instead of
     black and the plate settles white while staying genuinely see-through.

     `brightness` alone cannot do that lifting. It multiplies, and multiplying
     near-black stays near-black — at 1.6 the opening frame of the hero came
     through at maybe 8% grey and the bar still read as a grey slab. `contrast`
     below 1 is the lever that works, because it pulls toward mid-grey rather
     than scaling: at .32 the darkest footage lands near 34% and the brightening
     then carries it the rest of the way, while highlights clip to white. The
     backdrop is compressed into a narrow band up at the light end — light
     enough for the tint to finish white, still varied enough that the corridor
     visibly moves and bends under the bar as the hero scrubs.

     Saturation is held well above 100% because flattening contrast flattens
     colour with it; without it the ember in the footage washes out to grey. */
  background: rgba(255,255,255,.63);
  backdrop-filter: blur(28px) saturate(180%) contrast(.32) brightness(1.95);
  -webkit-backdrop-filter: blur(28px) saturate(180%) contrast(.32) brightness(1.95);
  transition: background-color .45s, backdrop-filter .45s;
}
/* Scrolled, the tint goes up but the same lift stays — the page alternates paper
   and navy all the way down, and the navy sections grey the bar out just as the
   hero did. Lifting a white section costs nothing (white clips to white), so the
   same treatment holds for the whole page; only the tint changes. */
.site-header.is-solid::before {
  background: rgba(255,255,255,.78);
  backdrop-filter: blur(28px) saturate(170%) contrast(.32) brightness(1.9);
  -webkit-backdrop-filter: blur(28px) saturate(170%) contrast(.32) brightness(1.9);
}
/* If backdrop-filter is unavailable the bar has no plate at all, and white text
   in the footage would read straight through it. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header::before { background: rgba(255,255,255,.95); }
}
.site-header.is-solid { border-bottom-color: rgba(10,14,39,.1); }
.site-header.is-hidden { transform: translateY(-102%); }
.site-header__row {
  display: flex; align-items: center; gap: clamp(1rem, 3vw, 2.5rem);
  height: 74px;
}
.brand { display: inline-flex; align-items: center; margin-right: auto; }
.brand__logo { display: block; height: 46px; width: auto; }

.site-nav ul { display: flex; gap: clamp(1rem, 2.2vw, 2.1rem); }
.site-nav a {
  position: relative; font-size: .92rem; font-weight: 500;
  color: rgba(10,14,39,.62); padding: .4rem 0;
  transition: color .3s;
}
.site-nav a::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 1px; width: 100%;
  background: var(--ember); transform: scaleX(0); transform-origin: 100% 50%;
  transition: transform .5s var(--e-out);
}
.site-nav a:hover, .site-nav a.is-current, .site-nav a[aria-current="page"] { color: #0A0E27; }
.site-nav a:hover::after, .site-nav a.is-current::after { transform: scaleX(1); transform-origin: 0 50%; }

/* Filled rather than outlined — a hairline box on this header was very nearly
   invisible against the footage behind it. */
.site-header__cta {
  color: #fff;
  background: var(--ember);
  border-color: transparent;
  font-weight: 600;
  box-shadow: 0 8px 26px -12px rgba(240,90,41,.85);
}
.site-header__cta:hover { background: var(--ember-soft); }
/* The read-progress hairline that used to run along the bottom edge of the bar is
   gone. It was a second thing moving in the header on every scroll, and the hero
   already reports position with its own dots. */

.nav-toggle {
  display: none; width: 40px; height: 40px; border-radius: var(--r-sm);
  border: 1px solid rgba(10,14,39,.18);
  flex-direction: column; justify-content: center; align-items: center; gap: 5px;
}
.nav-toggle span {
  display: block; width: 18px; height: 2px; background: #0A0E27; border-radius: 1px;
  transition: transform .4s var(--e-out), opacity .3s;
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; transform: scaleX(0); }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ---------- 7. Reveals ---------- */
[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition: opacity .95s var(--e-out), transform .95s var(--e-out);
  transition-delay: var(--d, 0ms);
}
[data-reveal].is-in { opacity: 1; transform: none; }
.no-js [data-reveal] { opacity: 1; transform: none; }

/* Mask reveal: the wrapper is observed (its clipped child never intersects). */
.hero__title .line[data-reveal] {
  display: block; overflow: hidden; padding-bottom: .08em;
  opacity: 1; transform: none;
}
.hero__title .line__in {
  display: block;
  transform: translate3d(0, 106%, 0);
  transition: transform 1.2s var(--e-out);
  transition-delay: var(--d, 0ms);
}
.hero__title .line.is-in .line__in { transform: none; }

/* ---------- 8. HERO ---------- */
.hero {
  position: relative;
  /* Halved from 3600px: the pin was holding long enough that visitors dropped
     off before the page began. Four scenes now share the shorter distance. */
  height: calc(100svh + 1800px);
  background: var(--navy-900);
}
.hero__pin {
  position: sticky; top: 0;
  height: 100svh;
  overflow: hidden; isolation: isolate;
  display: flex; align-items: center;
  padding: 7rem 0 5rem;
}
.hero__canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  z-index: 0;
}
.hero__overlay {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    /* No scrim. A full-plate wash darkens the whole frame to solve a contrast
       problem that only exists behind the glyphs, and the footage is the reason
       this hero exists — it should not be dimmed to carry text. Separation is
       handled entirely in the type now: a tight shadow stack on the headline and
       the lede, which costs the image nothing.

       What is left is the seam. The section below is white, so the last band
       resolves to the navy the page uses everywhere else instead of cutting the
       photograph off at a hard line. It sits under the copy, not behind it. */
    linear-gradient(0deg, var(--navy-900) 0%, rgba(1,6,43,.5) 6%, transparent 17%);
}
.hero__grain {
  position: absolute; inset: 0; z-index: 2; pointer-events: none; opacity: .5;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/><feColorMatrix type='saturate' values='0'/></filter><rect width='140' height='140' filter='url(%23n)' opacity='.055'/></svg>");
}
.hero__content { position: relative; z-index: 3; }

/* Scroll-driven hero scenes. The footage is a corridor receding to a vanishing
   point, so text arrives along the same axis: each scene is dollied in from
   deep in that space and pushed back out past the viewer on the way out.
   Scroll drives --a (0…1) and --dir (1 arriving, -1 leaving); the z/scale/blur
   live on the scene, the per-line stagger on its children. */
.hero__scene { grid-area: 1 / 1; }
.hero__scene:not(.is-active) { pointer-events: none; }
.js .hero__content {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
  min-height: 60svh;
  perspective: 900px;
  perspective-origin: 62% 46%; /* the corridor's vanishing point in the plate */
  transform-style: preserve-3d;
}
.js .hero__scene[data-hero-scene]:not([data-hero-scene="0"]) { opacity: 0; }

.js .hero__scene > * {
  transform: translate3d(0, calc((1 - var(--a, 1)) * var(--dir, 1) * var(--stagger, 0) * 1px), 0);
}
.js .hero__scene > :nth-child(1) { --stagger: 16; }
.js .hero__scene > :nth-child(2) { --stagger: 30; }
.js .hero__scene > :nth-child(3) { --stagger: 44; }
.js .hero__scene > :nth-child(4) { --stagger: 58; }
.js .hero__scene > :nth-child(5) { --stagger: 72; }

.hero__scene-tag {
  display: flex; align-items: baseline; gap: .8rem;
  font-family: var(--mono); font-size: .68rem; font-weight: 500;
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--fg-soft);
  margin-bottom: clamp(1.1rem, 2.4vw, 1.7rem);
}
.hero__scene-num {
  color: var(--ember);
  padding-right: .8rem;
  border-right: 1px solid rgba(255,255,255,.18);
}
.hero__scene-title {
  font-size: clamp(1.7rem, .9rem + 3.5vw, 3.5rem);
  line-height: 1.08;
  letter-spacing: -.025em;
  max-width: 20ch;
  margin-bottom: clamp(1.4rem, 2.6vw, 2rem);
  text-wrap: balance;
}
/* Gradient and colour for both hero headline treatments are set together
   further down, next to .hero__title — see the note there. */
.hero__scene-title em { font-style: normal; }
.hero__scene-lede {
  max-width: 52ch;
  font-size: clamp(1rem, .95rem + .35vw, 1.13rem);
  line-height: 1.62;
}
.hero__scene-meta {
  display: flex; flex-wrap: wrap; gap: .55rem;
  list-style: none; margin: clamp(1.9rem, 3.4vw, 2.6rem) 0 0; padding: 0;
}
.hero__scene-meta li {
  font-family: var(--mono); font-size: .64rem;
  letter-spacing: .13em; text-transform: uppercase;
  color: var(--fg-soft);
  padding: .48rem .85rem;
  border: 1px solid rgba(255,255,255,.16);
  border-radius: 100px;
  background: rgba(1,6,43,.42);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}

.hero__progress {
  position: absolute; z-index: 4;
  left: clamp(1.25rem, 4vw, 3.25rem); bottom: 2.4rem;
  display: flex; gap: .55rem;
}
.hero__progress-dot {
  width: 22px; height: 2px;
  background: rgba(255,255,255,.2);
  transition: background .45s var(--e-io), width .45s var(--e-io);
}
.hero__progress-dot.is-active { background: var(--ember); width: 38px; }

.hero__title {
  font-size: clamp(1.9rem, 1rem + 4vw, 4rem);
  max-width: 17ch;
  margin-bottom: clamp(1.6rem, 3vw, 2.2rem);
}
/* The second half of a hero headline used to be a clipped gradient. It is flat
   white now, which means the whole headline reads as one voice against the
   footage instead of shifting hue across the line. */
.hero__title .line--muted,
.hero__scene-title em {
  color: #fff;
}
/* With no scrim, this is the only thing separating the copy from the footage, so
   it is built as a stack rather than one blur. The tight core is what actually
   does the work — it hugs the glyph and guarantees an edge on any plate. The
   wider layer only softens the transition, and it is the one that was reading as
   heavy: at .6 it was a visible cloud around every letter, which is the scrim
   problem again at a smaller scale. Both layers come down; the core stays tight
   enough to hold the edge, the halo drops to where you notice the separation
   without noticing the shadow. */
.hero__title, .hero__scene-title {
  text-shadow: 0 1px 2px rgba(1,6,43,.62), 0 2px 8px rgba(1,6,43,.28);
}
/* Body-size type needs more help than the display line does: the strokes are
   thin, and on mobile the frame is cropped to its brightest part so there is no
   dark ground anywhere behind it. So this stack stays three layers where the
   headline lost weight — but each layer is lighter, and the widest one is pulled
   in so it stops fogging the plate behind a paragraph of text. */
.hero__lede, .hero__scene-lede {
  color: #fff;
  text-shadow: 0 1px 2px rgba(1,6,43,.7), 0 1px 4px rgba(1,6,43,.42), 0 2px 9px rgba(1,6,43,.24);
}
.hero__scene-tag {
  text-shadow: 0 1px 2px rgba(1,6,43,.62), 0 1px 6px rgba(1,6,43,.3);
}
.hero__lede {
  max-width: 54ch;
  font-size: clamp(1rem, .95rem + .35vw, 1.16rem);
}
.hero__actions { display: flex; flex-wrap: wrap; gap: .85rem; margin-top: clamp(2rem, 4vw, 2.9rem); }

/* capability ticker strip (between hero and core-principle) */
.ticker-strip {
  position: relative; z-index: 4;
  background: var(--navy-900);
  border-top: 1px solid rgba(255,255,255,.07);
  border-bottom: 1px solid rgba(255,255,255,.07);
  padding-block: .85rem;
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
}
/* Two identical groups, no gap between them, and the animation runs to exactly
   -50%. That combination is what makes the loop continuous instead of snapping:
   -50% of the track is one whole group only when the two groups are the same
   width and nothing sits between them, so at the moment the animation restarts,
   group two is standing precisely where group one began. The spacing that would
   otherwise be a flex gap on the track lives inside each group instead — the gap
   between items, plus a padding-right that supplies the one after the last item —
   so the rhythm is even across the seam as well. */
.ticker-strip__track {
  display: flex;
  align-items: center;
  width: max-content;
  animation: ticker-scroll 34s linear infinite;
  white-space: nowrap;
  font-family: var(--mono);
  font-size: .62rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(255,255,255,.32);
}
.ticker-strip__group {
  display: flex;
  align-items: center;
  gap: 2rem;
  padding-right: 2rem;
  flex: none;
}
.ticker-strip__sep {
  color: rgba(240,90,41,.6);
  font-weight: 400;
  letter-spacing: 0;
}
@keyframes ticker-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
/* The strip is the one piece of ambient motion left on the page, so under a
   reduced-motion preference it holds still rather than running at .001ms — the
   global rule in section 19 would otherwise leave it parked mid-loop. */
@media (prefers-reduced-motion: reduce) {
  .ticker-strip__track { animation: none !important; transform: none !important; }
}

/* ---------- 9. CORE PRINCIPLE ---------- */
.principle {
  position: relative;
  /* Light section: the mission reads on paper. */
  background: linear-gradient(180deg, var(--paper) 0%, var(--mist) 48%, var(--paper) 100%);
  color: var(--fg);
}
/* Not pinned. The section scrolls past like everything else and the statement
   lights word by word as it travels through the viewport — holding the page
   still for a screen and a half to deliver one sentence made the scroll feel
   broken rather than deliberate. */
.principle__scrub { display: none; }
.principle__sticky {
  position: static; min-height: 0;
  display: block; padding: var(--sec-y) 0;
}
/* One column since the chart came out, and centred: with nothing in the right
   half the statement was hanging off the left edge of a full-width section. It
   is the only thing here now, so it sits in the middle of the space and the
   eyebrow and the note centre with it. */
.principle__grid {
  display: grid; gap: clamp(2.5rem, 6vw, 5rem);
  grid-template-columns: minmax(0, 1fr);
  align-items: center; width: 100%;
}
.principle__copy { text-align: center; }
.principle__statement {
  font-size: clamp(1.65rem, .9rem + 2.9vw, 3.2rem);
  font-weight: 600; line-height: 1.16; letter-spacing: -.03em;
  /* Wider than the two-column measure it inherited — centred, 20ch broke into a
     narrow stack in the middle of a lot of paper. */
  max-width: 24ch; margin-inline: auto;
  text-wrap: balance;
}
.principle__statement .w {
  display: inline-block;
  opacity: .2;
  filter: blur(2px);
  transform: translateY(.14em);
  transition: opacity .55s var(--e-out), filter .55s var(--e-out), transform .55s var(--e-out), color .55s;
}
.principle__statement .w.is-lit { opacity: 1; filter: none; transform: none; }
.principle__statement .em.is-lit { color: var(--ember); }
.principle__statement .mute.is-lit { color: var(--fg-faint); }

.principle__note {
  margin-top: clamp(1.8rem, 3.5vw, 2.6rem);
  margin-inline: auto;
  color: var(--fg-faint); font-size: .93rem; max-width: 56ch;
}

/* ---------- 12. PRACTICES ---------- */
.practices {
  background: var(--navy-900); color: #fff;
  padding-top: var(--sec-y);
  padding-bottom: clamp(5rem, 11vw, 9rem);
  position: relative;
}
.practices::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 60vh; pointer-events: none;
  background: radial-gradient(60% 100% at 20% 0%, rgba(43,69,232,.22), transparent 70%);
}
.practices__intro {
  position: relative; margin-bottom: clamp(2.5rem, 5vw, 4rem);
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
}
.practices__intro .section-title { max-width: 22ch; }

.practices__viewport {
  overflow: visible;
  width: 100%; max-width: var(--shell); margin-inline: auto; padding: 0 var(--gutter);
  display: grid; gap: clamp(2rem, 4vw, 4rem);
  grid-template-columns: minmax(0, .78fr) minmax(0, 1.22fr);
  align-items: start;
}
.practices__media {
  grid-column: 2;
  grid-row: 1;
  justify-self: end;
  width: 94%;
  /* Pushed out into the gutter so the stage sits closer to the edge than the
     copy does — the asymmetry is the point, and it was reading as centred. */
  margin-right: calc(var(--gutter) * -.55);
  position: sticky;
  top: 12svh;
  aspect-ratio: 4 / 3.1;
  max-height: 76svh;
  will-change: transform;
}
.practices__rail {
  grid-column: 1;
  grid-row: 1;
  display: grid;
  gap: clamp(9rem, 20vh, 16rem);
  padding-block-start: 0;
  padding-block-end: 6svh;
}
.practice {
  min-height: 55svh;
  display: flex;
  align-items: center;
}
.practice__title {
  font-size: clamp(1.9rem, 1.1rem + 3vw, 3.3rem); margin-bottom: 1rem;
}
.practice__title em { font-style: normal; color: var(--azure); font-weight: 500; display: block; font-size: .48em; letter-spacing: -.02em; margin-top: .4rem; }
/* The practice's proposition, sitting between the brand name and the detail. */
.practice__head {
  font-size: clamp(1.05rem, .98rem + .5vw, 1.3rem);
  font-weight: 500; line-height: 1.35; letter-spacing: -.015em;
  max-width: 26ch; margin: -.25rem 0 .9rem;
}
.practice__lede { color: var(--fg-soft); max-width: 44ch; }
/* The three-item bullet list that used to sit between the lede and the links is
   gone, so the gap it was carrying (1.7rem above the links) moves onto the links
   themselves — otherwise the domains sit straight on the last line of the lede. */
.practice__links { display: flex; flex-wrap: wrap; gap: 1.4rem; margin-top: 1.7rem; }

.practice__stage {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  overflow: hidden;
  border-radius: var(--r-lg);
  padding: clamp(1rem, 2vw, 1.6rem);
  background: linear-gradient(155deg, rgba(255,255,255,.07), rgba(255,255,255,.015));
  border: 1px solid var(--card-edge);
  box-shadow: 0 40px 90px -50px rgba(0,0,0,.9);
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  transform: translate3d(0, 5%, 0) scale(.96);
  transition: opacity 1s var(--e-io), transform 1.1s var(--e-io), visibility 0s linear 1s;
}
.practice__stage.is-active {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transform: none;
  transition: opacity 1s var(--e-io), transform 1.1s var(--e-io), visibility 0s linear 0s;
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
.practice__stage canvas {
  width: 100%; flex: 1 1 auto; min-height: 0; border-radius: var(--r-md);
}
.practice__stage .stage-caption { padding-inline: .3rem; flex: none; margin-top: .8rem; }

.map-legend { position: absolute; left: 1.5rem; bottom: 4.4rem; display: flex; gap: .5rem; }
.map-pin {
  display: inline-flex; align-items: center; gap: .45rem;
  font-family: var(--mono); font-size: .64rem; letter-spacing: .12em; text-transform: uppercase;
  padding: .38rem .7rem; border-radius: 100px;
  border: 1px solid var(--card-edge); background: rgba(1,6,43,.55);
  color: var(--fg-soft);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  transition: color .3s, border-color .3s;
}
.map-pin i { width: 6px; height: 6px; border-radius: 50%; background: var(--ember); }
.map-pin:hover, .map-pin.is-on { color: #fff; border-color: var(--ember); }

/* goal scene */
.goal { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.goal canvas { flex: 1 1 auto; min-height: 0; width: 100%; }
.goal__scrubber { flex: none; }
.goal__readout {
  /* wide enough that every milestone settles on two lines, so the plot below
     it can reserve a constant amount of headroom */
  position: absolute; left: 1.4rem; top: 1.2rem; max-width: min(34ch, 62%);
}
.goal__year {
  font-family: var(--mono); font-size: .68rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--ember); margin-bottom: .35rem;
}
.goal__milestone { font-size: .95rem; font-weight: 600; line-height: 1.4; min-height: 2.8em; }
.goal__scrubber { margin-top: 1rem; padding-inline: .3rem; }
.goal__scrubber input[type="range"] {
  width: 100%; -webkit-appearance: none; appearance: none; background: transparent; cursor: grab;
}
.goal__scrubber input[type="range"]:active { cursor: grabbing; }
.goal__scrubber input[type="range"]::-webkit-slider-runnable-track {
  height: 2px; background: rgba(255,255,255,.16); border-radius: 2px;
}
.goal__scrubber input[type="range"]::-moz-range-track {
  height: 2px; background: rgba(255,255,255,.16); border-radius: 2px;
}
.goal__scrubber input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 16px; height: 16px; margin-top: -7px; border-radius: 50%;
  background: var(--ember); border: 3px solid var(--navy-900);
  box-shadow: 0 0 0 1px var(--ember), 0 0 18px rgba(240,90,41,.7);
  transition: transform .3s var(--e-out);
}
.goal__scrubber input[type="range"]::-moz-range-thumb {
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--ember); border: 3px solid var(--navy-900);
  box-shadow: 0 0 0 1px var(--ember);
}
.goal__scrubber input[type="range"]:hover::-webkit-slider-thumb { transform: scale(1.18); }
.goal__ticks {
  display: flex; justify-content: space-between; margin-top: .5rem;
  font-family: var(--mono); font-size: .6rem; letter-spacing: .12em; color: var(--fg-faint);
}

/* architecture scene */
.arch-key {
  display: flex; flex-wrap: wrap; gap: .4rem; margin-top: 1rem; padding-inline: .3rem;
  flex: none;
}
.arch-key button {
  font-family: var(--mono); font-size: .62rem; letter-spacing: .1em; text-transform: uppercase;
  padding: .34rem .66rem; border-radius: 100px;
  border: 1px solid var(--card-edge); color: var(--fg-faint);
  transition: color .3s, border-color .3s, background-color .3s;
}
.arch-key button:hover, .arch-key button.is-on {
  color: #fff; border-color: var(--brand-glow); background: rgba(94,123,255,.14);
}

/* ---------- 13. WHO WE ARE (stack) ----------
   Not pinned. Three and a half screens of scroll bought nothing here: the copy
   never changed, so all the hold did was freeze the page while five cards
   arrived one at a time. The section now scrolls like everything else and the
   cards land as it travels through the viewport — same assembly, but the page
   keeps moving under it, so the arrival reads as a consequence of scrolling
   rather than a toll charged for it. */
.stack {
  background: var(--mist); color: var(--fg);
  position: relative; z-index: 2;
  padding: var(--sec-y) 0;
}
.stack__sticky {
  position: static; height: auto; display: block;
}
.stack__grid {
  display: grid; gap: clamp(2rem, 5vw, 4.5rem);
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  align-items: center; width: 100%;
}
.stack__lede { color: var(--fg-soft); margin-top: 1.2rem; max-width: 40ch; }
.stack__layers { position: relative; display: grid; gap: .7rem; }
.slab {
  position: relative;
  padding: clamp(1rem, 2.2vw, 1.5rem) clamp(1.1rem, 2.4vw, 1.7rem);
  border-radius: var(--r-md);
  background: #fff;
  border: 1px solid rgba(10,14,39,.08);
  box-shadow: 0 24px 60px -44px rgba(1,6,43,.55);
  display: grid; gap: .2rem;
  opacity: 0;
  transform: translate3d(0, 46px, 0) scale(.97);
  transition: opacity .7s var(--e-out), transform .7s var(--e-out), box-shadow .5s, border-color .5s;
}
.slab.is-set { opacity: 1; transform: none; }
.slab h3 { font-size: clamp(1.05rem, .9rem + .6vw, 1.35rem); }
.slab p { color: var(--fg-soft); font-size: .92rem; margin-top: .25rem; }
.slab--crown {
  background: linear-gradient(122deg, var(--brand) 0%, var(--brand-lift) 62%, var(--ember) 132%);
  border-color: transparent; color: #fff;
  box-shadow: 0 34px 70px -40px rgba(0,19,160,.8);
}
.slab--crown p { color: rgba(255,255,255,.78); }

/* ---------- 14. REGULATORY ---------- */
.reg {
  background: var(--navy-900); color: #fff; padding: var(--sec-y) 0;
  position: relative;
}
.reg::before {
  content: ""; position: absolute; inset: auto 0 -30% 0; height: 70vh; pointer-events: none;
  background: radial-gradient(50% 100% at 78% 100%, rgba(240,90,41,.16), transparent 70%);
}
.reg__intro { position: relative; margin-bottom: clamp(.4rem, 1vw, .9rem); }

/* Not pinned either. The globe and the jurisdiction card are one widget with the
   note underneath them — holding the page still to swap SEC for SEBI separated
   the widget from the very paragraph that explains why it is there. The track is
   now just the widget's own height, and the crossfade is driven by how far the
   section has travelled through the viewport, so the whole section — globe,
   card, and the note below — moves together as one scroll. */
.reg__track { position: relative; }
.reg__sticky {
  position: static;
  padding: clamp(2rem, 5vh, 3.5rem) 0;
  display: block;
}
.reg__viewport {
  width: 100%; max-width: var(--shell); margin-inline: auto; padding: 0 var(--gutter);
  display: grid; gap: clamp(2rem, 4vw, 4rem);
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
  align-items: center;
}
/* Globe and panel both come down about a tenth. They were sized for a full
   screen of pin; on a shorter track they only have to sit under the headline. */
.reg__globe {
  grid-column: 1;
  width: 90%; margin-inline: auto;
  display: flex; align-items: center;
  will-change: transform;
}
.reg__globe canvas { width: 100%; height: auto; aspect-ratio: 1 / 1; }
/* Both panels share one grid cell, so the card is exactly as tall as whichever
   country's facts are longest — no reserved empty space underneath. */
.reg__panels {
  grid-column: 2;
  display: grid;
  align-items: start;
}
.reg__panel {
  grid-area: 1 / 1;
  width: 100%;
  padding: clamp(1.35rem, 2.7vw, 2.15rem);
  border-radius: var(--r-lg);
  background: linear-gradient(155deg, rgba(255,255,255,.075), rgba(255,255,255,.02));
  border: 1px solid var(--card-edge);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translate3d(0, 4%, 0) scale(.97);
  transition: opacity .7s var(--e-io), transform .8s var(--e-io), border-color .6s var(--e-io), visibility 0s linear .7s;
}
.reg__panel.is-active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  border-color: rgba(94,123,255,.45);
  transform: none;
  transition: opacity .7s var(--e-io), transform .8s var(--e-io), border-color .6s var(--e-io), visibility 0s linear 0s;
}
.reg__flagline {
  display: flex; align-items: center; gap: .7rem;
  font-size: .92rem; color: var(--fg-soft); margin-bottom: 1.2rem;
}
.reg__code {
  padding: .22rem .5rem; border-radius: 5px;
  background: rgba(255,255,255,.09); color: #fff; letter-spacing: .12em;
}
.reg__reg {
  font-size: clamp(2.35rem, 1.45rem + 3.6vw, 4.15rem); letter-spacing: -.055em; line-height: .9;
  background: linear-gradient(130deg, #fff 12%, var(--azure) 62%, var(--ember-soft) 118%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.reg__status {
  font-size: 1.05rem; font-weight: 600; margin-top: .7rem; color: #fff;
}
.reg__facts { display: grid; gap: .85rem; margin-top: 1.8rem; padding-top: 1.4rem; border-top: 1px solid var(--rule); }
.reg__facts > div { display: grid; grid-template-columns: minmax(0,.5fr) minmax(0,1fr); gap: 1rem; align-items: baseline; }
.reg__facts dt {
  font-family: var(--mono); font-size: .64rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--fg-faint);
}
.reg__facts dd { font-size: .95rem; font-weight: 500; }

/* Reads as the closing line of the panel above it, not a section of its own:
   it picks up the panel's edge and glass, and sits close enough underneath to
   belong to it. */
.reg__banner {
  position: relative;
  margin-top: clamp(1rem, 2.2vw, 1.8rem);
  padding: clamp(1.35rem, 2.7vw, 2rem) clamp(1.35rem, 2.7vw, 2.3rem);
  border-radius: var(--r-lg);
  border: 1px solid var(--card-edge);
  background: linear-gradient(155deg, rgba(255,255,255,.075), rgba(255,255,255,.02));
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  font-size: clamp(.98rem, .93rem + .35vw, 1.12rem); color: var(--fg-soft); max-width: 74ch;
}
.reg__banner-tag {
  display: block; font-family: var(--mono); font-size: .68rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--ember); margin-bottom: .7rem;
}

/* ---------- 15. CAREERS (homepage teaser) ----------
   Headline, paragraph, one CTA into careers.html. No panel beside it: the section
   exists to hand the visitor to the careers page, not to answer them here. */
.careers {
  position: relative;
  background: var(--bg);
  color: var(--fg);
  padding: var(--sec-y) 0;
  border-top: 1px solid var(--rule);
}
.careers__grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .88fr);
  gap: clamp(2rem, 5vw, 4.5rem); align-items: center;
}
.careers__copy { max-width: 46rem; }
/* Set like every other section lede — Who we are, Contact, the practice cards —
   which means no type scale of its own. It used to run a size larger and a good
   deal wider than any of them, and next to the plate that read as a different
   page rather than emphasis. Colour and measure are the only things a lede
   changes here; the size comes from the body. */
.careers__lede {
  margin-top: 1.2rem; max-width: 40ch;
  color: var(--fg-soft);
}
.careers__cta { margin-top: clamp(1.8rem, 3.5vw, 2.4rem); }
.careers__art { position: relative; margin: 0; }

/* The doorway plate. A dark panel on a paper section, which is the one place on
   the homepage that inversion happens — it is doing the job the photograph used
   to do, so it has to hold the right half of the section on its own. */
.careers-plate {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  border-radius: var(--r-lg);
  padding: clamp(1.9rem, 3.4vw, 3.1rem);
  min-height: clamp(20rem, 34vw, 27rem);
  display: flex;
  align-items: center;
  background:
    radial-gradient(115% 85% at 86% 12%, rgba(240,90,41,.16), transparent 62%),
    linear-gradient(158deg, var(--navy-800) 0%, var(--navy-900) 66%);
  box-shadow: 0 44px 100px -55px rgba(1,6,43,.8);
}
/* Anchored bottom-right and allowed to bleed off both of those edges: a doorway
   that fits neatly inside a box reads as an icon, and one that runs out of the
   frame reads as architecture. */
.careers-plate__door {
  position: absolute;
  right: -13%; bottom: 0;
  width: 72%; height: 100%;
  z-index: -1;
  pointer-events: none;
}
/* On a phone the figures wrap to two lines and reach much further across the
   plate than they do beside a 580px column, so the doorway has to give ground.
   Pushing it further off the right edge keeps the same slice of architecture —
   jamb and glow — without the labels running into the lit part of it. */
@media (max-width: 720px) {
  .careers-plate__door { right: -34%; width: 66%; }
}

.careers-figs {
  display: grid;
  gap: clamp(1.3rem, 2.4vw, 1.9rem);
  position: relative;
}
/* column-reverse, so the numeral leads visually while the DOM keeps label before
   value — a screen reader reads "Advisory practices under one standard, 3", which
   is the sentence, where the reverse would be a bare number with no subject. */
.careers-fig {
  display: flex;
  flex-direction: column-reverse;
  gap: .3rem;
  padding-left: 1.05rem;
  border-left: 2px solid var(--ember);
}
.careers-fig dd {
  font-family: var(--display);
  font-weight: 600;
  /* Proportional figures, not tabular: these are three standalone numerals, not a
     column that has to line up, and tabular widths make a single digit sit loose
     in its own box at this size. */
  font-size: clamp(2rem, 1.1rem + 2.6vw, 3.1rem);
  line-height: 1;
  letter-spacing: -.012em;
  font-optical-sizing: auto;
  color: #fff;
}
.careers-fig dt {
  font-size: .82rem;
  line-height: 1.45;
  color: rgba(255,255,255,.62);
  max-width: 26ch;
}

/* ---------- 15b. CAREERS PAGE (careers.html) ----------
   Four movements: the invitation, what we hire for, where the work sits, and the
   waitlist. There are no roles to list, so the page's job is to get an interested
   person into the Talent Network — every section leads there. Tokens are borrowed
   wholesale from the parent site; a sub-page should not invent a palette. */
.page-careers { background: var(--paper); color: #0A0E27; }

/* The header used to need a whole per-page treatment here — two logos, inverted
   nav colours, its own solid-state opacity — because the bar changed ground
   halfway down this page. It is one white plate on both pages now, so all of it
   is gone and the header section above is the only place it is described. */

/* --- Hero ---
   The only dark band above the fold. Everything from the traits down is white,
   so the navy reads as the page's masthead rather than its ground, and it hands
   off to the white section through its own bottom edge instead of a hard seam. */
.crn-open {
  position: relative;
  /* Still painted, and still the right colour: it is what shows while the photo
     decodes, and what shows if it never arrives. */
  background:
    radial-gradient(120% 100% at 8% 0%, rgba(0,19,160,.55) 0%, transparent 62%),
    linear-gradient(180deg, var(--navy-900) 0%, var(--navy-900) 74%, #0A1140 100%);
  color: #fff;
  padding: calc(74px + var(--sec-y)) 0 var(--sec-y);
  min-height: 88svh;
  display: flex; align-items: center;
}
/* The corridor from the homepage sequence, held as a still. The frame is already
   composed the way this section needs it — the whole left half is wall, and the
   light is a narrow band well right of centre — so the copy sits on dark ground
   without anything being dimmed to put it there. */
.crn-open__media { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.crn-open__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* Anchored right of centre so the doorway and the walking figure survive the
     crop instead of the empty wall on the far left. */
  object-position: 64% 50%;
}
/* Two directional passes, no flat plate. The first deepens the wall the headline
   crosses and is fully clear before it reaches the doorway, so the light keeps
   its full intensity. The second only handles the two edges the section has to
   hand off at: the header floating over the top, and the white traits section
   below, which the photo would otherwise meet at a cut. */
.crn-open__media::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(96deg, rgba(1,6,43,.88) 0%, rgba(1,6,43,.66) 30%, rgba(1,6,43,.16) 58%, transparent 76%),
    linear-gradient(180deg, rgba(1,6,43,.7) 0%, transparent 22%, transparent 64%, #0A1140 100%);
}
/* Full shell width, so the copy starts on the same gutter as every other section
   on the page. At 62rem the block was narrower than the shell and centred inside
   it, which pushed the headline about 145px right of where the traits and roles
   below it begin — it read as floating in the middle rather than set against the
   left edge. The lines are still short; the title and lede hold their own
   measures. */
.crn-open__inner { position: relative; z-index: 1; width: 100%; }
.crn-open__title {
  font-size: clamp(2.5rem, 1.3rem + 5.2vw, 5.2rem);
  line-height: 1.02; letter-spacing: -.04em;
  max-width: 15ch;
}
.crn-open__lede {
  margin-top: clamp(1.4rem, 3vw, 2rem); max-width: 58ch;
  color: var(--fg-soft);
  font-size: clamp(1.05rem, .98rem + .5vw, 1.28rem); line-height: 1.6;
}
.crn-open__actions {
  display: flex; flex-wrap: wrap; gap: .9rem;
  margin-top: clamp(1.9rem, 4vw, 2.8rem);
}

/* --- Who we are looking for --- */
/* --- Icon system -----------------------------------------------------------
   Every icon on this page sits in a doorway: round head, square feet, with the
   ember sweep from the mark arcing over it. The frame is what makes the set
   ours and it never changes, so the drawing inside can stay simple enough to
   read at 24px instead of carrying the styling on its own. One box, one scale
   variable, used by the traits and by the departments below them. */
.wd-glyph {
  --gh: 3.6rem;
  position: relative; flex: none;
  display: inline-flex; align-items: flex-end; justify-content: center;
  width: calc(var(--gh) * .86); height: var(--gh);
  padding-bottom: calc(var(--gh) * .18);
  border: 1px solid var(--card-edge);
  border-radius: calc(var(--gh) * .43) calc(var(--gh) * .43) calc(var(--gh) * .14) calc(var(--gh) * .14);
  background: var(--paper);
  color: var(--brand);
  transition: color .4s var(--e-out), border-color .4s var(--e-out);
}
/* The sweep over the arch head. */
.wd-glyph::before {
  content: ""; position: absolute;
  left: 13%; right: 13%; top: calc(var(--gh) * .09); height: calc(var(--gh) * .31);
  border: 1.5px solid var(--ember); border-bottom: 0;
  border-radius: 999px 999px 0 0;
  opacity: .5;
  transition: opacity .4s var(--e-out);
}
.wd-glyph svg {
  display: block;
  width: calc(var(--gh) * .42); height: calc(var(--gh) * .42);
}

.crn-traits { background: var(--paper); color: var(--fg); padding: var(--sec-y) 0; }
.crn-traits__grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(1.4rem, 3vw, 2.4rem);
}
/* Four peers with no ranking between them, so four identical cards and no numbers.
   On a page that is now white throughout, the card is what separates one trait
   from the next — the hairline alone had nothing to hold. */
.crn-trait {
  display: flex; flex-direction: column;
  padding: clamp(1.4rem, 2.4vw, 1.8rem);
  border: 1px solid var(--card-edge); border-radius: var(--r-lg);
  background: var(--mist);
  transition: border-color .4s var(--e-out), background-color .4s var(--e-out),
              transform .5s var(--e-out);
}
.crn-trait:hover {
  border-color: rgba(240,90,41,.4);
  background: var(--paper);
  transform: translateY(-3px);
}
.crn-trait .wd-glyph { margin-bottom: 1.3rem; }
.crn-trait:hover .wd-glyph {
  color: var(--ember);
  border-color: rgba(240,90,41,.32);
}
.crn-trait:hover .wd-glyph::before { opacity: 1; }
.crn-trait__title {
  font-size: clamp(1.08rem, 1rem + .45vw, 1.32rem);
  letter-spacing: -.02em; margin-bottom: .6rem;
  text-wrap: balance;
}
.crn-trait__desc { color: var(--fg-soft); font-size: .95rem; line-height: 1.6; }

/* --- Where you can make an impact ---
   Five departments, each a name paired with one line of focus. Kept as rows
   rather than cards because the pairing is the content; the doorway glyph gives
   each row something to be recognised by. */
.crn-impact { background: var(--paper); color: var(--fg); padding: var(--sec-y) 0; }
.crn-depts { display: grid; }
.crn-dept {
  display: grid;
  grid-template-columns: auto minmax(0, .4fr) minmax(0, 1fr);
  gap: clamp(1.1rem, 2.6vw, 2rem);
  align-items: center;
  padding: clamp(1rem, 2vw, 1.35rem) clamp(.6rem, 1.4vw, 1rem);
  border-bottom: 1px solid var(--rule);
  border-radius: var(--r-md);
  transition: background-color .35s var(--e-out);
}
.crn-dept:first-child { border-top: 1px solid var(--rule); }
.crn-dept:hover { background: rgba(10,14,39,.035); }
.crn-dept:hover .wd-glyph { color: var(--ember); border-color: rgba(240,90,41,.32); }
.crn-dept:hover .wd-glyph::before { opacity: 1; }
.crn-dept .wd-glyph { --gh: 3.15rem; }
.crn-dept__name {
  font-size: clamp(1.05rem, .98rem + .45vw, 1.3rem);
  font-weight: 600; letter-spacing: -.02em; text-wrap: balance;
}
.crn-dept__focus { color: var(--fg-soft); line-height: 1.55; }

/* --- Open roles + Talent Network --- */
.crn-roles { background: var(--paper); color: var(--fg); padding: var(--sec-y) 0; }
.crn-roles__grid {
  display: grid; gap: clamp(2.5rem, 6vw, 4.5rem);
  grid-template-columns: minmax(0, 1fr) minmax(0, .9fr);
  align-items: start;
}
/* Sits where it lands. It was sticky, so the heading tracked the page while the
   form scrolled past it — with only one short form beside it there is nothing to
   track, and the pairing reads better as one block that moves together. */
.crn-roles__intro { position: static; }
.crn-roles__intro .section-title { max-width: 14ch; }
.crn-roles__lede {
  margin-top: 1.4rem; max-width: 44ch;
  color: var(--fg-soft); line-height: 1.62;
  font-size: clamp(1.02rem, .96rem + .4vw, 1.15rem);
}
/* Two classes deep on purpose: the base .form is a glass panel built for the
   photograph behind the contact block, and translucent white over a white section
   is nothing at all. Here it needs a real fill and a real edge. */
.form.crn-form {
  padding: clamp(1.6rem, 3vw, 2.4rem);
  border: 1px solid var(--card-edge); border-radius: var(--r-lg);
  background: var(--mist);
  backdrop-filter: none; -webkit-backdrop-filter: none;
}

/* ---------- 16. CONTACT ---------- */
/* The hills sit under the whole section, but the wash is deliberately lopsided:
   near-opaque across the left column so the headline, lede and practice list keep
   a flat ground to sit on, then falling away past the middle so the photograph
   actually reads on the side where the glass form is. Held at .93 the picture was
   technically loaded and visually absent; the drop-off is what makes it a
   background rather than a rumour. */
.contact {
  background:
    linear-gradient(100deg,
      rgba(255,255,255,.9) 0%,
      rgba(255,255,255,.84) 34%,
      rgba(255,255,255,.44) 62%,
      rgba(255,255,255,.24) 100%),
    url("../img/contact-hills-arc.webp") center 60% / cover no-repeat,
    var(--paper);
  color: var(--fg); padding: var(--sec-y) 0;
  position: relative; z-index: 2;
}
.contact__grid {
  display: grid; gap: clamp(2.5rem, 6vw, 5rem);
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
  align-items: start;
}
.contact__lede { color: var(--fg-soft); margin-top: 1.2rem; max-width: 38ch; }
.contact__routes { display: grid; gap: .9rem; margin-top: 2.4rem; padding-top: 1.6rem; border-top: 1px solid var(--rule); }
.contact__routes li { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: 1rem; align-items: baseline; }
.contact__routes span {
  font-family: var(--mono); font-size: .66rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--fg-faint);
}
.contact__routes b { font-weight: 600; font-size: .96rem; }

.form {
  display: grid; gap: 1rem;
  position: relative; overflow: hidden;
  background: rgba(255,255,255,.32);
  border: 1px solid rgba(255,255,255,.55);
  border-radius: var(--r-lg);
  padding: clamp(1.4rem, 2.6vw, 2rem);
  box-shadow: 0 40px 90px -60px rgba(1,6,43,.35);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
}
.form::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--brand) 10%, var(--brand-lift) 55%, var(--ember) 105%);
  opacity: .85;
}
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.field { position: relative; }
.field label {
  display: block;
  font-family: var(--mono); font-size: .63rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--brand); margin-bottom: .5rem;
  transition: color .3s;
}
.field:has(input:focus) label,
.field:has(textarea:focus) label,
.field:has(select:focus) label { color: var(--ember); }
.field:has(input:placeholder-shown:not(:focus)) label,
.field:has(textarea:placeholder-shown:not(:focus)) label {
  transform: none; color: var(--fg-faint);
  letter-spacing: .14em; text-transform: uppercase; font-size: .63rem;
}
.field input, .field textarea, .field select {
  width: 100%;
  background: rgba(255,255,255,.45);
  border: 1px solid rgba(0,19,160,.14);
  border-radius: var(--r-sm);
  padding: .72rem .95rem;
  color: var(--fg);
  transition: border-color .3s, background .3s;
}
.field input::placeholder, .field textarea::placeholder {
  color: var(--fg-faint);
}
.field textarea { resize: vertical; min-height: 3.4rem; }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none;
  border-color: var(--brand);
  background: rgba(255,255,255,.7);
}
.field input:focus-visible, .field textarea:focus-visible, .field select:focus-visible {
  outline: 2px solid var(--ember); outline-offset: 2px;
}
.field--select select {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23686868' stroke-width='1.6' stroke-linecap='round'><path d='M4 6.5 8 10.5 12 6.5'/></svg>");
  background-repeat: no-repeat; background-position: right .75rem center; background-size: 16px;
  padding-right: 2.2rem;
}
.field--select select option { background: #fff; color: var(--fg); }
/* One line, always. A two-line error reflowed the whole form as you tabbed
   through it; the messages are written short enough to fit, and anything that
   somehow doesn't is truncated rather than allowed to wrap. */
.field__error {
  font-size: .78rem; color: #C4361B; margin-top: 0;
  white-space: nowrap; text-overflow: ellipsis;
  max-height: 0; opacity: 0; overflow: hidden;
  transition: max-height .3s var(--e-out), opacity .3s, margin-top .3s var(--e-out);
}
.field.is-invalid .field__error { max-height: 1.4rem; margin-top: .35rem; opacity: 1; }
.field.is-invalid input, .field.is-invalid textarea, .field.is-invalid select { border-color: #C4361B; }
.field.is-valid input, .field.is-valid textarea, .field.is-valid select { border-color: rgba(0,19,160,.45); }

/* One step darker than the other captions on the page: this one sits on glass
   over a photograph rather than on flat paper, and at --fg-faint it disappeared
   into the grass on the phone layout. */
.form__note { font-size: .8rem; color: var(--fg-soft); line-height: 1.55; }
.form__status {
  font-size: .92rem; font-weight: 600; color: var(--brand);
  max-height: 0; opacity: 0; overflow: hidden;
  transition: max-height .5s var(--e-out), opacity .4s;
}
.form__status.is-shown { max-height: 6rem; opacity: 1; }
.form.is-sent .field, .form.is-sent .btn { opacity: .45; pointer-events: none; }

/* ---------- 17. FOOTER ----------
   The same frosted white as the header, closing the page the way the bar opens
   it. The photograph stays — it is what there is to frost — but it now sits
   under white instead of under navy, so the footer reads as the page's own
   surface rather than a second dark band after the contact section. */
.site-footer {
  background: url('../img/footer-desert.png') center top / cover no-repeat, var(--paper);
  color: var(--fg); padding: clamp(3.5rem, 8vw, 6rem) 0 2.5rem;
  position: relative; z-index: 2;
  isolation: isolate;
  /* Light theme, but on frosted glass over a photograph rather than flat paper —
     the desert's own tonal variation eats contrast the other light sections
     don't have to fight. Lift both ink tiers a step (and the rules with them)
     while keeping the heading/link separation intact. Must stay in sync with
     [data-theme="light"]: this rule is later in the file at equal specificity,
     so whatever it declares wins for the footer. */
  --fg-soft:  rgba(10,14,39,.82);
  --fg-faint: rgba(10,14,39,.58);
  --rule:     rgba(10,14,39,.18);
}
/* The glass has to be its own layer rather than a wash on the section itself:
   backdrop-filter blurs what is painted *behind* the element, so putting it on
   .site-footer would frost the contact section above it and leave this photo
   perfectly sharp. On a child, the parent's own background is the backdrop. */
.site-footer::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  /* Weighted toward the top rather than away from it: blurred to this radius the
     desert's overcast sky is just a flat grey, and at .74 it dragged the head of
     the footer grey too. Higher white there keeps the glass reading as white,
     and the warmth further down — which is the sand — is the part worth showing. */
  background: linear-gradient(180deg, rgba(255,255,255,.88) 0%, rgba(255,255,255,.86) 46%, rgba(255,255,255,.92) 100%);
  backdrop-filter: blur(28px) saturate(140%);
  -webkit-backdrop-filter: blur(28px) saturate(140%);
}
.site-footer__top {
  display: flex; flex-wrap: wrap; gap: 1.5rem 3rem; align-items: center;
  justify-content: space-between;
  padding-bottom: clamp(2rem, 5vw, 3.5rem); border-bottom: 1px solid var(--rule);
}
.brand--footer .brand__logo { height: 40px; }
.site-footer__line { color: var(--fg-soft); max-width: 40ch; }
.site-footer__nav {
  display: grid; gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  padding: clamp(2.2rem, 5vw, 3.5rem) 0;
}
.site-footer__nav h2 {
  font-family: var(--mono); font-size: .66rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--fg-faint); margin-bottom: 1rem; font-weight: 500;
}
.site-footer__nav ul { display: grid; gap: .55rem; }
.site-footer__nav a {
  font-size: .93rem; color: var(--fg-soft);
  transition: color .3s, transform .4s var(--e-out);
  display: inline-block;
}
.site-footer__nav a:hover { color: var(--fg); transform: translateX(4px); }
.site-footer__legal {
  display: grid; gap: .6rem; padding-top: 1.8rem; border-top: 1px solid var(--rule);
  font-size: .78rem; color: var(--fg-faint); max-width: 78ch;
}

/* ---------- 18. Responsive ---------- */
@media (max-width: 1080px) {
  .stack__grid, .reg__viewport, .contact__grid, .practices__viewport,
  .careers__grid, .crn-roles__grid {
    grid-template-columns: minmax(0, 1fr);
  }
  /* Stacked, the careers plate would run the full shell and outweigh the copy it
     is meant to accompany — hold it to a readable size and centre it instead.
     width:100% is load-bearing: margin-inline:auto cancels the grid item's
     default stretch, and without it the figure shrinks to max-content. */
  .careers__art { width: 100%; max-width: 30rem; margin-inline: auto; }
  /* Stacked, the hero no longer needs to hold the viewport. */
  .crn-open { min-height: 0; display: block; }
  /* One column crops the frame to a slice, so there is no dark left half to sit
     the copy on any more. The scrim turns vertical to match: dark under the
     text, clearing toward the bottom where the doorway is. */
  /* A portrait crop of a 16:9 frame only keeps about a fifth of its width, so the
     anchor has to sit on the doorway itself — at the desktop value the slit fell
     just off the right edge and all that survived was lit wall. */
  .crn-open__media img { object-position: 72% 50%; }
  .crn-open__media::after {
    background: linear-gradient(180deg, rgba(1,6,43,.86) 0%, rgba(1,6,43,.78) 52%, rgba(1,6,43,.36) 78%, #0A1140 100%);
  }
  .crn-traits__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* One column, so the copy no longer occupies the left half — a sideways wash
     would clear exactly where the practice list now runs. It turns vertical:
     opaque over the copy at the top, opening up underneath where the form's own
     glass is the thing holding the text off the picture. */
  .contact {
    background:
      linear-gradient(180deg,
        rgba(255,255,255,.92) 0%,
        rgba(255,255,255,.88) 38%,
        rgba(255,255,255,.55) 70%,
        rgba(255,255,255,.4) 100%),
      url("../img/contact-hills-arc.webp") center 60% / cover no-repeat,
      var(--paper);
  }
  .reg__globe, .reg__panels, .practices__media, .practices__rail {
    grid-column: 1;
  }
  .reg__globe { max-width: 420px; margin-inline: auto; }
  /* The rightward shift is a two-column gesture — it reads as the stage sitting
     nearer the edge than the copy. In one column there is nothing to sit nearer
     than, so it comes back to the gutter. */
  .practices__media { grid-column: 1; grid-row: auto; justify-self: stretch; width: 100%; margin-right: 0; position: relative; top: auto; max-height: none; }
  .practices__rail { grid-column: 1; grid-row: auto; gap: 2.5rem; padding-block: 1.5rem 2rem; }
  .practice { min-height: auto; display: block; }
  /* Inlined stages are always on. The base rule hides every stage that is not
     .is-active, which left Nestvest's and the Platform's canvases invisible
     here even though they had been moved into place. */
  .practice__stage.is-mobile-inline {
    position: relative; inset: auto;
    opacity: 1 !important;
    visibility: visible !important;
    pointer-events: auto;
    transform: none !important;
    transition: none;
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    /* Height comes from the contents, not a ratio. Each stage carries a different
       amount of chrome — the Goal Door alone has a readout, a scrubber and a tick
       row — and a fixed ratio left its chart squeezed into 73px. */
    aspect-ratio: auto; min-height: 21rem;
    border-radius: var(--r-lg);
    overflow: hidden; margin-bottom: 1.5rem; display: flex;
  }
  .practice__stage.is-mobile-inline canvas { min-height: 11.5rem; }
}

@media (max-width: 900px) {
  html { scroll-padding-top: 76px; }
  .site-header__row { height: 64px; }
  /* 46px of mark in a 64px bar left 9px of air above and below and pushed the
     wordmark right up against the Contact button. */
  .brand__logo { height: 36px; }
  .nav-toggle { display: flex; }
  /* Contact stays in the bar next to the toggle — it is the one action on the
     page, and burying it in the drawer costs a tap. */
  .site-header__cta { padding: .5rem .9rem; font-size: .82rem; }

  /* The drawer is the bar continued downward, so it takes the same glass — just
     denser, because a full-height panel of links has to hold against whatever
     section it happens to open over. */
  .site-nav {
    position: fixed; inset: 0 0 auto; top: 64px;
    background: rgba(255,255,255,.93);
    backdrop-filter: blur(24px) saturate(160%); -webkit-backdrop-filter: blur(24px) saturate(160%);
    border-bottom: 1px solid rgba(10,14,39,.1);
    padding: 1.2rem var(--gutter) 2rem;
    clip-path: inset(0 0 100% 0);
    transition: clip-path .6s var(--e-out);
  }
  .site-nav.is-open { clip-path: inset(0 0 0 0); }
  .site-nav ul { flex-direction: column; gap: 0; }
  .site-nav li { border-bottom: 1px solid rgba(10,14,39,.08); }
  .site-nav a { display: block; padding: 1rem 0; font-size: 1.15rem; font-weight: 600; }
  .site-nav a::after { display: none; }

  /* Same reasoning as the desktop pin: four short holds, not a long hold. The
     pin is the full screen — at 72svh the footage stopped short and left a band
     of flat navy under it for the whole scroll. */
  .hero { height: calc(100svh + 1500px); }
  .hero__pin { height: 100svh; }
  .js .hero__content { min-height: 46svh; }
  .hero__scene-meta { gap: .45rem; }
  .hero__progress { bottom: 1.5rem; }
  .hero__overlay {
    background:
      linear-gradient(180deg, rgba(0,0,0,.35) 0%, rgba(1,6,43,.45) 38%, rgba(1,6,43,.8) 68%, var(--navy-900) 100%),
      linear-gradient(100deg, rgba(0,0,0,.4) 0%, rgba(0,0,0,.12) 55%, transparent 80%);
  }

  /* Nothing pins at any width now, so these only handle the one-column case. */
  .stack__lede { margin-bottom: 2rem; }

  /* One column is too narrow to overlap two cards in a single cell and still let
     the reader compare them, so both jurisdictions sit in normal flow instead of
     crossfading. */
  .reg__viewport { gap: 2.5rem; }
  .reg__panels { min-height: auto; display: grid; gap: 1.5rem; }
  .reg__panel {
    grid-area: auto;
    position: static; opacity: 1; visibility: visible; pointer-events: auto; transform: none;
  }
}

@media (max-width: 640px) {
  .hero__pin { padding: 6.5rem 0 5.5rem; }
  /* One card per row; they stay cards, so they keep their gap and their padding. */
  .crn-traits__grid { grid-template-columns: minmax(0, 1fr); }
  .crn-trait { padding: 1.3rem; }
  .crn-trait .wd-glyph { --gh: 3rem; margin-bottom: 1rem; }
  /* Two columns is too narrow for a name and a sentence, so the glyph keeps its
     own column and the pair stacks beside it — the pairing still reads. */
  .crn-dept {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    gap: .3rem 1rem;
    padding: 1.1rem .4rem;
  }
  .crn-dept .wd-glyph { --gh: 2.7rem; grid-row: 1 / span 2; }
  .crn-dept__focus { grid-column: 2; }
  .reg__facts > div, .contact__routes li { grid-template-columns: minmax(0,1fr); gap: .2rem; }
  .goal__readout { position: static; margin-bottom: .8rem; max-width: none; }
  .map-legend { position: static; margin-top: .8rem; }
  .form__row { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- 18b. Display voice ----------
   Last in the cascade on purpose: every headline below has its own size and
   tracking set in its own section, and this is the one place that decides which
   of them speak in the serif. Keep it as one list — if a heading is not here it
   is deliberately in the grotesk, which is the case for anything at card size
   and under, where a serif starts to read as decoration rather than authority.

   Two adjustments come with the family and apply to all of it:

   · Weight drops to 600. The grotesk needed 700 to hold its own at display size;
     Newsreader at 700 turns into a slab and closes up its counters.
   · Tracking opens from -.03em to -.012em. Negative tracking exists to close the
     gaps a grotesk leaves between straight-sided letters. A serif fills those
     gaps with its own serifs, so the same value collides them.
   · Optical sizing is on: the family carries an opsz axis, so the headline cut
     thins its hairlines and tightens its spacing as the clamp scales up, which
     is why it survives at 5rem without looking like body copy blown up. */
.hero__title, .hero__scene-title, .section-title, .principle__statement,
.practice__title, .crn-open__title, .reg__reg {
  font-family: var(--display);
  font-weight: 600;
  letter-spacing: -.012em;
  font-optical-sizing: auto;
}
/* The italic is the accent now that the gradient is gone. It is the second half
   of the sentence in every hero headline, and Newsreader's italic is a true
   cursive cut rather than a slant, so the shift is legible at a glance without
   another colour entering the page. */
.hero__scene-title em, .section-title em { font-style: italic; }
/* The practice sub-line is a name, not an aside — it stays upright and keeps the
   grotesk, so it reads as a label under the serif rather than a continuation
   of it. */
.practice__title em { font-family: var(--sans); font-style: normal; }

/* ---------- 19. Motion preferences ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal], .hero__title .line__in, .slab { opacity: 1 !important; transform: none !important; }
  .principle__statement .w { opacity: 1 !important; filter: none !important; transform: none !important; }
}
