/* ==========================================================================
   ONYX CAPITAL PARTNERS
   Global M&A, Pre-IPO & Private Equity Advisory

   Hand-authored, zero dependencies — no CSS framework, no animation library.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Obsidian: a tuned ramp rather than opacities over black, so layered
     surfaces keep their separation instead of muddying together. */
  --ob-900: #050506;
  --ob-850: #08080a;
  --ob-800: #0b0b0e;
  --ob-700: #111116;
  --ob-600: #17171d;
  --ob-500: #1f1f27;
  --ob-400: #2a2a34;

  /* Warm off-white. Pure #fff on near-black glares and reads cheap; bone
     carries the same contrast with none of the harshness. */
  --bone: #f4f1ec;
  --bone-dim: rgb(244 241 236 / 0.62);
  --bone-faint: rgb(244 241 236 / 0.38);
  --bone-ghost: rgb(244 241 236 / 0.16);
  --hairline: rgb(244 241 236 / 0.10);
  --hairline-strong: rgb(244 241 236 / 0.18);

  /* Brand red, sampled from the logo artwork. Used as punctuation, never as a
     surface — the scarcity is what keeps it feeling expensive. */
  --red: #d00102;
  --red-bright: #ff2f2f;
  --red-deep: #7a0110;
  /* --red measures 4.05:1 on the sunken and accent bands, just under AA for the
     11px eyebrow labels that sit on them. This one measures 4.91:1 there. */
  --red-ink: #b80102;
  /* And the mirror problem on the dusk band: --red-bright is fine on obsidian
     (5.53:1) but only 4.44:1 on the raised card inside dusk, because that card
     is a lighter ground than obsidian. This one measures 5.00:1 there. */
  --red-lift: #ff4d4d;

  /* Display was Bodoni Moda, a Didone. Measured on canvas, its hairline is
     1 CSS pixel at 20px AND at 60px AND at weight 700 -- invariant, because
     stroke contrast is what a Didone is. At 1px those edges disappear on a
     phone. Inter's thinnest stroke scales with size (2px at 20, 5px at 60), so
     display now uses the same family as text and earns its authority from
     scale, case and tracking instead of from stroke contrast. The ONYX
     wordmark is artwork, so the Didone stays in the mark itself. */
  --font-display: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Fluid type: minimums land at 375px, maximums around 1600px. The display
     end is tuned down from the first pass — a Didone at 143px overpowered the
     layout and crowded the lede beneath it. */
  --t-hero: clamp(1.875rem, 1.15rem + 3.1vw, 3.75rem);
  --t-h1: clamp(1.5rem, 1.1rem + 1.7vw, 2.5rem);
  --t-h2: clamp(1.25rem, 1rem + 1.05vw, 1.875rem);
  --t-h3: clamp(1rem, 0.94rem + 0.28vw, 1.25rem);
  --t-lede: clamp(1.0625rem, 1rem + 0.3vw, 1.3125rem);
  /* Floors raised for phones: body from 15px and small from 13px. */
  --t-body: clamp(1rem, 0.95rem + 0.2vw, 1.0625rem);
  --t-small: clamp(0.875rem, 0.83rem + 0.2vw, 0.9375rem);
  --t-label: 0.6875rem;

  /* Leading. Uppercase sans has no descenders in the display lines, so it can
     sit tighter than the Didone could. */
  --lh-display: 1.08;
  --lh-title: 1.14;
  --lh-lede: 1.55;
  --lh-body: 1.75;

  /* Descender room for masked line reveals — see .reveal-line. */
  --lead-room: 0.16em;

  --gutter: clamp(1.25rem, 0.7rem + 2.2vw, 3.5rem);
  /* Tightened from a 10.5rem maximum. Whitespace reads as considered up to a
     point, past which it just reads as thin. */
  --section: clamp(3.75rem, 2.4rem + 4.6vw, 7rem);
  --container: 1440px;
  --measure: 62ch;

  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.76, 0, 0.24, 1);

  --nav-h: 5rem;

  /* Collapsed to ~0 by the reduced-motion block, switching off every
     transition in the sheet from a single place. */
  --dur: 1;
}

/* --------------------------------------------------------------------------
   1b. Semantic roles
   The block above is the PALETTE — fixed values. These are ROLES, and they are
   what components actually reference. Roles are redefined inside the dark
   zones below, so a single set of component rules serves both themes.
   -------------------------------------------------------------------------- */
:root {
  /* Warm stone rather than off-white. The first pass sat at #faf8f5, which is
     within a hair of paper white — across a full page of content that glares
     and reads thin. Dropping the ground and letting panels lift above it gives
     the light sections weight without going back to a dark site.
       --surface       the page itself
       --surface-raised cards and panels, a step up from the page
       --surface-hi    hover, the brightest step
       --surface-sunken recessed / alternate bands */
  --surface: #e9e5dd;
  --surface-raised: #f3f0ea;
  /* Palette value and role kept separate here on purpose: .section--hi paints
     itself from --stone-hi and re-points --surface-hi for the cards inside it.
     If the band painted from the role it would repaint itself with the override. */
  --stone-hi: #fbf9f6;
  --surface-hi: var(--stone-hi);
  --surface-sunken: #ded9cf;
  /* Was #f0e7e0, which is 1.030 away from the page it sits on -- below the
     ~1.06 where a band change becomes perceptible at all, so the accent
     sections were invisible as sections. This is the warm partner to
     --surface-sunken: same step on the ladder, different temperature. */
  --surface-accent: #e3d7cf;
  --surface-veil: rgb(243 240 234 / 0.86);

  --text: #14141a;
  --text-dim: rgb(20 20 26 / 0.72);
  /* 0.62, not 0.48: on the deeper ground the old value measured 3.1:1, which
     fails AA for normal-size text — and faint is doing real work here (stat
     captions, definition terms, footer copy). 0.62 measures 4.7:1. */
  --text-faint: rgb(20 20 26 / 0.62);
  --text-ghost: rgb(20 20 26 / 0.50);

  --hairline: rgb(20 20 26 / 0.13);
  --hairline-strong: rgb(20 20 26 / 0.24);

  /* On a light ground the brighter red vibrates; the deeper one holds. */
  --red-on-surface: var(--red);
  --glow-strength: 0.07;
}

/* Dark zones. The hero opens, the CTA and footer close, and the overlay menu
   takes over the screen — darkness became punctuation rather than the whole
   experience. */
.screen,
.hero,
.page-hero,
.cta,
.footer,
.menu,
.section--dusk,
.section--dark {
  --surface: var(--ob-900);
  --surface-raised: var(--ob-850);
  --surface-hi: var(--ob-700);
  --surface-sunken: var(--ob-800);
  --surface-accent: var(--ob-800);
  --surface-veil: rgb(5 5 6 / 0.72);

  --text: var(--bone);
  /* Raised from 0.66 / 0.42 / 0.18. Those were carried over from the all-dark
     build and never checked: faint measured 3.7:1 and ghost 1.5:1 against the
     obsidian ground — and ghost is what the footer's legal disclaimer is set
     in. These values clear 4.5:1, so every line of it is actually readable. */
  --text-dim: rgb(244 241 236 / 0.74);
  --text-faint: rgb(244 241 236 / 0.60);
  --text-ghost: rgb(244 241 236 / 0.50);

  --hairline: rgb(244 241 236 / 0.11);
  --hairline-strong: rgb(244 241 236 / 0.20);

  --red-on-surface: var(--red-bright);
  --glow-strength: 0.13;
}

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 2rem);
  background: var(--surface);
}

body {
  font-family: var(--font-sans);
  font-size: var(--t-body);
  /* Was 300. Inter Light at 15-17px, dimmed to 72%, with subpixel antialiasing
     switched off underneath it, left the edges of the letters too faint to read
     comfortably -- worst on phones, where the size floor is smallest. 400 is
     the weight the face is designed to be read at. */
  font-weight: 400;
  line-height: 1.7;
  color: var(--text-dim);
  background: var(--surface);
  overflow-x: hidden;
}

/* Grayscale smoothing thins strokes, which is why it is confined to the dark
   bands -- light type on a dark ground is the one case where subpixel
   rendering blooms and the thinner rasterization actually reads better. */
.screen, .hero, .page-hero, .cta, .footer, .menu, .section--dusk, .section--dark {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

button, input, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; padding: 0; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--text);
  line-height: var(--lh-title);
  letter-spacing: -0.015em;
  text-wrap: balance;
  /* Headings share the text family now; the display classes below carry the
     case, tracking and weight that make them read as headings. */
}

p { text-wrap: pretty; }

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

/* --red-bright measures 2.93:1 on the stone page and 2.62:1 on the sunken
   bands — under the 3:1 WCAG 2.2 asks of a focus indicator, and most of this
   site is light. --red-on-surface is the zone-aware pair (#d00102 on light,
   #ff2f2f on dark) and holds 4.05:1 or better everywhere. 2px carries the
   thickness the same criterion wants. */
:focus-visible { outline: 2px solid var(--red-on-surface); outline-offset: 3px; }

.skip-link {
  position: absolute;
  left: 50%;
  top: 0;
  translate: -50% -150%;
  z-index: 300;
  background: var(--text);
  color: var(--surface);
  padding: 0.75rem 1.5rem;
  font-size: var(--t-small);
  font-weight: 500;
  transition: translate 0.25s var(--ease);
}
.skip-link:focus-visible { translate: -50% 0; }

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--narrow { max-width: 1080px; }

.section { padding-block: var(--section); position: relative; }
.section--tight { padding-block: clamp(3.5rem, 2.5rem + 4vw, 6rem); }
/* Paired with .section-head--center: the one pivotal section on a page gets
   both the centered head and the air to carry it. */
.section--wide { padding-block: clamp(5.5rem, 3.5rem + 7vw, 10rem); }
.section--ruled { border-top: 1px solid var(--hairline); }

/* --------------------------------------------------------------------------
   The tone ladder.

   Sections used to be stone, stone-with-a-hairline, or obsidian, which meant
   most neighbors were the same value and only a 1px rule stood between them.
   Measured as a contrast ratio between the two backgrounds, a band change
   needs about 1.06 to register at all and about 1.12 to feel deliberate:

       hi      #fbf9f6   1.195 from the page
       page    #e9e5dd   --
       sunken  #ded9cf   1.120 from the page   (neutral)
       accent  #e3d7cf   1.123 from the page   (warm -- same step, not a step of its own)
       dark    #050506   16.2  from the page

   The rule the pages follow: no two adjacent sections may sit on the same
   step, and --sunken and --accent count as one step. -------------------- */
/* On every other band a card is lighter than its ground, which is what makes it
   read as raised. Here the page IS the lightest step, so the stock card color
   lands 1.08 DARKER than its own section and the hover color lands exactly on it
   -- a hovered card disappeared into the page. So on this band a card is a well
   rather than a lift, and hover brings it up clear of both. */
.section--hi {
  background: var(--stone-hi);
  --surface-hi: #fff;
}

/* The mid-dark rung. --dark is the site's hard stop and belongs to the hero, the
   CTA and the footer; a band in the middle of a page that uses the same obsidian
   and the same red bloom makes the page close twice. Dusk is 1.14 above obsidian
   -- enough to be a different room, not enough to be a different palette. */
.section--dusk {
  background: var(--ob-600);
  --surface: var(--ob-600);
  --surface-raised: var(--ob-500);
  --surface-hi: var(--ob-400);
  --surface-sunken: var(--ob-700);
  --red-on-surface: var(--red-lift);
}

/* On the two deeper light bands the eyebrow red drops to 4.05:1 and the cards
   would vanish into their ground, so both are restated here. */
.section--raised,
.section--accent {
  --red-on-surface: var(--red-ink);
  --surface-raised: #f3f0ea;
  --hairline: rgb(20 20 26 / 0.16);
}
.section--raised { background: var(--surface-sunken); }

/* Hairline rules are the structural motif — they do the work that boxes and
   cards would do in a louder design. */
.rule { height: 1px; background: var(--hairline); border: 0; width: 100%; }

.split { display: grid; gap: clamp(2rem, 1rem + 4vw, 5rem); align-items: start; }
@media (min-width: 900px) {
  .split { grid-template-columns: minmax(0, 4fr) minmax(0, 7fr); }
  .split__aside--sticky { position: sticky; top: calc(var(--nav-h) + 3rem); }
}

.stack > * + * { margin-top: var(--gap, 1.5rem); }

/* --------------------------------------------------------------------------
   4. Typography components
   -------------------------------------------------------------------------- */
.label {
  display: block;
  font-family: var(--font-sans);
  font-size: var(--t-label);
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* The red tick before a label — the most repeated brand gesture on the site.
   On the lighter build the label text itself carries the red too, which is
   what gives the accent structural presence instead of leaving it to a single
   28px rule. */
.label--marked {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--red-on-surface);
}
.label--marked::before {
  content: "";
  width: 1.75rem;
  height: 1px;
  background: var(--red);
  flex-shrink: 0;
}

/* The display scale. Uppercase, tracked open, and never lighter than 400 --
   below that Inter's own thinnest stroke drops to 1px at small display sizes
   and we are back where we started. Tracking widens as the size falls, which is
   what keeps a 20px heading reading as a heading. */
.display-1 {
  font-family: var(--font-display);
  font-size: var(--t-hero);
  font-weight: 400;
  line-height: var(--lh-display);
  letter-spacing: 0.045em;
  text-transform: uppercase;
}
.display-2 {
  font-family: var(--font-display);
  font-size: var(--t-h1);
  font-weight: 400;
  line-height: var(--lh-display);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.display-3 {
  font-family: var(--font-display);
  font-size: var(--t-h2);
  font-weight: 400;
  line-height: var(--lh-title);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.display-4 {
  font-family: var(--font-display);
  font-size: var(--t-h3);
  font-weight: 500;
  line-height: var(--lh-title);
  letter-spacing: 0.075em;
  text-transform: uppercase;
}

/* The emphasis is carried by color alone. font-style must be stated: these
   classes sit on <em>, which the UA stylesheet italicises, and Inter has no
   italic loaded -- the browser would synthesise an oblique, which is the same
   smearing that made the old headings look broken. */
.accent,
.accent--bone { font-style: normal; }
.accent { color: var(--red-bright); }
.accent--bone { color: var(--text); }

.lede {
  font-size: var(--t-lede);
  font-weight: 400;
  line-height: var(--lh-lede);
  color: var(--text-dim);
  max-width: 52ch;
}

.prose-measure { max-width: var(--measure); }
.muted { color: var(--text-faint); }
.bone { color: var(--text); }
.center { text-align: center; }
.center .lede { margin-inline: auto; }

.numeral {
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: -0.02em;
}

.section-head { margin-bottom: clamp(1.75rem, 1.2rem + 1.8vw, 3rem); }
.section-head .display-3,
.section-head .display-2 { margin-top: 1.25rem; }
.section-head .lede { margin-top: 1.5rem; }

/* Editorial two-column section head.
   Every section on the site was previously the same silhouette: label, heading
   and lede stacked hard against the left margin, full container width, section
   after section. Pinning the label into its own narrow rail gives the page a
   vertical spine of small-caps labels and sets the heading against real
   negative space — which is what separates a firm's site from a landing page.

   Done entirely in CSS: all 25 section heads share one markup shape, so none of
   the pages needed editing. */
@media (min-width: 900px) {
  .section-head {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 8fr);
    column-gap: clamp(2rem, 3.5vw, 4.5rem);
    align-items: start;
  }

  .section-head > .label {
    grid-column: 1;
    grid-row: 1;
    /* nudge onto the heading's first baseline rather than its box top */
    padding-top: 0.65rem;
  }

  .section-head > :not(.label) { grid-column: 2; }

  /* Vertical rhythm is now the grid's job, not the margins'. */
  .section-head > .display-2,
  .section-head > .display-3 { margin-top: 0; }
}

/* --------------------------------------------------------------------------
   Section head variants.

   The rail above is the default, and it was the ONLY shape on the site: all 18
   section heads resolved to the same 3fr/8fr grid, so even where the background
   changed, the silhouette repeated and the page read as one continuous scroll.
   These are the alternates. The rule the pages follow is that no two adjacent
   sections may wear the same one.

   All four take the same markup as the default -- an optional .label, a heading,
   an optional .lede -- except --index, which adds one <span class="section-head__num">.
   Each collapses to the plain stacked shape below 900px, where there is no room
   for a rail and no need for the variety.
   -------------------------------------------------------------------------- */

/* Stacked: eyebrow directly over the heading, both hard left, heading held to a
   display measure so it breaks where the writer intended. The quiet shape --
   use it where the heading itself is the event. */
.section-head--stack { display: block; }
.section-head--stack > .label { padding-top: 0; margin-bottom: 1.25rem; }
.section-head--stack > .display-2,
.section-head--stack > .display-3 { margin-top: 0; max-width: 18ch; }

/* Indexed: an oversized numeral anchors the rail instead of the eyebrow.
   Gives a sequence of sections an actual count, and the numeral reads as
   structure rather than decoration. */
.section-head--index > .section-head__num {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 1.6rem + 3.4vw, 4.5rem);
  line-height: 0.9;
  color: var(--red-on-surface);
  letter-spacing: -0.03em;
}
.section-head--index > .label { color: var(--text-faint); }

/* Inline: the heading sits left and the eyebrow is pushed to the far right of
   the same first baseline, with a hairline running between them. Turns the head
   into a rule across the page rather than a block sitting on top of one.

   The heading has to come first in the markup for the grid to place it, which
   below 900px would leave the eyebrow reading as a caption underneath. Order it
   back on top where the layout is a simple stack. */
.section-head--inline {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.25rem;
}
.section-head--inline > .label { padding-top: 0; order: -1; }

/* Centered: reserved for the single pivotal section on a page -- never two on
   one page, and never adjacent to another centered thing. The short rule above
   is what keeps it from reading as a landing page. */
.section-head--center { text-align: center; }
.section-head--center > .label { padding-top: 0; margin-bottom: 1.5rem; }
.section-head--center > .label.label--marked::before { display: none; }
.section-head--center > .display-2,
.section-head--center > .display-3 {
  margin-top: 0;
  margin-inline: auto;
  max-width: 22ch;
}
.section-head--center > .lede { margin-inline: auto; max-width: 54ch; }
.section-head--center::before {
  content: "";
  display: block;
  width: 2.5rem;
  height: 1px;
  margin: 0 auto 2rem;
  background: var(--red-on-surface);
}

@media (min-width: 900px) {
  /* Undo the default rail for the two variants that do not use one. */
  .section-head--stack,
  .section-head--center { display: block; }

  .section-head--index {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 8fr);
    column-gap: clamp(2rem, 3.5vw, 4.5rem);
    align-items: start;
  }
  .section-head--index > .section-head__num { grid-column: 1; grid-row: 1; }
  .section-head--index > .label {
    grid-column: 1;
    grid-row: 2;
    padding-top: 0.85rem;
  }
  .section-head--index > :not(.label):not(.section-head__num) { grid-column: 2; }
  .section-head--index > .display-2,
  .section-head--index > .display-3 { grid-row: 1 / span 2; margin-top: 0; }

  .section-head--inline {
    --head-gap: clamp(2.5rem, 5vw, 6rem);
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--head-gap);
    align-items: baseline;
  }
  .section-head--inline > .display-2,
  .section-head--inline > .display-3 { grid-column: 1; grid-row: 1; margin-top: 0; }
  .section-head--inline > .label {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
    white-space: nowrap;
  }
  .section-head--inline > .lede { grid-column: 1; grid-row: 2; max-width: 58ch; }
  /* The hairline that carries the eye from the heading across to the label.
     It is confined to the column gap. It used to run 40vw (up to 352px)
     leftward from the label with nothing to stop it, so between about 900px
     and 1350px -- wherever the heading was long enough -- the rule was drawn
     straight through the heading's own text. The gap is the one strip of the
     row guaranteed to be empty however the heading wraps. */
  .section-head--inline > .label::after {
    content: "";
    position: absolute;
    right: calc(100% + 0.9rem);
    top: 0.5em;
    width: calc(var(--head-gap) - 1.8rem);
    height: 1px;
    background: var(--hairline-strong);
  }
  .section-head--inline > .label { position: relative; }
  .section-head--inline > .label.label--marked::before { display: none; }
}

/* --------------------------------------------------------------------------
   5. Buttons & links
   -------------------------------------------------------------------------- */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.85em;
  padding: 1.05em 2em;
  min-height: 3rem;
  font-family: var(--font-sans);
  font-size: var(--t-small);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
  border: 1px solid var(--hairline-strong);
  isolation: isolate;
  overflow: hidden;
  transition: color calc(0.31s * var(--dur)) var(--ease),
    border-color calc(0.31s * var(--dur)) var(--ease);
}

/* Fill wipes up from the baseline — quieter than a color swap, and it reads
   as deliberate rather than reactive. */
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--text);
  transform-origin: bottom;
  scale: 1 0;
  transition: scale calc(0.34s * var(--dur)) var(--ease-out);
}

.btn:hover { color: var(--surface); border-color: var(--text); }
.btn:hover::before { scale: 1 1; }

.btn__arrow {
  width: 1.15em;
  height: 1.15em;
  flex-shrink: 0;
  transition: transform calc(0.31s * var(--dur)) var(--ease-out);
}
.btn:hover .btn__arrow { transform: translateX(4px); }

.btn--primary { border-color: var(--red); }
.btn--primary::before { background: var(--red); }
.btn--primary:hover { color: #fff; border-color: var(--red); }

.btn--solid { background: var(--text); color: var(--surface); border-color: var(--text); }
.btn--solid::before { background: var(--red); }
.btn--solid:hover { color: #fff; border-color: var(--red); }

.btn--sm { padding: 0.7em 1.35em; min-height: 2.5rem; font-size: var(--t-label); }
.btn--block { width: 100%; }

.link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  color: var(--text);
  font-size: var(--t-small);
  letter-spacing: 0.08em;
  padding-bottom: 0.35em;
  transition: color calc(0.2s * var(--dur)) var(--ease);
}
.link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  scale: 0 1;
  transform-origin: left;
  transition: scale calc(0.31s * var(--dur)) var(--ease-out);
}
.link:hover { color: var(--red-on-surface); }
.link:hover::after { scale: 1 1; }

/* --------------------------------------------------------------------------
   6. Navigation
   -------------------------------------------------------------------------- */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  /* At rest the bar floats over the dark hero, so it keeps the light-on-dark
     roles; once stuck it is over light content and flips. */
  --text: var(--bone);
  /* .btn:hover knocks its label out in --surface against a fill of --text. The
     nav re-points --text to bone but used to leave --surface at the page value,
     so hovering "Inquire" over the hero painted #e9e5dd on #f4f1ec -- 1.12:1,
     a blank button. --surface has to track the ground the nav is sitting on. */
  --surface: var(--ob-900);
  /* Only .nav__locale reads this. 0.42 looked right and measured 3.63:1 on the
     hero — under AA for 11px text. 0.52 clears 4.5 with room to spare and is
     still visibly quieter than the brand and the CTA beside it. */
  --text-faint: rgb(244 241 236 / 0.52);
  --hairline: rgb(244 241 236 / 0.11);
  --hairline-strong: rgb(244 241 236 / 0.20);
  --red-on-surface: var(--red-bright);
  color: var(--text);
  border-bottom: 1px solid transparent;
  transition: background-color calc(0.34s * var(--dur)) var(--ease),
    border-color calc(0.34s * var(--dur)) var(--ease);
}

.nav.is-stuck {
  --text: #14141a;
  /* Stuck, the bar is over light content again, so the knockout goes back. */
  --surface: #e9e5dd;
  /* The stuck bar is an 86% veil, so a dark section scrolling underneath drags
     the ground down to ~#d2cfca. 0.48 measured 2.94:1 against that worst case;
     0.64 holds 4.60:1 there and 5.23:1 over the ordinary stone page. */
  --text-faint: rgb(20 20 26 / 0.64);
  --hairline: rgb(20 20 26 / 0.13);
  --hairline-strong: rgb(20 20 26 / 0.24);
  --red-on-surface: var(--red);
  color: var(--text);
  background: var(--surface-veil);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border-bottom-color: var(--hairline);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  height: var(--nav-h);
  transition: height calc(0.34s * var(--dur)) var(--ease);
}
.nav.is-stuck .nav__inner { height: 4.25rem; }

.nav__brand { display: flex; align-items: center; gap: 1rem; flex-shrink: 0; }

/* Two lockups, cross-faded. The bar floats over the dark hero at rest (white
   wordmark) and over light content once stuck (ink wordmark) — a single image
   would disappear into one of the two. */
.nav__logo-stack {
  position: relative;
  display: block;
  flex-shrink: 0;
  height: 2rem;
  transition: height calc(0.34s * var(--dur)) var(--ease);
}
.nav.is-stuck .nav__logo-stack { height: 1.75rem; }

.nav__logo {
  height: 100%;
  width: auto;
  transition: opacity calc(0.34s * var(--dur)) var(--ease);
}

.nav__logo--ink {
  position: absolute;
  left: 0;
  top: 0;
  /* Explicit height with auto width. inset:0 would force the image to the
     stack's box and distort it the moment the two lockups differ in aspect. */
  height: 100%;
  width: auto;
  opacity: 0;
}

.nav.is-stuck .nav__logo--knockout { opacity: 0; }
.nav.is-stuck .nav__logo--ink { opacity: 1; }

.nav__locale {
  display: none;
  padding-left: 1rem;
  border-left: 1px solid var(--hairline);
  font-size: var(--t-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.nav__actions { display: flex; align-items: center; gap: 1.25rem; }
.nav__cta { display: none; }

@media (min-width: 720px) {
  .nav__locale { display: block; }
  .nav__cta { display: inline-flex; }
}

.nav__toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.6rem 0;
  /* The primary navigation control on small screens — hold it at the 44px
     touch-target minimum regardless of how little the label and bars need. */
  min-height: 2.75rem;
  color: var(--text);
  font-size: var(--t-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  z-index: 101;
}

.nav__toggle-label { display: none; }
@media (min-width: 480px) { .nav__toggle-label { display: inline; } }

.nav__toggle-box { position: relative; width: 1.5rem; height: 0.6rem; flex-shrink: 0; }

.nav__toggle-bar {
  position: absolute;
  left: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transition: transform calc(0.31s * var(--dur)) var(--ease-in-out);
}
.nav__toggle-bar:nth-child(1) { top: 0; }
.nav__toggle-bar:nth-child(2) { bottom: 0; }

[aria-expanded="true"] .nav__toggle-bar:nth-child(1) { transform: translateY(0.3rem) rotate(45deg); }
[aria-expanded="true"] .nav__toggle-bar:nth-child(2) { transform: translateY(-0.3rem) rotate(-45deg); }

/* Full-screen overlay menu */
.menu {
  position: fixed;
  inset: 0;
  z-index: 99;
  background: var(--surface-raised);
  display: grid;
  grid-template-rows: var(--nav-h) 1fr auto;
  visibility: hidden;
  opacity: 0;
  /* The visibility flip is DELAYED so the overlay stays on screen for the fade
     out. That delay is the whole risk in this rule: this element covers the
     viewport, so for as long as it is visible it eats every click. If the
     transition is ever interrupted or its clock stalls -- a throttled
     background tab will do it -- the page is left unclickable with nothing
     on screen to explain why. pointer-events carries no delay, so the closed
     overlay cannot swallow a click even while it is still fading. */
  pointer-events: none;
  transition: opacity calc(0.37s * var(--dur)) var(--ease-in-out),
    visibility 0s linear calc(0.37s * var(--dur));
}

.menu.is-open {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transition: opacity calc(0.37s * var(--dur)) var(--ease-in-out), visibility 0s;
}

/* No align-items: center here. Centering a flex item that overflows its scroll
   container pushes the start of the content above scrollTop 0, where scrolling
   cannot reach it -- at 390x420 the first menu entry was clipped and
   unreachable. Auto margins center identically but refuse to overflow the
   start edge. */
.menu__body { display: flex; overflow-y: auto; }
.menu__body > * { margin-block: auto; padding-block: 1.5rem; width: 100%; }
.menu__list { width: 100%; max-width: 30rem; }

.menu__item {
  border-top: 1px solid var(--hairline);
  opacity: 0;
  transform: translateY(1.5rem);
  transition: opacity calc(0.34s * var(--dur)) var(--ease-out),
    transform calc(0.41s * var(--dur)) var(--ease-out);
}
.menu__item:last-child { border-bottom: 1px solid var(--hairline); }

.menu.is-open .menu__item {
  opacity: 1;
  transform: none;
  transition-delay: calc(var(--i, 0) * 60ms * var(--dur));
}

.menu__link {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: clamp(0.85rem, 1.4vw, 1.5rem);
  padding: clamp(0.6rem, 0.45rem + 0.5vw, 0.9rem) 0;
}

.menu__num {
  font-family: var(--font-sans);
  /* A touch larger and heavier than a generic label: this is the overlay's only
     small type and it is doing navigation work on a phone. */
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  color: var(--text-faint);
  flex-shrink: 0;
  width: 1.85rem;
  transition: color calc(0.27s * var(--dur)) var(--ease);
}

.menu__text {
  font-family: var(--font-display);
  /* Was clamp(2rem … 5rem). 80px rows are a statement piece, not navigation —
     a menu should be quick to scan, not something you read. */
  font-size: clamp(1.375rem, 1.05rem + 1.4vw, 2.125rem);
  line-height: 1.1;
  color: var(--text);
  letter-spacing: -0.02em;
  transition: transform calc(0.34s * var(--dur)) var(--ease-out),
    color calc(0.27s * var(--dur)) var(--ease);
}

.menu__link:hover .menu__text {
  transform: translateX(0.6rem);
  color: var(--red-bright);
}
.menu__link:hover .menu__num { color: var(--red-on-surface); }
.menu__link[aria-current="page"] .menu__text { font-style: italic; }

.menu__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 2rem;
  border-top: 1px solid var(--hairline);
  font-size: var(--t-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.menu__foot a:hover { color: var(--red-bright); }

/* Reading-progress hairline */
.progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 100%;
  transform-origin: 0 50%;
  scale: var(--p, 0) 1;
  background: linear-gradient(90deg, var(--red-deep), var(--red), var(--red-bright));
  z-index: 101;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   7. Hero
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   The screen — the homepage, and the homepage only.

   One viewport. No sections, no scroll, nothing to read past. The whole page
   is a statement, a single way in, and an index of where else to go. Every
   other page carries the detail; this one carries the position.
   -------------------------------------------------------------------------- */
.screen {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto;
  gap: 2rem;
  padding-block: calc(var(--nav-h) + 2rem) clamp(1.5rem, 1rem + 1.5vw, 2.5rem);
  color: var(--text-dim);
  background:
    radial-gradient(120% 120% at 15% 0%, #2a0508 0%, transparent 55%),
    linear-gradient(150deg, #0d0d0f 0%, #16080a 55%, #0a0a0b 100%);
}

.screen__inner {
  align-self: center;
  width: 100%;
  max-width: 62rem;
}

.screen__title {
  font-family: var(--font-display);
  font-size: var(--t-hero);
  font-weight: 400;
  line-height: var(--lh-display);
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--text);
  margin-block: 1.5rem 1.75rem;
  text-wrap: balance;
}

.screen__lede {
  font-size: var(--t-lede);
  line-height: var(--lh-lede);
  color: var(--text-dim);
  max-width: 44ch;
}

.screen__cta { margin-top: clamp(2rem, 1.5rem + 2vw, 3.25rem); }

/* The foot carries the index the removed sections used to carry: where the
   firm is, where else to go, and the two legal links. */
.screen__foot {
  align-self: end;
  display: grid;
  gap: 1.5rem 2rem;
  align-items: center;
  font-size: var(--t-label);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding-top: 1.5rem;
  border-top: 1px solid var(--hairline);
}

.screen__index {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
}

.screen__index a {
  display: inline-flex;
  align-items: baseline;
  gap: 0.55rem;
  padding-block: 0.35rem;
  color: var(--text-faint);
  transition: color calc(0.24s * var(--dur)) var(--ease);
}
.screen__index a:hover { color: var(--text); }

.screen__num {
  color: var(--red-on-surface);
  font-weight: 500;
  transition: transform calc(0.24s * var(--dur)) var(--ease-out);
}
.screen__index a:hover .screen__num { transform: translateY(-0.15em); }

.screen__where { white-space: nowrap; }

.screen__legal { display: flex; gap: 1.5rem; }
.screen__legal a {
  color: var(--text-faint);
  padding-block: 0.35rem;
  transition: color calc(0.24s * var(--dur)) var(--ease);
}
.screen__legal a:hover { color: var(--text); }

@media (min-width: 860px) {
  .screen__foot {
    grid-template-columns: auto 1fr auto;
    gap: 2.5rem;
  }
  .screen__index { justify-content: center; }
}

/* Short phones -- a 667px viewport was 51px short of holding the screen, which
   is the worst kind of scroll: just enough to look like a mistake. Tighten the
   vertical rhythm rather than dropping anything from the page. */
@media (max-height: 720px) {
  .screen {
    padding-block: calc(var(--nav-h) + 1rem) 1.25rem;
    gap: 1.25rem;
  }
  .screen__title { margin-block: 1rem 1.15rem; }
  .screen__cta { margin-top: 1.5rem; }
  .screen__foot { padding-top: 1.1rem; gap: 0.75rem 1.5rem; }
}

/* A phone in landscape has no room for a full viewport of air; let the screen
   size to its content there rather than crushing it. */
@media (max-height: 560px) and (orientation: landscape) {
  .screen { min-height: 0; padding-block: calc(var(--nav-h) + 1.25rem) 1.25rem; }
}

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: min(100svh, 52rem);
  display: flex;
  align-items: center;
  padding-top: var(--nav-h);
  /* The hero previously had no ground of its own — it inherited the dark body.
     With the page now light it has to carry its own, or the bone text lands on
     off-white and disappears. */
  color: var(--text-dim);
  background:
    radial-gradient(120% 120% at 15% 0%, #2a0508 0%, transparent 55%),
    linear-gradient(150deg, #0d0d0f 0%, #16080a 55%, #0a0a0b 100%);
}

.hero--inner { min-height: 78svh; }

/* The facet field: the logo's own gem geometry, enlarged and slowly drifting.
   Replaces the background video most firms in this category use — same
   atmosphere, a rounding error of the bytes. */
.facets {
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  overflow: hidden;
}

/* The generated field. Sits behind the facet marks and paints the blooms and
   the light rays that the static gradients used to fake. */
.field {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: block;
  width: 100%;
  height: 100%;
}

.facets__mark {
  position: absolute;
  top: 50%;
  right: -26%;
  width: min(104vh, 78vw);
  aspect-ratio: 1;
  translate: 0 -50%;
  /* Was 0.10 and cropping hard against the right edge, which read as clip-art
     competing with the headline rather than as atmosphere behind it. */
  opacity: 0.055;
  color: var(--red-on-surface);
  animation: facet-turn 90s linear infinite;
  will-change: transform;
}

.facets__mark--echo {
  right: auto;
  left: -28%;
  width: min(80vh, 70vw);
  opacity: 0.05;
  animation-duration: 130s;
  animation-direction: reverse;
}

@keyframes facet-turn {
  to { transform: rotate(360deg); }
}

/* Slow bloom behind the mark */
.facets__glow {
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  pointer-events: none;
  will-change: transform;
}

.facets__glow--1 {
  width: 46rem;
  height: 46rem;
  top: -16rem;
  right: -10rem;
  background: radial-gradient(circle, rgb(208 1 2 / 0.17), transparent 70%);
  animation: bloom-a 24s var(--ease) infinite alternate;
}

.facets__glow--2 {
  width: 34rem;
  height: 34rem;
  bottom: -14rem;
  left: -8rem;
  background: radial-gradient(circle, rgb(122 1 16 / 0.24), transparent 72%);
  animation: bloom-b 31s var(--ease) infinite alternate;
}

@keyframes bloom-a { to { transform: translate3d(-5rem, 4rem, 0) scale(1.2); } }
@keyframes bloom-b { to { transform: translate3d(4rem, -3rem, 0) scale(1.28); } }

/* Fine grid, masked so it fades out rather than ending abruptly */
.hero::before,
.page-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(rgb(244 241 236 / 0.025) 1px, transparent 1px),
    linear-gradient(90deg, rgb(244 241 236 / 0.025) 1px, transparent 1px);
  background-size: 88px 88px;
  mask-image: radial-gradient(130% 100% at 50% 0%, #000 20%, transparent 78%);
  -webkit-mask-image: radial-gradient(130% 100% at 50% 0%, #000 20%, transparent 78%);
  pointer-events: none;
}

/* Grain — an inline SVG turbulence, sharper and lighter than a bitmap */
.grain {
  position: fixed;
  inset: 0;
  z-index: 98;
  pointer-events: none;
  opacity: 0.11;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

.hero__inner { width: 100%; padding-block: clamp(2.5rem, 1.75rem + 2.5vw, 4rem); }

.hero__title {
  font-size: var(--t-hero);
  font-weight: 400;
  line-height: var(--lh-display);
  /* Positive tracking, not the Didone's negative. Uppercase display type needs
     air between the letters or it sets as a wall. */
  letter-spacing: 0.045em;
  text-transform: uppercase;
  margin-block: 1.25rem 1.5rem;
}

.hero__lede { max-width: 40ch; }

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: clamp(2rem, 1.5rem + 2vw, 3.25rem);
}

/* Scroll cue */
.scroll-cue {
  position: absolute;
  bottom: 2.25rem;
  /* Was bottom-left, directly beneath the CTAs and crowding them. */
  left: auto;
  right: var(--gutter);
  display: flex;
  align-items: center;
  gap: 0.85rem;
  font-size: var(--t-label);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.scroll-cue__line {
  width: 3rem;
  height: 1px;
  background: var(--hairline-strong);
  position: relative;
  overflow: hidden;
}
.scroll-cue__line::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--red);
  transform-origin: left;
  animation: cue 2.6s var(--ease-in-out) infinite;
}
@keyframes cue {
  0% { transform: scaleX(0); transform-origin: left; }
  45% { transform: scaleX(1); transform-origin: left; }
  55% { transform: scaleX(1); transform-origin: right; }
  100% { transform: scaleX(0); transform-origin: right; }
}

/* Inner-page hero */
.page-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  color: var(--text-dim);
  background:
    radial-gradient(120% 130% at 12% 0%, #2a0508 0%, transparent 58%),
    linear-gradient(150deg, #0d0d0f 0%, #16080a 60%, #0a0a0b 100%);
  padding-top: calc(var(--nav-h) + clamp(2.5rem, 1.75rem + 3vw, 4.25rem));
  padding-bottom: clamp(2.5rem, 1.75rem + 2.5vw, 4rem);
}

.page-hero__title { margin-block: 1.5rem 1.75rem; }

/* --------------------------------------------------------------------------
   8. Statistics
   -------------------------------------------------------------------------- */
.stats {
  display: grid;
  /* minmax(0, 1fr) rather than 1fr: a grid item's automatic minimum size is its
     min-content width, and "$480m+" set at 36px is wider than a 320px screen
     leaves for half a row — with plain 1fr the tracks refused to shrink and
     pushed 9px of the table off the side of the page. */
  grid-template-columns: minmax(0, 1fr);
  border-top: 1px solid var(--hairline);
  border-left: 1px solid var(--hairline);
}

/* Two up needs ~170px of content per cell once the padding is taken out.
   Below that the figures crowd their own labels, so stack them instead. */
@media (min-width: 480px) { .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 860px) { .stats { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.stat {
  padding: clamp(1.5rem, 1rem + 2vw, 2.75rem);
  border-right: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  transition: background-color calc(0.34s * var(--dur)) var(--ease);
}
.stat:hover { background: var(--surface-raised); }

.stat__value {
  font-family: var(--font-display);
  font-size: clamp(2.25rem, 1.4rem + 3vw, 3.75rem);
  color: var(--text);
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums lining-nums;
}

.stat__label {
  margin-top: 0.85rem;
  font-size: var(--t-small);
  color: var(--text-faint);
  line-height: 1.5;
}

/* --------------------------------------------------------------------------
   9. Editorial cards & lists
   -------------------------------------------------------------------------- */
.cards { display: grid; gap: 1px; background: var(--hairline); border: 1px solid var(--hairline); }
@media (min-width: 700px) { .cards--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 960px) { .cards--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 700px) { .cards--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .cards--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.card {
  position: relative;
  isolation: isolate;
  /* Sitting flush with the page made a grid of cards read as one flat slab.
     Lifting them a step gives the light sections the depth the dark ones got
     for free from the glows. */
  background: var(--surface-raised);
  padding: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  overflow: hidden;
  transition: background-color calc(0.34s * var(--dur)) var(--ease);
}

/* Cursor-tracked wash; --mx/--my written by the pointer handler. */
.card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0;
  background: radial-gradient(20rem circle at var(--mx, 50%) var(--my, 50%),
    rgb(208 1 2 / 0.10), transparent 55%);
  transition: opacity calc(0.31s * var(--dur)) var(--ease);
}
.card:hover { background: var(--surface-hi); }
.card:hover::before { opacity: 1; }

.card__num {
  font-family: var(--font-sans);
  font-size: var(--t-label);
  letter-spacing: 0.24em;
  color: var(--red-on-surface);
  display: block;
  margin-bottom: 1.5rem;
}

.card__title {
  font-size: var(--t-h3);
  margin-bottom: 0.85rem;
  color: var(--text);
}

.card__text { font-size: var(--t-small); line-height: 1.7; color: var(--text-dim); }

.card__meta {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--hairline);
  display: grid;
  gap: 0.6rem;
}

.card__row { display: flex; justify-content: space-between; gap: 1rem; font-size: var(--t-small); }
.card__row dt { color: var(--text-faint); }
.card__row dd { color: var(--text); }

/* Numbered process list */
.steps { border-top: 1px solid var(--hairline); }

.step {
  display: grid;
  gap: 0.75rem 2.5rem;
  padding-block: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  border-bottom: 1px solid var(--hairline);
  transition: background-color calc(0.34s * var(--dur)) var(--ease);
}
@media (min-width: 800px) {
  .step { grid-template-columns: 5rem minmax(0, 20rem) minmax(0, 1fr); align-items: baseline; }
}
.step:hover { background: var(--surface-raised); }

.step__num {
  font-family: var(--font-sans);
  font-size: var(--t-label);
  letter-spacing: 0.24em;
  color: var(--red-on-surface);
}
.step__title { font-size: var(--t-h3); color: var(--text); }
.step__text { font-size: var(--t-small); line-height: 1.75; color: var(--text-dim); }

/* Definition rows — a two-column hairline table */
.deflist { border-top: 1px solid var(--hairline); }
.deflist__row {
  display: grid;
  gap: 0.35rem 2rem;
  padding-block: 1.35rem;
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 700px) {
  .deflist__row { grid-template-columns: minmax(0, 14rem) minmax(0, 1fr); align-items: baseline; }
}
.deflist__term { font-size: var(--t-label); letter-spacing: 0.2em; text-transform: uppercase; color: var(--text-faint); }
.deflist__desc { color: var(--text); }

/* Pull quote */
.quote { position: relative; padding-left: clamp(1.5rem, 4vw, 4rem); }
.quote::before {
  content: "\201C";
  position: absolute;
  left: 0;
  top: -0.35em;
  font-family: var(--font-display);
  font-size: clamp(4rem, 2rem + 8vw, 9rem);
  line-height: 1;
  color: var(--red-on-surface);
  opacity: 0.5;
}
.quote__text {
  /* This is a <p>, not a heading, so it does not inherit the display face from
     the h1-h4 rule — it must ask for it. Without this the pull quote rendered
     in Inter Light at h2 size, which is the one place a sans at that size looks
     obviously wrong in a Didone-led layout. */
  font-family: var(--font-display);
  font-size: var(--t-h2);
  line-height: 1.12;
  color: var(--text);
}
.quote__attr { margin-top: 2rem; font-size: var(--t-label); letter-spacing: 0.2em; text-transform: uppercase; color: var(--text-faint); }

/* --------------------------------------------------------------------------
   10. Marquee
   -------------------------------------------------------------------------- */
.marquee {
  position: relative;
  overflow: hidden;
  padding-block: clamp(1.5rem, 1rem + 1.5vw, 2.25rem);
  border-block: 1px solid var(--hairline);
  mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}

.marquee__track {
  display: flex;
  width: max-content;
  align-items: center;
  gap: clamp(2.5rem, 5vw, 5rem);
  /* Position is driven by JS, not a CSS animation. Modulating speed by writing
     animation-duration restarts the animation's timing every frame, which is
     what made the ticker visibly jump. A transform loop can change speed
     continuously without ever resetting. */
  will-change: transform;
}

/* Deliberately no pause-on-hover: the ticker reads as a live feed, and stopping
   it under the cursor made it feel broken rather than interactive. */

.marquee__item {
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 0.9rem + 0.9vw, 1.75rem);
  color: var(--text-faint);
  white-space: nowrap;
  transition: color calc(0.27s * var(--dur)) var(--ease);
}
.marquee__item:hover { color: var(--text); }

.marquee__dot { color: var(--red-on-surface); flex-shrink: 0; }

/* --------------------------------------------------------------------------
   11. Team
   -------------------------------------------------------------------------- */
.team { display: grid; gap: 1px; background: var(--hairline); border: 1px solid var(--hairline); }
/* minmax(0, 1fr), never a bare 1fr: a grid item will not shrink below its
   min-content width, and at 900px the three partner cards did exactly that --
   they overran the row by 32px and put a 1px horizontal scrollbar on the page. */
@media (min-width: 800px) { .team { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.person {
  background: var(--surface-raised);
  padding: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
  transition: background-color calc(0.34s * var(--dur)) var(--ease);
}
.person:hover { background: var(--surface-hi); }

.person__role {
  font-size: var(--t-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--red-on-surface);
}
.person__name { font-size: var(--t-h3); color: var(--text); margin-block: 1.25rem 0.75rem; }
.person__bio { font-size: var(--t-small); line-height: 1.7; color: var(--text-dim); }
.person__contact { margin-top: 1.5rem; }

/* --------------------------------------------------------------------------
   12. Contact / CTA
   -------------------------------------------------------------------------- */
.cta {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-top: 1px solid var(--hairline);
  padding-block: clamp(3.25rem, 2.25rem + 3.5vw, 5.5rem);
  background:
    radial-gradient(120% 140% at 80% 0%, #1d0409 0%, transparent 60%),
    var(--ob-900);
  color: var(--text-dim);
}

.cta::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -60% 15%;
  background: radial-gradient(ellipse at center, rgb(208 1 2 / 0.20), transparent 62%);
  filter: blur(50px);
  animation: bloom-a 20s var(--ease) infinite alternate;
}

.cta__title { font-size: var(--t-h2); margin-block: 1.5rem 1.5rem; }

/* Form */
.form { display: grid; gap: 1.5rem; }
/* display and gap belong on the base rule; only the second column is a
   breakpoint decision. They used to sit inside the media query together, which
   left the stacked mobile form with 8px between fields. */
.form__grid { display: grid; gap: 1.5rem; }
@media (min-width: 700px) { .form__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.field--full { grid-column: 1 / -1; }

.field label {
  display: block;
  font-size: var(--t-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 0.65rem;
}

.input {
  width: 100%;
  padding: 0.9rem 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--hairline-strong);
  color: var(--text);
  font-size: var(--t-body);
  transition: border-color calc(0.24s * var(--dur)) var(--ease);
}
.input::placeholder { color: var(--text-ghost); }
.input:focus { outline: none; border-bottom-color: var(--red); }
/* The line above is the pointer affordance, but it also stripped the ring from
   keyboard focus — .input:focus outranks the bare :focus-visible rule — leaving
   a 1px underline as the only indicator. Put the ring back for keyboard use
   only, so a mouse still gets the clean underline. */
.input:focus-visible { outline: 2px solid var(--red-on-surface); outline-offset: 3px; }
.input[aria-invalid="true"] { border-bottom-color: var(--red-on-surface); }

textarea.input { resize: vertical; min-height: 6rem; }

select.input { cursor: pointer; }
select.input option { background: var(--surface-sunken); color: var(--text); }

/* Says what an optional field is for. Sits between the input and its error slot,
   and is wired to the input through aria-describedby so it is announced too. */
.field__hint {
  display: block;
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--text-faint);
  margin-top: 0.5rem;
}

.field__error {
  display: block;
  font-size: 0.75rem;
  /* Was --red-bright, which is 2.93:1 on the light form ground. The role
     resolves to #d00102 (4.53:1) here and stays bright inside dark zones. */
  color: var(--red-on-surface);
  margin-top: 0.5rem;
  min-height: 0;
  opacity: 0;
  transition: opacity 0.2s var(--ease);
}
.field__error:not(:empty) { opacity: 1; }

/* Honeypot: off-screen rather than display:none, which some bots skip. */
.hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
}

.consent { display: flex; align-items: flex-start; gap: 0.85rem; }
.consent input[type="checkbox"] {
  flex-shrink: 0;
  width: 1.05rem;
  height: 1.05rem;
  margin-top: 0.3rem;
  accent-color: var(--red);
  cursor: pointer;
}
.consent label {
  font-size: var(--t-small);
  line-height: 1.65;
  color: var(--text-faint);
  letter-spacing: 0;
  text-transform: none;
  margin: 0;
  cursor: pointer;
}
.consent a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }

/* The reply and retention statement is NOT part of what the checkbox consents
   to -- the policy answers inquiries on legitimate interest -- so it sits
   outside the label rather than inside it. */
.consent__note {
  margin-top: 0.85rem;
  font-size: var(--t-small);
  line-height: 1.65;
  color: var(--text-faint);
}
.consent__note a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }

.spinner {
  width: 1em;
  height: 1em;
  border: 1px solid rgb(244 241 236 / 0.3);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* The status box is a standing live region, so it is always in the DOM. Hide it
   by emptiness rather than the hidden attribute -- a region toggled in and out
   of the tree announces nothing. */
#form-status:empty { display: none; }

.form-status {
  margin-top: 2rem;
  padding: 1.75rem;
  border: 1px solid var(--hairline-strong);
  animation: rise 0.5s var(--ease-out) both;
}
@keyframes rise { from { opacity: 0; transform: translateY(12px); } }
.form-status--ok { border-left: 2px solid var(--red); }
.form-status--err { border-left: 2px solid var(--red-on-surface); }
.form-status h3 { font-size: var(--t-h3); margin-bottom: 0.75rem; }
.form-status a { color: var(--text); text-decoration: underline; }

/* --------------------------------------------------------------------------
   13. Footer
   -------------------------------------------------------------------------- */
.footer {
  border-top: 1px solid var(--hairline);
  padding-block: clamp(3rem, 2rem + 3vw, 5rem) 2.5rem;
  background: var(--ob-900);
  color: var(--text-dim);
}

.footer__grid { display: grid; gap: 3rem; }
@media (min-width: 720px) { .footer__grid { grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr) minmax(0, 1.35fr); } }

.footer__logo { height: 2rem; width: auto; margin-bottom: 1.5rem; }
.footer__about { font-size: var(--t-small); color: var(--text-faint); max-width: 34ch; line-height: 1.75; }

.footer__heading {
  font-family: var(--font-sans);
  font-size: var(--t-label);
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 1.5rem;
}

.footer__list { display: grid; gap: 0.85rem; font-size: var(--t-small); }
.footer__list a {
  color: var(--text-dim);
  /* info@onyxcapital.partners is one unbreakable token and the contact
     column is narrow. Let it wrap instead of widening the document. */
  overflow-wrap: anywhere;
  transition: color calc(0.2s * var(--dur)) var(--ease);
}
.footer__list a:hover { color: var(--red-bright); }

.footer__bottom {
  margin-top: clamp(3rem, 2rem + 3vw, 4.5rem);
  padding-top: 2rem;
  border-top: 1px solid var(--hairline);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  font-size: var(--t-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-ghost);
}
@media (min-width: 720px) {
  .footer__bottom { flex-direction: row; align-items: center; justify-content: space-between; }
}

.footer__disclaimer {
  margin-top: 2rem;
  font-size: 0.6875rem;
  line-height: 1.8;
  color: var(--text-ghost);
  max-width: 88ch;
  letter-spacing: 0;
  text-transform: none;
}

/* --------------------------------------------------------------------------
   14. Legal pages
   -------------------------------------------------------------------------- */
.prose { max-width: 70ch; }
.prose h2 {
  font-size: var(--t-h3);
  margin-top: 3.5rem;
  margin-bottom: 1rem;
  scroll-margin-top: calc(var(--nav-h) + 2rem);
}
.prose h3 { font-family: var(--font-sans); font-size: 1rem; font-weight: 500; color: var(--text); margin-top: 2rem; margin-bottom: 0.65rem; }
.prose p, .prose li { color: var(--text-dim); line-height: 1.8; }
.prose > p + p, .prose ul { margin-top: 1rem; }
.prose ul { display: grid; gap: 0.6rem; padding-left: 1.35rem; list-style: disc; }
.prose a { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.prose a:hover { color: var(--red-on-surface); }
.prose strong { color: var(--text); font-weight: 500; }
.prose__lede { font-size: var(--t-lede); color: var(--text-dim); margin-bottom: 2.5rem; }

.legal-layout { display: grid; gap: 3rem; }
@media (min-width: 1024px) {
  .legal-layout { grid-template-columns: minmax(0, 1fr) 15rem; align-items: start; }
}

.toc { display: none; }
/* The list is filled by script from the page's own headings, so without JS the
   box renders as a title over an empty bordered rail. */
.no-js .toc { display: none !important; }
@media (min-width: 1024px) {
  .toc { display: block; position: sticky; top: calc(var(--nav-h) + 2rem); }
}
.toc__title { font-size: var(--t-label); letter-spacing: 0.24em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 1rem; }
.toc__list { display: grid; gap: 0.2rem; border-left: 1px solid var(--hairline); }
.toc__list a {
  display: block;
  padding: 0.4rem 0 0.4rem 1rem;
  margin-left: -1px;
  border-left: 1px solid transparent;
  font-size: var(--t-small);
  color: var(--text-faint);
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.toc__list a:hover { color: var(--text); }
.toc__list a.is-active { color: var(--red-on-surface); border-left-color: var(--red); }

/* --------------------------------------------------------------------------
   15. Motion utilities
   -------------------------------------------------------------------------- */

/* Masked line reveal — the signature entrance for display type. Each line sits
   in an overflow-hidden shell and rises into view.

   The mask must be TALLER than the line box or it crops the ink that falls
   below the baseline. So pad the mask, pull the following line back up by the
   same amount to leave the vertical rhythm untouched, and translate the span
   clear of the padding so no sliver peeks out while it is hidden. */
.reveal-line {
  display: block;
  overflow: hidden;
  padding-bottom: var(--lead-room);
  margin-bottom: calc(var(--lead-room) * -1);
}
.reveal-line > span {
  display: block;
  transform: translateY(calc(100% + var(--lead-room)));
  transition: transform calc(0.75s * var(--dur)) var(--ease-out);
  transition-delay: calc(var(--d, 0) * 1ms);
  will-change: transform;
}
.is-visible .reveal-line > span,
.reveal-line.is-visible > span { transform: none; }

[data-reveal] {
  opacity: 0;
  transform: translateY(1.75rem);
  transition: opacity calc(0.61s * var(--dur)) var(--ease-out),
    transform calc(0.61s * var(--dur)) var(--ease-out);
  transition-delay: calc(var(--d, 0) * 1ms);
}
[data-reveal].is-visible { opacity: 1; transform: none; }

[data-reveal="fade"] { transform: none; }
[data-reveal="scale"] { transform: scale(0.97); }
[data-reveal="scale"].is-visible { transform: none; }

/* Left/right slides go vertical on narrow screens: sideways motion in a
   single column both reads oddly and pushes past the viewport edge. */
[data-reveal="left"] { transform: translateX(-2rem); }
[data-reveal="right"] { transform: translateX(2rem); }
@media (max-width: 767px) {
  [data-reveal="left"], [data-reveal="right"] { transform: translateY(1.75rem); }
}

/* If JS never runs, nothing may stay invisible. */
.no-js [data-reveal] { opacity: 1; transform: none; }
.no-js .reveal-line > span { transform: none; }
/* Same list the reduced-motion block restores. These all start at scale: 0 1
   and are drawn by script, so without JS the page lost every hairline rule,
   every red eyebrow tick and every row separator. */
.no-js .rule,
.no-js [data-line],
.no-js .label--marked::before,
.no-js .deflist__row::after,
.no-js .step::after { scale: 1 1; }
.no-js .steps::after { scale: 1 1; }

/* Addresses and URLs are single unbreakable tokens; wherever one sits in a
   constrained column it must be allowed to break rather than widen the page. */
a[href^="mailto:"], a[href^="tel:"] { overflow-wrap: anywhere; }

.to-top {
  position: fixed;
  right: var(--gutter);
  bottom: 2rem;
  z-index: 90;
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--hairline-strong);
  background: var(--surface-veil);
  backdrop-filter: blur(10px);
  color: var(--text);
  opacity: 0;
  translate: 0 1rem;
  pointer-events: none;
  /* opacity: 0 hides a button but leaves it in the tab order, so keyboard users
     used to land on an invisible "back to top" before it was offered. Only
     visibility (or display) takes it out; it is transitioned with a delay so
     the fade still plays on the way out. */
  visibility: hidden;
  transition: opacity calc(0.27s * var(--dur)) var(--ease),
    translate calc(0.27s * var(--dur)) var(--ease-out),
    border-color calc(0.27s * var(--dur)) var(--ease),
    visibility 0s linear calc(0.27s * var(--dur));
}
.to-top.is-visible {
  opacity: 1;
  translate: 0 0;
  pointer-events: auto;
  visibility: visible;
  transition: opacity calc(0.27s * var(--dur)) var(--ease),
    translate calc(0.27s * var(--dur)) var(--ease-out),
    border-color calc(0.27s * var(--dur)) var(--ease),
    visibility 0s;
}
.to-top:hover { border-color: var(--red); color: var(--red-on-surface); }
.to-top svg { width: 1rem; height: 1rem; }

/* Cursor glow, desktop only */
/* The pointer was a 480px soft red disc trailing the cursor — a lot of colored
   haze for very little meaning. This is a lens instead: a thin ring that
   brightens what is behind it rather than adding light of its own. It reads as
   looking through one of the facets, which is the geometry the whole site is
   built on, and it costs no color. */
.cursor-glow {
  position: fixed;
  top: 0;
  left: 0;
  width: 8.5rem;
  height: 8.5rem;
  margin: -4.25rem 0 0 -4.25rem;
  border-radius: 50%;
  pointer-events: none;
  z-index: 3;
  opacity: 0;
  border: 1px solid rgb(208 1 2 / 0.22);
  box-shadow: 0 0 0 1px rgb(244 241 236 / 0.04) inset;
  -webkit-backdrop-filter: brightness(1.14) saturate(1.28) contrast(1.03);
  backdrop-filter: brightness(1.14) saturate(1.28) contrast(1.03);
  transition:
    opacity 0.45s var(--ease),
    width 0.4s var(--ease-out),
    height 0.4s var(--ease-out),
    margin 0.4s var(--ease-out),
    border-color 0.4s var(--ease);
  will-change: transform;
}
.cursor-glow.is-active { opacity: 1; }

/* Over something you can act on, the lens contracts and its rim sharpens —
   the cursor stops being ambient and starts pointing. */
.cursor-glow.is-live {
  width: 4.25rem;
  height: 4.25rem;
  margin: -2.125rem 0 0 -2.125rem;
  border-color: rgb(255 47 47 / 0.55);
}

/* Backdrop filters are the one thing here that can cost real frames on a weak
   GPU, and they do nothing useful for someone who asked for less motion. */
@media (prefers-reduced-motion: reduce) {
  .cursor-glow { display: none; }
}


/* --------------------------------------------------------------------------
   17. Utilities
   Exist so pages need no inline style attributes, which in turn lets the
   Content-Security-Policy drop 'unsafe-inline' for styles entirely.
   -------------------------------------------------------------------------- */
.mt-sm { margin-top: 1rem; }
.mt-md { margin-top: 1.5rem; }
.mt-lg { margin-top: 2rem; }
.mt-xl { margin-top: 2.5rem; }
.mb-lg { margin-bottom: 2rem; }
.measure-52 { max-width: 52ch; }
.label--center { justify-content: center; }
/* BEM base for the sticky modifier; min-width:0 also stops a long child from
   blowing out the grid column it sits in. */
.split__aside { min-width: 0; }
.flow > * + * { margin-top: 1.5rem; }

/* Menu rows cascade in; done with nth-child rather than an inline --i so the
   markup stays attribute-free. */
.menu.is-open .menu__item:nth-child(1) { transition-delay: calc(40ms * var(--dur)); }
.menu.is-open .menu__item:nth-child(2) { transition-delay: calc(100ms * var(--dur)); }
.menu.is-open .menu__item:nth-child(3) { transition-delay: calc(160ms * var(--dur)); }
.menu.is-open .menu__item:nth-child(4) { transition-delay: calc(220ms * var(--dur)); }
.menu.is-open .menu__item:nth-child(5) { transition-delay: calc(280ms * var(--dur)); }
.menu.is-open .menu__item:nth-child(6) { transition-delay: calc(340ms * var(--dur)); }
.menu.is-open .menu__item:nth-child(7) { transition-delay: calc(400ms * var(--dur)); }


/* --------------------------------------------------------------------------
   18. Typographic detail on the remaining display elements
   -------------------------------------------------------------------------- */
.stat__value { line-height: 1.02; }
.quote__text { line-height: 1.16; }
.page-hero__title { line-height: var(--lh-display); }
/* Figures in a statistic must be lining and tabular, so a column of them
   aligns and none of them drop below the baseline. */
.stat__value,
.numeral,
.card__row dd { font-variant-numeric: tabular-nums lining-nums; }

/* --------------------------------------------------------------------------
   19. Motion
   -------------------------------------------------------------------------- */

/* The red tick draws itself in. It sits before every section label on the
   site, so this one rule animates the brand's most repeated gesture. */
.label--marked::before {
  transform-origin: left;
  scale: 0 1;
  transition: scale calc(0.51s * var(--dur)) var(--ease-out);
  transition-delay: calc((var(--d, 0) + 120) * 1ms);
}
.label--marked.is-visible::before,
.is-visible .label--marked::before { scale: 1 1; }

/* Hairlines wipe in rather than appearing. Rules are the structural motif, so
   drawing them is the most on-brand motion available. */
.rule,
[data-line] {
  transform-origin: left;
  scale: 0 1;
  transition: scale calc(0.75s * var(--dur)) var(--ease-out);
  transition-delay: calc(var(--d, 0) * 1ms);
}
.rule.is-visible,
[data-line].is-visible { scale: 1 1; }

/* Rows in the hairline tables draw their own underline as they arrive. */
.deflist__row,
.step {
  position: relative;
  border-bottom-color: transparent;
}
.deflist__row::after,
.step::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: var(--hairline);
  transform-origin: left;
  scale: 0 1;
  transition: scale calc(0.61s * var(--dur)) var(--ease-out);
  transition-delay: calc(var(--d, 0) * 1ms);
}
.deflist__row.is-visible::after,
.step.is-visible::after { scale: 1 1; }

/* Blur-in variant — used sparingly, on the single most important block of a
   page, because it is the most expensive reveal to composite. */
[data-reveal="blur"] {
  opacity: 0;
  filter: blur(14px);
  transform: translateY(1.25rem) scale(1.01);
  transition: opacity calc(0.68s * var(--dur)) var(--ease-out),
    filter calc(0.75s * var(--dur)) var(--ease-out),
    transform calc(0.75s * var(--dur)) var(--ease-out);
  transition-delay: calc(var(--d, 0) * 1ms);
}
[data-reveal="blur"].is-visible {
  opacity: 1;
  filter: blur(0);
  transform: none;
}

/* Parallax. --py is written by the scroll handler; the facet marks and the
   hero copy drift at different rates so the header gains depth as it leaves. */
.facets__mark { will-change: transform; }
.hero .facets { transform: translate3d(0, calc(var(--py, 0) * 0.18px), 0); }
.hero__inner {
  transform: translate3d(0, calc(var(--py, 0) * 0.06px), 0);
  /* Tuned so the copy is still ~two-thirds opaque when the header is two-thirds
     visible, and only reaches zero once it has actually left the viewport.
     The first value faded it to half while it was still plainly on screen. */
  opacity: calc(1 - var(--py, 0) * 0.0011);
}

/* Cards tilt fractionally toward the cursor. Kept under a degree — any more
   reads as a gimmick on a firm like this. */
.card,
.person {
  transform: perspective(900px)
    rotateX(calc(var(--ry, 0) * -0.9deg))
    rotateY(calc(var(--rx, 0) * 0.9deg));
  transform-style: preserve-3d;
  transition: transform calc(0.34s * var(--dur)) var(--ease-out),
    background-color calc(0.34s * var(--dur)) var(--ease);
}

/* Magnetic buttons: JS writes the offset, CSS owns the easing so the snap-back
   is smooth when the pointer leaves. */
[data-magnetic] {
  transition: transform calc(0.31s * var(--dur)) var(--ease-out),
    color calc(0.31s * var(--dur)) var(--ease),
    border-color calc(0.31s * var(--dur)) var(--ease);
}

/* Marquee speed responds to scroll velocity — it drifts at rest and pushes
   along as the page moves. */

/* Page transition. Only ever shown by JS, so a failure to load leaves an
   invisible, inert overlay rather than a black screen. */
.page-fade {
  position: fixed;
  inset: 0;
  z-index: 200;
  /* Always obsidian, never the themed surface — the transition should read as
     the brand closing over the page, not as the page fading out. */
  background: var(--ob-900);
  pointer-events: none;
  /* A wipe up from the baseline rather than a dissolve, matching the button
     fill and the masked line reveals so the whole site moves one way. */
  transform: translateY(101%);
  transition: transform calc(0.4s * var(--dur)) var(--ease-in-out);
}
html.is-leaving .page-fade { transform: translateY(0); }

/* Scroll cue retreats once the visitor has taken the hint. */
.scroll-cue {
  transition: opacity calc(0.34s * var(--dur)) var(--ease),
    transform calc(0.34s * var(--dur)) var(--ease-out);
}
html.has-scrolled .scroll-cue {
  opacity: 0;
  transform: translateY(1rem);
  pointer-events: none;
}


/* --------------------------------------------------------------------------
   20. Refinements
   -------------------------------------------------------------------------- */

/* The facet device as a watermark. Encoded as a background so the brand mark
   can appear on any surface without adding markup to nine pages. */
.cta::after {
  content: "";
  position: absolute;
  z-index: -1;
  right: -6rem;
  top: 50%;
  translate: 0 -50%;
  width: min(34rem, 55vw);
  aspect-ratio: 1;
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20200%20200%22%20fill%3D%22none%22%20stroke%3D%22%23d00102%22%20stroke-width%3D%220.6%22%3E%3Cpath%20d%3D%22M100%208%20L128%2040%20L160%2040%20L160%2072%20L192%20100%20L160%20128%20L160%20160%20L128%20160%20L100%20192%20L72%20160%20L40%20160%20L40%20128%20L8%20100%20L40%2072%20L40%2040%20L72%2040%20Z%22%2F%3E%3Cpath%20d%3D%22M100%2030%20L124%2054%20L146%2054%20L146%2076%20L170%20100%20L146%20124%20L146%20146%20L124%20146%20L100%20170%20L76%20146%20L54%20146%20L54%20124%20L30%20100%20L54%2076%20L54%2054%20L76%2054%20Z%22%2F%3E%3Ccircle%20cx%3D%22100%22%20cy%3D%22100%22%20r%3D%2242%22%2F%3E%3Cpath%20d%3D%22M100%208%20V58%20M192%20100%20H142%20M100%20192%20V142%20M8%20100%20H58%22%2F%3E%3Cpath%20d%3D%22M40%2040%20L72%2072%20M160%2040%20L128%2072%20M160%20160%20L128%20128%20M40%20160%20L72%20128%22%2F%3E%3C%2Fsvg%3E");
  background-size: contain;
  background-repeat: no-repeat;
  opacity: 0.16;
  animation: facet-turn 120s linear infinite;
  pointer-events: none;
}

/* Process rail. The steps get a hairline spine that fills as the list passes
   through the viewport — the reader can see how far through the sequence they
   are without a scrollbar telling them. */
@media (min-width: 800px) {
  .steps {
    position: relative;
    padding-left: 2.5rem;
  }

  .steps::before,
  .steps::after {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: 1px;
  }

  .steps::before {
    bottom: 0;
    background: var(--hairline);
  }

  .steps::after {
    height: 100%;
    background: linear-gradient(var(--red), var(--red-deep));
    transform-origin: top;
    scale: 1 var(--steps-progress, 0);
  }
}

/* Hover states gain a hairline shift as well as a surface shift — two quiet
   signals read as more considered than one loud one. */
.card,
.person {
  border-color: transparent;
  transition: transform calc(0.34s * var(--dur)) var(--ease-out),
    background-color calc(0.34s * var(--dur)) var(--ease),
    box-shadow calc(0.34s * var(--dur)) var(--ease);
}

.card:hover,
.person:hover {
  box-shadow: 0 1px 0 var(--red) inset;
}

/* Links inside body copy get the same wipe the standalone .link has. */
.card__text a,
.step__text a,
.deflist__desc a {
  color: var(--text);
  box-shadow: 0 1px 0 var(--hairline-strong);
  transition: box-shadow calc(0.27s * var(--dur)) var(--ease),
    color calc(0.27s * var(--dur)) var(--ease);
}
.card__text a:hover,
.step__text a:hover,
.deflist__desc a:hover {
  color: var(--red-on-surface);
  box-shadow: 0 1px 0 var(--red);
}


/* --------------------------------------------------------------------------
   21. Page-signature components
   Every page currently runs the same sequence: page-hero, section-head + grid,
   repeat, CTA. These exist so each page can have one structural moment that no
   other page uses — a spine of its own rather than a shared template.
   Use ONE per page. They stop working the moment they are everywhere.
   -------------------------------------------------------------------------- */

/* A single dominant figure. For a page whose whole argument rests on one
   number — an advance rate, a fee, a timeframe. */
.figure {
  display: grid;
  gap: clamp(1.5rem, 1rem + 2vw, 3rem);
  align-items: center;
}
@media (min-width: 800px) {
  .figure { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
}

.figure__value {
  font-family: var(--font-display);
  font-size: clamp(5rem, 2rem + 14vw, 14rem);
  line-height: 0.86;
  letter-spacing: -0.045em;
  color: var(--text);
  font-variant-numeric: lining-nums tabular-nums;
}

.figure__value sup {
  font-size: 0.34em;
  vertical-align: super;
  letter-spacing: -0.01em;
  color: var(--red-on-surface);
}

.figure__label {
  font-size: var(--t-lede);
  line-height: 1.5;
  color: var(--text-dim);
  max-width: 34ch;
}

.figure__note {
  margin-top: 1.25rem;
  font-size: var(--t-small);
  color: var(--text-faint);
  max-width: 40ch;
}

/* A compact card: name, a figure, one line. For dense reference grids where
   the standard card's prose would be padding. */
.card--compact {
  padding: clamp(1.1rem, 0.9rem + 0.8vw, 1.5rem);
}

.card--compact .card__title {
  font-size: var(--t-h3);
  margin-bottom: 0.35rem;
}

.card--compact .card__figure {
  display: block;
  font-family: var(--font-sans);
  font-size: var(--t-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--red-on-surface);
  margin-bottom: 0.9rem;
}

.card--compact .card__text {
  font-size: var(--t-small);
  color: var(--text-faint);
  line-height: 1.5;
}

/* A full-bleed statement band. One line, set large, on obsidian — a hard stop
   in the middle of a light page. Pair with .section--dark. */
/* --------------------------------------------------------------------------
   Horizon — the private equity page's signature.

   That page argues the holding period IS the product ("Capital measured in
   years, not quarters"), so its opening section gets a horizon rather than a
   list: three markers hanging from one continuous hairline. It also fixes the
   composition problem underneath the centered head — a single left-aligned
   sentence under a centered three-line display heading read as a mistake, and
   left a 721px band carrying 28 words.
   -------------------------------------------------------------------------- */
.horizon {
  margin-top: clamp(3rem, 2rem + 3vw, 5rem);
  display: grid;
  gap: 0;
}

.horizon__mark {
  position: relative;
  border-top: 1px solid var(--hairline-strong);
  padding: 1.9rem 0 2rem;
}

/* The tick that pins each marker to the line. */
.horizon__mark::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1.15rem;
  background: var(--red-on-surface);
}

.horizon__when {
  display: block;
  font-size: var(--t-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--red-on-surface);
  margin-bottom: 0.8rem;
}

.horizon__what {
  color: var(--text-dim);
  max-width: 34ch;
  line-height: 1.65;
}

@media (min-width: 800px) {
  /* One unbroken rule across the row, with the three ticks hanging from it —
     so the border moves off the marks and onto the row itself. */
  .horizon {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: clamp(2rem, 4vw, 4.5rem);
    border-top: 1px solid var(--hairline-strong);
  }
  .horizon__mark { border-top: 0; padding-bottom: 0; }
}

.statement {
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 1rem + 3.4vw, 3.25rem);
  line-height: 1.14;
  letter-spacing: -0.02em;
  color: var(--text);
  max-width: 24ch;
}

.statement__attr {
  margin-top: clamp(1.5rem, 1rem + 1.5vw, 2.5rem);
  font-size: var(--t-label);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* The dark band needs its own ground now that the page is light. */
.section--dark {
  background:
    radial-gradient(110% 130% at 85% 0%, #1d0409 0%, transparent 62%),
    var(--ob-900);
  color: var(--text-dim);
}


/* --------------------------------------------------------------------------
   22. Hero variants
   All five inner pages opened with the identical block: label, headline, lede.
   These give each page a different opening shape. One per page.
   -------------------------------------------------------------------------- */

.page-hero__grid { display: grid; gap: clamp(2rem, 1.2rem + 3vw, 4rem); }

/* Headline against a supporting column — for a page with one number or claim
   worth stating before the reader scrolls. */
@media (min-width: 900px) {
  .page-hero--split .page-hero__grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
    align-items: end;
  }
}

/* A key/value strip under the headline — the facts a qualified reader is
   scanning for, before any prose. */
.hero-meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  margin-top: clamp(2rem, 1.4rem + 2vw, 3rem);
  background: var(--hairline);
  border: 1px solid var(--hairline);
}
@media (min-width: 760px) {
  .hero-meta { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.hero-meta > div {
  background: var(--surface);
  padding: clamp(0.9rem, 0.7rem + 0.6vw, 1.25rem);
}

.hero-meta dt {
  font-size: var(--t-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 0.45rem;
}

.hero-meta dd {
  font-family: var(--font-display);
  font-size: var(--t-h3);
  color: var(--text);
  line-height: 1.1;
}

/* A numbered contents list in the hero — states what the page covers without
   a paragraph explaining that the page covers it. */
.hero-index { display: grid; gap: 0; margin-top: 0.5rem; }

.hero-index li {
  border-top: 1px solid var(--hairline);
  font-size: var(--t-small);
  color: var(--text-dim);
}
.hero-index li:last-child { border-bottom: 1px solid var(--hairline); }

/* The list used to be four inert lines for a six-section page. It is the page's
   table of contents, so every row is now a link to the band it names, and the
   whole row is the target rather than the words in it. */
.hero-index a {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding-block: 0.7rem;
  color: inherit;
  transition: color calc(0.22s * var(--dur)) var(--ease);
}
.hero-index a:hover { color: var(--text); }
.hero-index a:hover b { color: var(--red-bright); }

.hero-index b {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--t-label);
  letter-spacing: 0.18em;
  color: var(--red-on-surface);
  flex-shrink: 0;
}

/* Wide opening — the headline runs the full measure and the lede drops into the
   same column the section-head rail uses, so the page opens on typography rather
   than on a two-column layout like the others. */
.page-hero--wide .page-hero__title { max-width: 20ch; }

@media (min-width: 900px) {
  .page-hero--wide .page-hero__lede {
    margin-left: 27.3%;
    max-width: 46ch;
  }
}

/* Statement opening — an oversized line carrying the page alone, no lede. */
.page-hero--statement .page-hero__title { font-size: var(--t-h1); max-width: 18ch; }

/* Compact opening — for a page whose job starts below the fold. */
.page-hero--compact {
  padding-top: calc(var(--nav-h) + clamp(1.75rem, 1.25rem + 2vw, 3rem));
  padding-bottom: clamp(1.75rem, 1.25rem + 1.5vw, 2.5rem);
}
.page-hero--compact .page-hero__title { font-size: var(--t-h2); }

/* --------------------------------------------------------------------------
   23. Mid-page tone
   The light build ran one flat stone tone from the hero to the CTA. These give
   the middle of a page somewhere to change temperature.
   -------------------------------------------------------------------------- */

/* Warm clay — a lighter change of tone that keeps the page light. */
.section--accent {
  background: var(--surface-accent);
  border-block: 1px solid var(--hairline);
}

/* A dark band mid-page. Components inside inherit the dark roles automatically,
   so stats, figures and step lists all invert without their own overrides. */
.section--dark .stat:hover { background: var(--surface-raised); }

/* The band carries the red bloom the hero has, so the middle of the page gets
   actual color rather than only a value change. */
.section--dark::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(80% 120% at 15% 0%, rgb(208 1 2 / 0.22), transparent 60%);
  pointer-events: none;
}

.section--dark { position: relative; isolation: isolate; }

/* --------------------------------------------------------------------------
   16. Motion & print
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   21. Touch and small-screen ergonomics

   The layout above is authored mobile-first, so this section is not a phone
   stylesheet. It carries only the corrections layout cannot make on its own:
   hit areas that fall below the touch minimum once a label is hidden, and the
   16px field floor that stops iOS Safari zooming the page on focus.
   -------------------------------------------------------------------------- */

/* iOS Safari zooms into any control whose text is under 16px, then leaves the
   page zoomed. --t-body bottoms out at 15px, so raise the floor for form
   controls only; body copy keeps the scale it was designed at. */
.input { font-size: max(1rem, var(--t-body)); }

/* Below 480px the toggle drops its "Menu" label and the two bars are all that
   is left — 24px wide. Pad the hit area out to 44px, then pull the padding
   back off the layout so the icon stays optically flush with the gutter. */
@media (max-width: 479px) {
  .nav__toggle { padding-inline: 0.625rem; margin-right: -0.625rem; }
}

/* Footer and legal links are 16-19px tall on their own. Give each one a row
   to be tapped in and take the added height back out of the list gap, so the
   vertical rhythm is unchanged and only the target grows. */
@media (max-width: 767px) {
  .footer__list { gap: 0; }
  .footer__list a { display: block; padding-block: 0.62rem; }
  .footer__bottom a { display: inline-block; padding-block: 0.5rem; }
}

/* A 17px checkbox is under every touch guideline going. */
/* 24px is the WCAG 2.2 minimum target, and the box is the one part of this
   control that is not covered by the label. */
.consent input[type="checkbox"] { width: 1.5rem; height: 1.5rem; margin-top: 0.1rem; }

/* Two buttons of different widths stacked one above the other read as an
   accident rather than a choice. Match them where they stack. */
@media (max-width: 559px) {
  .hero__actions { flex-direction: column; align-items: stretch; }
  .hero__actions .btn { justify-content: center; width: 100%; }
}

/* A phone held sideways is ~360px tall. The hero still needs its full content
   height, so the cue — anchored to the bottom of the hero — lands level with
   the buttons and overlaps them. It is decorative and already below the fold
   at that height, so drop it rather than fight it. */
@media (max-height: 560px) and (orientation: landscape) {
  .scroll-cue { display: none; }
}

/* Touch devices have no hover, so a tap leaves the :hover state latched on the
   last thing touched — a card that stays lit long after you have scrolled past
   it. Hold the resting appearance where the pointer cannot leave. */
@media (hover: none) {
  .card:hover, .person:hover { background: var(--surface-raised); box-shadow: none; }
  .card:hover::before { opacity: 0; }
  .footer__list a:hover { color: var(--text-dim); }
  .toc__list a:hover { color: var(--text-faint); }
  .toc__list a.is-active:hover { color: var(--red-on-surface); }
}

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

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

  /* Reveals must never leave content stranded off-screen or invisible. */
  [data-reveal] { opacity: 1 !important; transform: none !important; filter: none !important; }
  .reveal-line > span { transform: none !important; }
  .cursor-glow, .grain, .page-fade { display: none; }
  .facets__mark, .facets__glow { animation: none; }

  /* Hairlines and the red tick must still be drawn, just not animated. */
  .rule, [data-line],
  .label--marked::before,
  .deflist__row::after, .step::after { scale: 1 1 !important; }

  /* The ticker's motion is supplied entirely by script, which does not run in
     this mode -- leaving a max-content track inside overflow: hidden, so every
     sector past the first screenful was unreachable. Let it scroll by hand. */
  .marquee { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .marquee::before, .marquee::after { display: none; }

  /* No parallax, no tilt, no velocity coupling. */
  .hero .facets, .hero__inner, .card, .person, [data-magnetic] {
    transform: none !important;
    opacity: 1 !important;
  }
  .steps::after { scale: 1 1 !important; }
  .cta::after { animation: none !important; }
  .page-fade { transform: translateY(101%) !important; }
  .scroll-cue { opacity: 1 !important; transform: none !important; }
}

@media print {
  /* The dark zones carry their own grounds now, so printing without this
     produced solid obsidian blocks for the hero, CTA and footer — unreadable,
     and it empties a toner cartridge. Redefining the roles makes every
     component follow, rather than chasing them one at a time. Worth getting
     right: the legal pages are the ones people actually print. */
  :root,
  .hero,
  .page-hero,
  .cta,
  .footer,
  .menu,
  .section--dusk,
  .section--dark,
  .section--hi,
  .section--raised,
  .section--accent,
  .nav {
    --surface: #fff;
    --surface-raised: #fff;
    --surface-hi: #fff;
    --surface-sunken: #fff;
    --surface-accent: #fff;
    --surface-veil: #fff;
    /* .section--hi paints from the palette token, not the role, so that one
       has to be flattened here too or the band prints in color. */
    --stone-hi: #fff;
    --text: #000;
    --text-dim: #222;
    --text-faint: #444;
    --text-ghost: #555;
    --hairline: #ccc;
    --hairline-strong: #999;
    --red-on-surface: #000;
    --glow-strength: 0;
  }

  .nav, .menu, .grain, .to-top, .cursor-glow, .progress, .page-fade,
  .facets, .marquee, .scroll-cue { display: none !important; }

  .section--dark::before { display: none !important; }

  .hero, .page-hero, .cta, .footer,
  .section--dusk, .section--dark,
  .section--hi, .section--raised, .section--accent {
    background: #fff !important;
    color: #000 !important;
    min-height: 0 !important;
    padding-block: 1.5rem !important;
  }

  .cta::after,
  .cta::before,
  .hero::before,
  .page-hero::before { display: none !important; }

  body { background: #fff; color: #000; font-size: 11pt; }
  h1, h2, h3, h4 { color: #000 !important; }

  /* Do not strand a heading at the foot of a page, and do not split a card,
     a process step or a definition row across the fold. */
  h1, h2, h3, h4 { break-after: avoid-page; }
  .card, .step, .person, .deflist__row, .stat, .form-status { break-inside: avoid; }
  .prose li { break-inside: avoid; }

  /* Print the destination of real links, but not of same-page anchors or the
     mailto/tel ones where the text already is the address. */
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.8em;
    word-break: break-all;
  }

  @page { margin: 18mm 16mm; }
}
