/* Generated by scripts/fetch-fonts.mjs — do not edit by hand.
   Self-hosted so the site makes no third-party requests on load. */

@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/source-serif-4-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/source-serif-4-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("/fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

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

@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/fonts/jetbrains-mono-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Metric-matched fallbacks: these keep font-display:swap from shifting layout. */
@font-face {
  font-family: "Serif Fallback";
  src: local("Georgia"), local("Times New Roman"), local("Times");
  size-adjust: 97%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}

@font-face {
  font-family: "Sans Fallback";
  src: local("Helvetica Neue"), local("Helvetica"), local("Arial");
  size-adjust: 104%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}


/* ==========================================================================
   Altervest — design system

   THE COLOUR LAW, which governs everything below:
   #00AEEF measures 2.53:1 on white. It fails AA text (4.5:1) and it fails the
   3:1 non-text/UI threshold too. On light grounds it is a DECORATION colour
   only — never a `color`, never a `border-color`, never a focus ring. Light-
   ground text and interactive blue is #17629E (6.41:1); light-ground UI strokes
   are #0099CC (3.27:1). Cyan gets to be loud on navy, where it measures 6.08:1.
   ========================================================================== */

:root {
  /* --- Grounds ------------------------------------------------------------ */
  --navy-900: #061527;              /* footer only */
  --navy-800: #081c34;              /* hero dark stop */
  --navy: #0b2545;                  /* primary dark ground */
  --white: #ffffff;
  --bone: #f7f5f2;                  /* warm off-white; cool greys read clinical */

  /* --- Ink ---------------------------------------------------------------- */
  --ink: #12263a;                   /* 15.4:1 on white */
  --ink-muted: #4a6076;             /* 6.5:1 on white */
  --ink-invert: #ffffff;
  --ink-invert-muted: rgba(255, 255, 255, 0.72);

  /* --- Brand -------------------------------------------------------------- */
  --cyan: #00aeef;                  /* graphics + on-navy text */
  --blue: #1c75bc;                  /* graphics only */
  --cyan-ui: #0099cc;               /* light-ground UI strokes */
  --blue-ink: #17629e;              /* light-ground text + links */

  --grad-brand: linear-gradient(60deg, #081c34 0%, #1c75bc 70%, #00aeef 100%);

  /* --- Surfaces ----------------------------------------------------------- */
  --navy-05: #f2f5f8;
  --hairline-light: rgba(18, 38, 58, 0.11);
  /* Controls, not decoration. --hairline-light composites to #dedede on bone,
     1.24:1, so a field had no boundary until you hovered it. WCAG 1.4.11 wants
     3:1 for the resting state. Asserted in scripts/audit.mjs. */
  --stroke-ui: #7f8a94;              /* 3.23:1 on bone, 3.52:1 on white */
  --hairline-dark: rgba(255, 255, 255, 0.16);

  /* --- Space -------------------------------------------------------------- */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px;
  --s7: clamp(2.5rem, 1.8rem + 2.2vw, 3.5rem);
  --s8: clamp(3.5rem, 2.4rem + 3.4vw, 5rem);
  --s9: clamp(4.5rem, 2.5rem + 6vw, 8rem);

  /* --- Measure ------------------------------------------------------------ */
  --w-page: 1180px;
  --w-wide: 1400px;
  --w-text: 68ch;
  --gutter: clamp(20px, 4vw, 40px);
  --header-h: 88px;
  /* The condensed height. Named because three other rules need it: the anchor
     offset, the white-opening pages' top padding, and .header.is-stuck itself.
     Note --header-h drops to 76px at <=560px while this stays 64. */
  --header-h-stuck: 64px;

  /* --- Type --------------------------------------------------------------- */
  --font-serif: "Source Serif 4", "Serif Fallback", Georgia, serif;
  --font-sans: "Inter", "Sans Fallback", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", monospace;

  --t-display: clamp(2.25rem, 1.45rem + 3.4vw, 4rem);
  --t-h1: clamp(2rem, 1.5rem + 2.1vw, 3rem);
  --t-h2: clamp(1.75rem, 1.35rem + 1.7vw, 2.5rem);
  --t-h3: clamp(1.3rem, 1.15rem + 0.65vw, 1.625rem);
  --t-h4: 1.3125rem;
  --t-lead: clamp(1.15rem, 1.05rem + 0.45vw, 1.4rem);
  --t-body: 1.1875rem;
  --t-sm: 1rem;
  --t-micro: 0.8125rem;
  --t-eyebrow: 0.75rem;

  /* --- Shape -------------------------------------------------------------- */
  /* Every header control resolves to one height, so the language chip and the
     CTA cannot drift apart again. 46px is .btn's natural height and clears the
     44px tap minimum. */
  --control-h: 46px;

  --radius: 2px;
  --shadow-hover: 0 10px 24px -12px rgba(11, 37, 69, 0.28);

  /* --- Motion. Three curves; no control point above y=1, so nothing bounces. */
  --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);

  --dur-instant: 120ms;
  --dur-press: 120ms;
  --dur-hover: 180ms;
  --dur-ui: 260ms;
  --dur-reveal: 520ms;
  --dur-hero: 720ms;
  --dur-draw: 900ms;
  --dur-build: 1000ms;
  --stagger: 90ms;
  --reveal-y: 20px;
}

/* Layer 1 of the reduced-motion handling: zero the tokens, so every duration
   and offset derived from them collapses without touching a single rule. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: 0ms; --dur-hover: 0ms; --dur-ui: 0ms;
    /* The press stays, only its ramp goes: feedback is a state change, not motion. */
    --dur-press: 0ms;
    --dur-reveal: 0ms;  --dur-hero: 0ms;  --dur-draw: 0ms;
    --dur-build: 0ms;
    --stagger: 0ms;     --reveal-y: 0px;
  }
}

/* ==========================================================================
   Reset
   ========================================================================== */

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

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

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

body {
  margin: 0;
  background: var(--white);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--t-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, p, figure, blockquote, ul, ol, dl { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img, svg, picture { display: block; max-width: 100%; }
img { height: auto; }
button { font: inherit; color: inherit; }
address { font-style: normal; }

/* Anything a fragment link or the scrollspy focuses must clear the sticky
   header, or the header eats the element the user was sent to. */
:target, [id] { scroll-margin-top: calc(var(--header-h-stuck) + var(--s5)); }

/* A focus ring that survives white, bone, navy AND photography: two tones with
   a white separator, so one of the three is always visible. */
:focus-visible {
  outline: 2px solid var(--cyan-ui);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--white), 0 0 0 6px var(--navy);
  border-radius: var(--radius);
}

.on-navy :focus-visible,
.menu :focus-visible,
.footer :focus-visible,
.header:not(.is-stuck) :focus-visible,
.section--navy :focus-visible {
  box-shadow: 0 0 0 4px var(--navy), 0 0 0 6px var(--white);
}

.u-visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  top: var(--s3); left: var(--s3);
  z-index: 200;
  padding: var(--s3) var(--s5);
  background: var(--white);
  color: var(--ink);
  font-size: var(--t-sm);
  text-decoration: none;
  transform: translateY(-200%);
}

.skip-link:focus { transform: none; }

/* ==========================================================================
   Type
   ========================================================================== */

h1, h2, h3, .u-serif {
  font-family: var(--font-serif);
  font-weight: 400;
  text-wrap: balance;
}

h1 { font-size: var(--t-h1); line-height: 1.08; letter-spacing: -0.012em; }
h2 { font-size: var(--t-h2); line-height: 1.12; letter-spacing: -0.01em; }
h3 { font-size: var(--t-h3); line-height: 1.2; }

h4 {
  font-family: var(--font-sans);
  font-size: var(--t-h4);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.005em;
}

p { text-wrap: pretty; }

.lead {
  font-size: var(--t-lead);
  line-height: 1.55;
  color: var(--ink-muted);
}

.prose { max-width: var(--w-text); }
.prose p + p { margin-top: var(--s5); }

.eyebrow {
  display: inline-block;
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  font-weight: 500;
  letter-spacing: 0.14em;
  line-height: 1.2;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.section--navy .eyebrow { color: var(--cyan); }

/* The 3px gradient rule that sits under every section eyebrow. Its scaleX draw
   is the smallest recurring motion on the site and the one that ties the
   sections together. */
.eyebrow-rule {
  display: block;
  width: 56px;
  height: 3px;
  margin-top: var(--s3);
  background: var(--grad-brand);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-reveal) var(--ease-out-quart) 120ms;
}

/* Sections that keep the firm's own heading carry the rule alone. */
.eyebrow-rule--bare { margin-top: 0; margin-bottom: var(--s5); }

.is-in .eyebrow-rule,
.eyebrow-rule.is-in { transform: scaleX(1); }

/* The start state above sits outside the `.js` scope, so the head failsafe that
   strips `.js` cannot reach it: with JS off, blocked or broken, every rule on
   every page stayed at scaleX(0). Same escape hatch as .hero__line > span. */
html:not(.js) .eyebrow-rule { transform: none; }

/* When the heading itself is set at eyebrow scale, the mono/uppercase
   treatment has to beat the h1–h3 serif rule that would otherwise win. */
h2.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  font-weight: 500;
  letter-spacing: 0.14em;
  line-height: 1.2;
  text-transform: uppercase;
}

/* Every figure, date and phone number aligns down a column. */
.num, time, .tel {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1;
}

/* ==========================================================================
   Links and buttons
   ========================================================================== */

a { color: inherit; }

/* The underline wipes in rather than switching colour — the Pictet move. */
.link,
.prose a,
.footer__col a,
.contact__list a {
  color: var(--blue-ink);
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 1px;
  transition: background-size 250ms ease-in-out;
}

.link:hover, .link:focus-visible,
.prose a:hover, .prose a:focus-visible,
.footer__col a:hover, .footer__col a:focus-visible,
.contact__list a:hover, .contact__list a:focus-visible { background-size: 100% 1px; }

.on-navy .link,
.section--navy .prose a,
.footer__col a { color: var(--cyan); }

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--s3);
  padding: 14px 28px;
  /* min-, not height: .btn--lg computes to 54px and must keep growing. */
  min-height: var(--control-h);
  border: 1px solid currentColor;
  border-radius: var(--radius);
  font-family: var(--font-sans);
  font-size: var(--t-sm);
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  background: transparent;
  transition:
    background-color var(--dur-hover) var(--ease-out-quart),
    color var(--dur-hover) var(--ease-out-quart),
    transform var(--dur-press) var(--ease-out-quart);
}

.btn--lg { padding: 18px 36px; }

/* On light grounds: ink outline, fills to ink. */
.btn--solid { color: var(--ink); }
.btn--solid:hover,
.btn--solid:focus-visible { background: var(--ink); color: var(--white); }

/* On navy: white outline, fills to white. Never a brand-colour fill — cyan
   behind white text would be 2.5:1. */
.on-navy .btn--solid,
.section--navy .btn--solid,
.menu .btn--solid,
.footer .btn--solid { color: var(--white); }

.on-navy .btn--solid:hover,
.on-navy .btn--solid:focus-visible,
.section--navy .btn--solid:hover,
.section--navy .btn--solid:focus-visible,
.menu .btn--solid:hover,
.menu .btn--solid:focus-visible,
.footer .btn--solid:hover,
.footer .btn--solid:focus-visible { background: var(--white); color: var(--navy); }

.btn--ghost { color: var(--ink-muted); border-color: var(--stroke-ui); }
.btn--ghost:hover { color: var(--ink); border-color: currentColor; }

/* Press. On a phone hover never fires, so without this nothing on the site
   acknowledges being touched. .btn:disabled matters as much: main.js disables
   the submit while the post is in flight, and .btn sets an explicit colour over
   a transparent ground, so the browser's own disabled greying never lands and
   the button looked identical mid-send. */
.btn:active { transform: scale(0.98); }
.btn:disabled { opacity: 0.6; cursor: wait; transform: none; }
.btn:disabled .btn__arrow { transform: none; }
.burger:active { transform: scale(0.94); }
.provider__link:active { transform: scale(0.99); }
.link:active,
.prose a:active,
.footer__col a:active { opacity: 0.7; }

.btn__arrow { transition: transform var(--dur-hover) var(--ease-out-quart); }
.btn:hover .btn__arrow { transform: translateX(3px); }

/* ==========================================================================
   Layout
   ========================================================================== */

.container { width: 100%; max-width: var(--w-page); margin-inline: auto; padding-inline: var(--gutter); }
.container--wide { max-width: var(--w-wide); }

.section { padding-block: var(--s9); }
.section--white { background: var(--white); }
.section--bone { background: var(--bone); }

.section--navy {
  background: var(--navy);
  color: var(--ink-invert);
}

.section--navy .lead,
.section--navy p { color: var(--ink-invert-muted); }
.section--navy h1, .section--navy h2, .section--navy h3 { color: var(--ink-invert); }

.section__head { max-width: var(--w-text); margin-bottom: var(--s8); }
.section__head h2 { margin-top: var(--s5); }
.section__head .eyebrow-rule--bare + h2 { margin-top: 0; }
.section__head .lead { margin-top: var(--s5); }

/* Hairlines are inset to the text column and tinted navy rather than grey; a
   full-bleed #ddd rule is what makes a page look like a spreadsheet. */
.rule { height: 1px; background: var(--hairline-light); border: 0; margin: 0; }
.section--navy .rule { background: var(--hairline-dark); }

/* ==========================================================================
   Motion — M2 rise / M3 stagger
   The opacity:0 lives inside a .js scope set by an inline head script, so a
   failed or blocked script can never leave the page blank.
   ========================================================================== */

.js .reveal {
  opacity: 0;
  transform: translate3d(0, var(--reveal-y), 0);
  transition:
    opacity var(--dur-reveal) var(--ease-out-quart),
    transform var(--dur-reveal) var(--ease-out-quart);
  transition-delay: calc(var(--i, 0) * var(--stagger));
  will-change: opacity, transform;
}

.js .reveal.is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* ==========================================================================
   Header — M8 condense
   ========================================================================== */

/* fixed, not sticky. Sticky put the header in flow, so every page cancelled it
   again with a hard-coded negative margin that did NOT follow the animated
   height: condensing 88 -> 64 shortened the document by 24px and slid the first
   section up, on every page, within a second of the visitor starting to scroll.
   Out of flow, the height animates against nothing. */
.header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  background: transparent;
  transition:
    height var(--dur-ui) var(--ease-standard),
    background-color var(--dur-ui) var(--ease-standard),
    box-shadow var(--dur-ui) var(--ease-standard),
    color var(--dur-ui) var(--ease-standard),
    backdrop-filter var(--dur-ui) var(--ease-standard);
}

.header { color: var(--ink-invert); }

/* Pages that open on white ship .is-stuck in the markup and never toggle, so
   they have no dark hero to sit the header over and nothing reclaims the space
   the fixed header no longer occupies. Emitted from the same `solid` flag that
   sets .is-stuck (src/layout.mjs), not patched onto .legal, so a future
   white-opening page cannot regress. */
.has-solid-header main { padding-top: var(--header-h-stuck); }

.header__inner {
  width: 100%;
  max-width: var(--w-wide);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  gap: var(--s6);
}

.header.is-stuck {
  height: var(--header-h-stuck);
  background: rgba(255, 255, 255, 0.92);
  box-shadow: inset 0 -1px 0 var(--hairline-light);
  color: var(--ink);
}

/* 0.72 must never apply where blur is unavailable, or body copy reads through
   the nav. The opaque 0.92 above is the floor; this only lightens it once
   there is a blur to carry the separation. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .header.is-stuck {
    background: rgba(255, 255, 255, 0.72);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    backdrop-filter: blur(20px) saturate(180%);
  }
}

@media (prefers-reduced-transparency: reduce) {
  .header.is-stuck {
    background: var(--white);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}



.header__brand {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  text-decoration: none;
  margin-right: auto;
}

.logo { width: auto; }
.header__logo { height: 34px; transition: height var(--dur-ui) var(--ease-standard); }
.header.is-stuck .header__logo { height: 28px; }

/* Until it condenses, the header floats over navy on every page, so the mark
   takes the light gradient stops and the outline button takes white. */
.header:not(.is-stuck) .logo { --logo-from: #ffffff; --logo-to: #7fd4f5; }

.header:not(.is-stuck) .btn--solid { color: var(--ink-invert); }

.header:not(.is-stuck) .btn--solid:hover,
.header:not(.is-stuck) .btn--solid:focus-visible {
  background: var(--white);
  color: var(--navy);
}

.header:not(.is-stuck) .btn--ghost { color: rgba(255, 255, 255, 0.72); border-color: var(--hairline-dark); }
.header:not(.is-stuck) .btn--ghost:hover { color: var(--ink-invert); border-color: currentColor; }

@media (max-width: 560px) {
  :root { --header-h: 76px; }
  .header__logo { height: 28px; }
  .header__brand { gap: var(--s2); }
}

.nav { display: none; }

@media (min-width: 900px) {
  .nav { display: block; }
  .nav__list { display: flex; gap: var(--s6); }
}

.nav__link {
  position: relative;
  font-size: var(--t-sm);
  font-weight: 500;
  text-decoration: none;
  padding-block: var(--s2);
}

.nav__link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 250ms var(--ease-out-quart);
}

.nav__link:hover::after,
.nav__link:focus-visible::after,
.nav__link.is-current::after { transform: scaleX(1); }

.header__actions { display: flex; align-items: center; gap: var(--s4); }

/* The Loi 96 control, so it does not get to be the weakest thing in the header.
   It was 43.7 x 39.4 beside a 46px button, and `opacity: .75` over the hero sky
   measured 3.38:1 — a band check-scrims.py does not sample. The tint reuses the
   scrim's own navy so it survives the photograph being swapped. */
.langswitch {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--control-h);
  padding-inline: var(--s3);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  font-weight: 500;
  letter-spacing: 0.08em;
  line-height: 1;
  text-decoration: none;
  border: 1px solid currentColor;
  border-radius: var(--radius);
  transition:
    background-color var(--dur-hover) var(--ease-out-quart),
    border-color var(--dur-hover) var(--ease-out-quart);
}

.header:not(.is-stuck) .langswitch {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.45);
  background: rgba(6, 21, 39, 0.28);
}

.header__cta, .header__login { display: none; }

@media (min-width: 900px) {
  .header__cta { display: inline-flex; }
  .header__login { display: inline-flex; }
}

/* --- Burger + slide-in menu ---------------------------------------------- */

.burger {
  display: grid;
  place-items: center;
  transition: transform var(--dur-press) var(--ease-out-quart);
  width: var(--control-h); height: var(--control-h);
  border: 0;
  background: none;
  cursor: pointer;
}

@media (min-width: 900px) { .burger { display: none; } }

.burger__box { position: relative; display: block; width: 22px; height: 12px; }

.burger__bar,
.burger__bar::before,
.burger__bar::after {
  position: absolute;
  left: 0;
  width: 22px;
  height: 1.5px;
  background: currentColor;
  transition: transform var(--dur-ui) var(--ease-standard), opacity var(--dur-instant);
}

.burger__bar { top: 0; }
.burger__bar::before { content: ""; top: 5px; }
.burger__bar::after { content: ""; top: 10px; }

.burger[aria-expanded="true"] .burger__bar { transform: translateY(5px) rotate(45deg); }
.burger[aria-expanded="true"] .burger__bar::before { opacity: 0; }
.burger[aria-expanded="true"] .burger__bar::after { transform: translateY(-10px) rotate(-90deg); }

/* `safe center` and a scroll container, not `place-items: center`.
   body.is-locked is overflow:hidden, so a panel taller than the viewport had
   nowhere to go: at 740x380 (a phone in landscape, or any phone with OS text
   scaling turned up) the nav is 460px tall and the language link and the CTA
   sat below the fold, hit-testing to nothing. `safe` keeps the panel optically
   centred whenever it fits and only falls back to start-aligned scrolling when
   it does not, so tall phones are unaffected. The top padding clears the header,
   which stays above this panel because it holds the only close control. */
.menu {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: var(--navy);
  color: var(--ink-invert);
  display: grid;
  align-content: safe center;
  justify-items: center;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-block: calc(var(--header-h) + var(--s5)) var(--s7);
  opacity: 0;
  transition: opacity var(--dur-ui) var(--ease-standard);
}

.menu[hidden] { display: none; }
.menu.is-open { opacity: 1; }

/* The header outranks the panel (z 100 vs 90) because it carries the close
   control, so while the panel is open it has to stop looking like a header:
   otherwise a white blurred bar sits across the navy overlay. Always on the two
   pages that ship .is-stuck, and on every other page the moment the visitor has
   scrolled at all, which on a phone is the normal case.

   Keyed off the panel's own visibility rather than body.is-locked, because
   close() drops is-locked on the first frame and the white would cross-fade
   back in over a panel that is still fully visible. :has() takes its argument's
   weight, so this outranks .header.is-stuck; browsers without it keep today's
   behaviour, which is merely ugly rather than broken. */
body:has(.menu:not([hidden])) .header {
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
  color: var(--ink-invert);
}

body:has(.menu:not([hidden])) .logo {
  --logo-from: #ffffff;
  --logo-to: #7fd4f5;
}

.menu__nav { width: 100%; padding: var(--gutter); max-width: 520px; }

.menu__list { counter-reset: m; display: grid; gap: var(--s5); }

.menu__list a {
  font-family: var(--font-serif);
  font-size: clamp(2rem, 8vw, 2.75rem);
  text-decoration: none;
  display: flex;
  align-items: baseline;
  gap: var(--s4);
}

.menu__list a::before {
  counter-increment: m;
  content: "0" counter(m);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--cyan);
}

.menu__foot {
  margin-top: var(--s8);
  padding-top: var(--s5);
  border-top: 1px solid var(--hairline-dark);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
}

.menu__lang { font-size: var(--t-sm); text-decoration: none; color: var(--cyan); }

body.is-locked { overflow: hidden; }

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  position: relative;
  min-height: min(88vh, 860px);
  padding-top: var(--header-h);
  display: flex;
  align-items: flex-end;
  background: var(--navy-800);
  color: var(--ink-invert);
  overflow: clip;
}

.hero__media { position: absolute; inset: 0; }

.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 62%;
}

/* Two scrims. The vertical one guarantees the headline band never exceeds
   0.18 relative luminance; the 60deg one carries the brand gradient's
   direction into the photograph so the field feels lit, not filtered. */
.hero__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(6, 21, 39, 0.94) 0%, rgba(6, 21, 39, 0.82) 38%, rgba(6, 21, 39, 0.42) 72%, rgba(6, 21, 39, 0.34) 100%),
    linear-gradient(60deg, rgba(8, 28, 52, 0.75) 0%, rgba(28, 117, 188, 0.16) 70%, rgba(0, 174, 239, 0.1) 100%);
}

.hero__inner {
  position: relative;
  width: 100%;
  max-width: var(--w-page);
  margin-inline: auto;
  padding: var(--s9) var(--gutter) var(--s8);
}

.hero__title {
  font-size: var(--t-display);
  line-height: 1.04;
  letter-spacing: -0.015em;
  max-width: 16ch;
}

/* M1 hero-lines: each line masked, inner span rising into place. */
.hero__line { display: block; overflow: hidden; }

.hero__line > span {
  display: block;
  transform: translateY(105%);
  transition: transform var(--dur-hero) var(--ease-out-expo);
  transition-delay: calc(var(--i, 0) * 70ms + 80ms);
}

.js .hero.is-ready .hero__line > span,
html:not(.js) .hero__line > span { transform: none; }

.hero__standfirst {
  margin-top: var(--s6);
  max-width: 46ch;
  font-size: var(--t-lead);
  color: rgba(255, 255, 255, 0.86);
}

.hero__audience {
  margin-top: var(--s4);
  max-width: 52ch;
  padding-top: var(--s4);
  border-top: 1px solid var(--hairline-dark);
  font-size: var(--t-sm);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.66);
}

.hero__actions { margin-top: var(--s7); display: flex; flex-wrap: wrap; gap: var(--s4); }

.hero__foot {
  margin-top: var(--s8);
  padding-top: var(--s5);
  border-top: 1px solid var(--hairline-dark);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s5);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: rgba(255, 255, 255, 0.6);
}

.hero__scroll {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  text-decoration: none;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.hero__scroll svg { animation: nudge 2.6s var(--ease-standard) infinite; }

@keyframes nudge {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(3px); }
}

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

/* ==========================================================================
   Who — the firm's own description, set as one large serif statement
   ========================================================================== */

.who__grid { display: grid; gap: var(--s8); }

@media (min-width: 900px) {
  .who__grid { grid-template-columns: 1.35fr 1fr; gap: var(--s9); align-items: start; }
}

.who__statement {
  font-family: var(--font-serif);
  font-size: var(--t-h2);
  line-height: 1.28;
  letter-spacing: -0.01em;
  margin-top: var(--s5);
}

.who__body {
  margin-top: var(--s6);
  max-width: var(--w-text);
  /* Stops "after-tax" splitting across lines at its own hyphen. */
  hyphens: none;
}

.who__facts { display: grid; gap: var(--s5); }

.who__fact {
  padding-top: var(--s5);
  border-top: 1px solid var(--hairline-light);
}

.who__fact dt {
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.who__fact dd {
  margin: var(--s2) 0 0;
  font-family: var(--font-serif);
  font-size: var(--t-h3);
  line-height: 1.2;
}

/* ==========================================================================
   Line-art marks

   These were the icons on the three "Why Altervest" cards. The cards are gone —
   they read as a slide deck — and the marks moved onto the photographic band,
   where the colour is overridden to the on-navy cyan. This is all that is left
   of that block; the .pillars grid and .pillar card rules were deleted rather
   than left behind as styles nothing selects.
   ========================================================================== */

.pillar__icon { color: var(--cyan-ui); }

/* ==========================================================================
   Why choose our firm — three numbered reasons beside a photograph
   ========================================================================== */

/* start, not center: centring gave the photo-to-first-hairline offset two
   different values (90px and 67px in EN, 77px and 43px in FR), so the eye
   never found the repeat. Every other multi-column pairing here start-aligns. */
.band { display: grid; gap: var(--s7); align-items: start; }
.band + .band { margin-top: var(--s9); }

@media (min-width: 960px) {
  .band { grid-template-columns: 1fr minmax(300px, 40%); gap: var(--s9); }
  .band--wide { grid-template-columns: 1fr minmax(320px, 48%); }

  /* Swap the sides on alternate bands. Ordering rather than re-ordering the
     markup keeps the reading order correct for a screen reader. */
  .band--flip { grid-template-columns: minmax(320px, 48%) 1fr; }
  .band--flip .band__media { order: -1; }
}

.band__text { display: grid; gap: var(--s7); }

.reason {
  display: grid;
  grid-template-columns: 3.5rem 1fr;
  gap: var(--s4);
  align-items: baseline;
  padding-top: var(--s5);
  border-top: 1px solid var(--hairline-light);
}

/* No line-height here. It was 1.9, a magic number that optically centred the
   numeral at exactly one width: the heading beside it is on the --t-h3 clamp, so
   the numeral floated 8px high at 1440 and 4px at 375. The baseline above does
   the job at every width. */
.reason__num {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--blue-ink);
}

.reason__tag { font-size: var(--t-h3); }
.reason__text { margin-top: var(--s3); font-size: var(--t-sm); color: var(--ink-muted); }

/* Regulatory qualifier: set as typography, not as small-print mush. */
.reason__note {
  margin-top: var(--s4);
  padding-left: var(--s4);
  border-left: 2px solid var(--cyan-ui);
  font-size: var(--t-micro);
  line-height: 1.6;
  color: var(--ink-muted);
  max-width: 58ch;
}

.band__media { margin: 0; }

.band__media picture,
.band__media img { width: 100%; border-radius: var(--radius); }

/* --- M13 image-build ------------------------------------------------------
   The photograph builds upward into its frame while the image inside settles
   out of a slight over-scale. Two things make it read as construction rather
   than as a slide: the wipe travels bottom-to-top, and the scale lands ~200ms
   after the wipe finishes, so the picture arrives and then comes to rest.

   That is the point. The brief was images that say stability — stone and steel
   rather than a Jenga tower — and an entrance that assembles and settles says
   the same thing the subjects do. It is also the reason the frame never moves:
   nothing on this page should look like it could still fall over.
   -------------------------------------------------------------------------- */

.js .band__media picture {
  display: block;
  overflow: hidden;
  border-radius: var(--radius);
  clip-path: inset(0 0 100% 0);
  transition: clip-path var(--dur-build) var(--ease-out-expo);
}

.js .band__media img {
  transform: scale(1.08);
  transform-origin: center 60%;
  transition: transform calc(var(--dur-build) + 320ms) var(--ease-out-expo);
}

.js .band__media.is-in picture { clip-path: inset(0 0 0 0); }
.js .band__media.is-in img { transform: scale(1); }

/* These figures are still .reveal so the one IntersectionObserver keeps driving
   them, but the build IS their entrance — stacking a fade and a rise on top
   would be three things happening to one photograph at once. */
.js .band__media.reveal { opacity: 1; transform: none; }

/* The caption follows the image up rather than arriving with it. */
.js .band__media .caption {
  opacity: 0;
  transition: opacity var(--dur-reveal) var(--ease-out-quart) 480ms;
}

.js .band__media.is-in .caption { opacity: 1; }

/* Stacked, a portrait crop would run over a full screen on its own; the tall
   frame is only worth it once the image sits beside the text. */
.band__media img { aspect-ratio: 3 / 2; object-fit: cover; }

@media (min-width: 960px) {
  .band__media img { aspect-ratio: 4 / 5; }
  .band__media--wide img { aspect-ratio: 3 / 2; }
}

/* ==========================================================================
   Platform — the two mechanisms, plus the diagram
   ========================================================================== */

.platform__panels { display: grid; gap: var(--s6); margin-bottom: var(--s8); }

@media (min-width: 800px) { .platform__panels { grid-template-columns: 1fr 1fr; gap: var(--s7); } }

/* The two mechanism panels are lit by the same source as the pane below them,
   so their top rules brighten toward it. Stacked (below 800px) the light is
   straight ahead, so both read centre-bright. */
.panel {
  padding-top: var(--s5);
  border-top: 0;
  background-image: linear-gradient(90deg,
    rgba(255, 255, 255, 0.08) 0%,
    rgba(255, 255, 255, 0.30) 50%,
    rgba(255, 255, 255, 0.08) 100%);
  background-size: 100% 1px;
  background-position: 0 0;
  background-repeat: no-repeat;
}

@media (min-width: 800px) {
  .platform__panels > .panel:first-child {
    background-image: linear-gradient(90deg,
      rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.30) 100%);
  }
  .platform__panels > .panel:last-child {
    background-image: linear-gradient(90deg,
      rgba(255, 255, 255, 0.30) 0%, rgba(255, 255, 255, 0.08) 100%);
  }
}
.panel h3 { margin-bottom: var(--s5); }
.panel ul { display: grid; gap: var(--s4); }

.panel li {
  position: relative;
  padding-left: var(--s6);
  font-size: var(--t-sm);
  color: var(--ink-invert-muted);
}

.panel li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.62em;
  width: 14px; height: 1px;
  background: var(--cyan);
}

.panel__note {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--hairline-dark);
  font-size: var(--t-micro);
  line-height: 1.6;
  color: var(--ink-invert-muted);
}

/* --- Diagram (M5 path-draw) ---------------------------------------------- */

.diagram { margin: 0; }
.diagram__caption {
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cyan);
  margin-bottom: var(--s5);
}

/* THE APERTURE.

   ONE light, stated once, at the diligence gate: x = 536 of the 1000-unit
   viewBox, 53.6%. Everything on this surface obeys it.

   The pane is lit by SUBTRACTION, not addition. Adding light at the centre
   raises the ground under the 1.5px cyan strokes and eats their contrast;
   shading the corners instead reads identically to the eye and can only ever
   improve it. Computed in sRGB: cyan on flat navy 6.08:1, on the pane centre
   5.89:1, at the corners 6.61:1. Do not "simplify" this back into a glow.

   178deg rather than 180deg on the face: a surface a fraction off-axis reads
   as an object rather than as a CSS box.

   NOTHING HERE ANIMATES. That is the point — static material needs no
   reduced-motion branch, no JS-off branch, and cannot strand content. Do not
   add will-change: a long-lived layer promotion is the exact failure the
   hero's settle() workaround in main.js exists to clean up after. */
.diagram__pane {
  position: relative;
  padding: var(--s6) clamp(16px, 2.4vw, 36px) var(--s7);
  border-radius: var(--radius);
  background:
    radial-gradient(115% 145% at 53.6% 50%,
      rgba(6, 21, 39, 0) 0%,
      rgba(6, 21, 39, 0.13) 50%,
      rgba(6, 21, 39, 0.46) 100%),
    linear-gradient(178deg,
      rgba(255, 255, 255, 0.035) 0%,
      rgba(255, 255, 255, 0.014) 42%,
      rgba(255, 255, 255, 0.004) 100%),
    var(--navy);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),   /* the lit lip */
    inset 1px 0 0 rgba(255, 255, 255, 0.045),  /* sides, weaker: light is above */
    inset -1px 0 0 rgba(255, 255, 255, 0.045),
    inset 0 -1px 0 rgba(6, 21, 39, 0.6),       /* the shaded underside */
    0 26px 64px -30px rgba(0, 0, 0, 0.62);     /* contact shadow on the wall */
}

/* backdrop-filter is deliberately NOT used: there is nothing behind the pane
   but flat navy, so it would cost a compositor layer and buy nothing. */

.diagram__svg { width: 100%; height: auto; overflow: visible; }

/* Light through the slit. On because the light is on — nothing to gate. */
.dg-spill { pointer-events: none; }

.dg-dot {
  /* Fallback path: today's exact appearance, byte for byte. */
  fill: #ffffff;
  fill-opacity: 0.28;
  opacity: 0;
  transition: opacity 420ms var(--ease-out-quart);
  transition-delay: calc(var(--i, 0) * 12ms);
}

/* Atmospheric perspective. --d is written by the generator: 0 far, 1 near.
   78 particles at one identical tone is the clip-art tell; the generator was
   already varying radius and throwing the information away. Small dots go
   dimmer AND bluer, because distance takes the colour of the medium it is seen
   through. The ramp averages 0.2835 against today's flat 0.28, so the field
   gains depth without getting darker. */
@supports (color: color-mix(in srgb, #fff 50%, #000)) {
  .dg-dot {
    fill: color-mix(in srgb, #ffffff calc(var(--d, 0.5) * 100%), #6f9fd0);
    fill-opacity: calc(0.17 + var(--d, 0.5) * 0.24);
  }
}

/* MUST follow the @supports block: equal specificity, later wins. Without the
   fill-opacity restatement the survivors inherit the ramp and dim to ~0.29.
   They are the ones that passed. */
.dg-dot--pass { fill: var(--cyan); fill-opacity: 1; }
.is-in .dg-dot { opacity: 1; }
html:not(.js) .dg-dot { opacity: 1; }

.dg-wall, .dg-rail {
  fill: none;
  stroke: var(--cyan);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-dasharray: var(--len, 1000);
  stroke-dashoffset: var(--len, 1000);
  transition: stroke-dashoffset var(--dur-draw) var(--ease-out-expo);
}

.is-in .dg-wall, .is-in .dg-rail { stroke-dashoffset: 0; }
html:not(.js) .dg-wall, html:not(.js) .dg-rail { stroke-dashoffset: 0; }

.dg-gate {
  stroke: rgba(255, 255, 255, 0.5);
  stroke-width: 1;
  stroke-dasharray: 3 5;
  opacity: 0;
  transition: opacity var(--dur-ui) var(--ease-out-quart) 400ms;
}

.is-in .dg-gate { opacity: 1; }
html:not(.js) .dg-gate { opacity: 1; }

/* The ring catches the light on the side facing the gate. Stops 0.34 -> 0.20,
   averaging 0.27 against today's flat 0.24: the shaded side stays legible
   because it carries meaning (the traditional holdings), not decoration. Do
   not take the dark stop below 0.18. */
.dg-ring__base { fill: none; stroke: url(#dg-rim); stroke-width: 10; }

.dg-ring__alt {
  fill: none;
  stroke: var(--cyan);
  stroke-width: 10;
  stroke-linecap: butt;
  transform: rotate(-90deg);
  /* 2πr ≈ 414.7 at r=66. A 108° alternatives sleeve = 124.4 of arc. */
  stroke-dasharray: 124.4 290.3;
  stroke-dashoffset: 124.4;
  transition: stroke-dashoffset var(--dur-draw) var(--ease-out-expo) 500ms;
}

.is-in .dg-ring__alt { stroke-dashoffset: 0; }

/* Without this the sleeve is not merely hidden, it is drawn in the wrong place:
   an offset equal to the dash length slides the visible arc round the ring. */
html:not(.js) .dg-ring__alt { stroke-dashoffset: 0; }

.diagram__legend { display: grid; gap: var(--s5); margin-top: var(--s7); }

@media (min-width: 760px) {
  .diagram__legend { grid-template-columns: repeat(4, 1fr); gap: var(--s6); }
}

/* Same light as the pane above: each 1px rule is brightest at the edge nearest
   the source and falls off. A chamfer under a real light does not have one
   value along its length. Cheapest detail in the whole section and probably
   the one that does the most work. */
.diagram__step {
  padding-top: var(--s4);
  border-top: 0;
  background-image: linear-gradient(90deg,
    rgba(255, 255, 255, 0.28) 0%,
    rgba(255, 255, 255, 0.11) 55%,
    rgba(255, 255, 255, 0.07) 100%);
  background-size: 100% 1px;
  background-position: 0 0;
  background-repeat: no-repeat;
}

.diagram__num {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--cyan);
  font-variant-numeric: tabular-nums;
}

.diagram__step h3 { font-size: var(--t-h4); font-family: var(--font-sans); font-weight: 600; margin-top: var(--s3); }

/* --- Mobile: weight, not size --------------------------------------------
   At 390px the gutter is 20px, so the SVG renders 350px against a 1000-unit
   viewBox: scale 0.35. At 1440px the inner width is 1320px: scale 1.32. Every
   stroke on the phone was 3.8x thinner in CSS pixels than on desktop —
   stroke-width 1.5 landed at 0.53px, a sub-pixel ghost, and the gate's "3 5"
   dash landed at 1.05px marks with 1.75px gaps, i.e. invisible. The cure is
   user-space weight plus a full bleed that buys back the gutter (+11% scale).
   No JavaScript and no scroll timeline, so it lands on every phone.
   ------------------------------------------------------------------------ */
@media (max-width: 640px) {
  .diagram__pane {
    margin-inline: calc(var(--gutter) * -1);
    border-radius: 0;
    padding: var(--s5) var(--s3) var(--s6);
  }

  .dg-wall, .dg-rail { stroke-width: 3.4; }
  .dg-gate { stroke-width: 2.4; stroke-dasharray: 6 8; }
  .dg-ring__base, .dg-ring__alt { stroke-width: 15; }

  /* r as a CSS geometry property: Chrome 90+, Firefox 72+, Safari 16.4+.
     Going through --r rather than a flat radius keeps both the size variation
     and the --d depth ramp. Without support the r="..." attribute still
     applies, and the stroke half of the win still lands. */
  @supports (r: 1px) {
    .dg-dot { r: calc(var(--r, 3.4) * 1.9px); }
    /* 6.4, not 8.4: CSS geometry properties resolve in USER units, and the
       survivors are only 15.2 apart. At 8.4 the six merged into one capsule
       and stopped reading as six. 6.4 leaves a 2.4-unit gap. */
    .dg-dot--pass { r: 6.4px; }
  }
}

.diagram__step p { margin-top: var(--s2); font-size: var(--t-micro); font-family: var(--font-sans); color: var(--ink-invert-muted); line-height: 1.5; }

/* ==========================================================================
   Exempt market services — full-bleed photographic band

   The Laurentians photograph sits behind the type rather than beside it, the
   way the old site used it. Two details keep that legible: the scrim is a
   vertical gradient so the ridgeline survives instead of flattening to grey,
   and the darkest part of it sits under the heading rather than spread evenly.
   ========================================================================== */

.imageband {
  position: relative;
  overflow: clip;
  background: var(--navy);
  color: var(--ink-invert);
  isolation: isolate;
}

.imageband__media { position: absolute; inset: 0; z-index: -2; }

.imageband__media picture,
.imageband__media img { width: 100%; height: 100%; }
.imageband__media img { object-fit: cover; object-position: center 42%; }

.imageband__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(to bottom, rgba(6, 21, 39, 0.76) 0%, rgba(6, 21, 39, 0.48) 46%, rgba(6, 21, 39, 0.7) 100%),
    linear-gradient(60deg, rgba(8, 28, 52, 0.55) 0%, rgba(11, 37, 69, 0.2) 70%, rgba(0, 174, 239, 0.08) 100%);
}

.imageband__inner { position: relative; }
.imageband__head { max-width: var(--w-text); }

/* --- Split variant: heading in its own column, points listed beside it ------
   The pillars used to be three bordered cards in a row, which read as a slide.
   Removing the boxes is most of the fix; holding the heading in a narrow column
   is the rest, because it turns three equal panels into one list to read down.
   -------------------------------------------------------------------------- */

.imageband__scrim--split {
  /* Pale sky over ice — a brighter picture than the Laurentians, so it takes a
     heavier hand. Measured in scripts/check-scrims.py. */
  background:
    linear-gradient(to bottom, rgba(6, 21, 39, 0.78) 0%, rgba(6, 21, 39, 0.58) 50%, rgba(6, 21, 39, 0.76) 100%),
    linear-gradient(60deg, rgba(8, 28, 52, 0.6) 0%, rgba(11, 37, 69, 0.24) 70%, rgba(0, 174, 239, 0.08) 100%);
}

.whyband { display: grid; gap: var(--s7); }

@media (min-width: 960px) {
  .whyband { grid-template-columns: minmax(260px, 32%) 1fr; gap: var(--s9); align-items: start; }
}

.whyband__head h2 { margin-top: var(--s5); }
.whyband__head .lead { margin-top: var(--s5); color: var(--ink-invert-muted); }

.whyband__points { display: grid; gap: var(--s6); }

.wpoint {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s5);
  align-items: start;
  padding-top: var(--s5);
  border-top: 1px solid var(--hairline-dark);
}

.wpoint .pillar__icon { color: var(--cyan); }
.wpoint__tag { font-size: var(--t-h3); }
.wpoint__text { margin-top: var(--s3); font-size: var(--t-sm); color: var(--ink-invert-muted); }

/* Two classes, because `.imageband .caption` below zeroes the caption margin.
   That rule is for the caption tucked under the exempt-market note, and without
   the extra specificity here it also flattened this credit onto the last line of
   the pillar list beside it. */
.imageband .caption.imageband__credit { margin-top: var(--s8); text-align: right; }
.imageband__head h2 { margin-top: var(--s5); }
.imageband__head .lead { margin-top: var(--s5); color: var(--ink-invert-muted); }

.services {
  display: grid;
  gap: var(--s5);
  margin-top: var(--s8);
}

@media (min-width: 700px) { .services { grid-template-columns: repeat(2, 1fr); gap: var(--s6); } }
@media (min-width: 1000px) { .services { grid-template-columns: repeat(4, 1fr); } }

.service {
  padding-top: var(--s5);
  border-top: 1px solid var(--hairline-dark);
  display: grid;
  gap: var(--s3);
}

.service__num { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--cyan); }

.service__name {
  font-family: var(--font-serif);
  font-size: var(--t-h3);
  line-height: 1.2;
}

/* One name wraps to two lines while its three siblings do not, so a row meant to
   read as four equal capabilities read as three plus an overflow. 2 x the 1.2
   line-height above. Fixes the inverted case in French too. */
@media (min-width: 1000px) {
  .service__name { min-height: 2.4em; }
}

.imageband__foot {
  margin-top: var(--s8);
  padding-top: var(--s5);
  border-top: 1px solid var(--hairline-dark);
  display: grid;
  gap: var(--s4);
}

@media (min-width: 800px) {
  .imageband__foot { grid-template-columns: 1fr auto; align-items: baseline; gap: var(--s7); }
}

.imageband__note {
  font-size: var(--t-micro);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.62);
  max-width: 68ch;
}

.imageband .caption { margin-top: 0; color: rgba(255, 255, 255, 0.62); }

.caption {
  margin-top: var(--s3);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--ink-muted);
}

/* ==========================================================================
   404

   Bilingual, both blocks shown at once (French first), because the page is
   reached with no language context to infer from. Two columns on desktop so
   neither language is buried below the fold; stacked below 760px with a rule
   between them, which is the only cue that the second block is a translation
   rather than more content.
   ========================================================================== */

.nf {
  width: 100%;
  max-width: var(--w-page);
  margin-inline: auto;
  padding: var(--s9) var(--gutter);
  display: grid;
  gap: var(--s8);
}

@media (min-width: 760px) {
  .nf { grid-template-columns: 1fr 1fr; gap: var(--s9); align-items: start; }
}

.nf__lang { max-width: 46ch; }

/* The divider belongs to the second block, so it appears between the two in
   both directions: a top rule when stacked, a left rule when side by side. */
.nf__lang + .nf__lang {
  padding-top: var(--s7);
  border-top: 1px solid var(--hairline-light);
}

@media (min-width: 760px) {
  .nf__lang + .nf__lang {
    padding-top: 0;
    padding-left: var(--s8);
    border-top: 0;
    border-left: 1px solid var(--hairline-light);
  }
}

.nf__heading {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: var(--t-h2);
  line-height: 1.12;
  letter-spacing: -0.01em;
}

.nf__body {
  margin-top: var(--s5);
  color: var(--ink-muted);
  font-size: var(--t-sm);
}

.nf__links {
  margin-top: var(--s6);
  display: grid;
  gap: 0;
}

.nf__links li { border-top: 1px solid var(--hairline-light); }
.nf__links li:last-child { border-bottom: 1px solid var(--hairline-light); }

.nf__links a {
  display: block;
  padding: var(--s4) 0;
  color: var(--ink);
  text-decoration: none;
  font-size: var(--t-sm);
  transition: color var(--dur-hover) var(--ease-out-quart);
}

@media (hover: hover) {
  .nf__links a:hover { color: var(--blue-ink); }
}

.nf__links a:active { opacity: 0.7; }

.nf__help {
  margin-top: var(--s6);
  font-size: var(--t-micro);
  color: var(--ink-muted);
}

.nf__help a { color: var(--blue-ink); }

/* ==========================================================================
   Team
   ========================================================================== */

.team__grid { display: grid; gap: var(--s6); }

@media (min-width: 620px) { .team__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .team__grid { grid-template-columns: repeat(4, 1fr); gap: var(--s5); } }

/* A two-person team. Four columns would leave half the row empty, and shrinking
   the portraits to fill it would make the firm look smaller than it is. */
.team__grid--pair { gap: var(--s7); }

@media (min-width: 760px) {
  .team__grid--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1000px) {
  .team__grid--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s8); }
}

.member__media {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  /* Matches the studio grey the portraits sit on, so nothing flashes while
     an image decodes. */
  background: #9b9b9b;
}

.member__media img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  /* M12 portrait-warm. The portraits are already framed to a common head size
     and eye line at build time, so all this has to do is lift the grade. */
  filter: grayscale(1) contrast(1.04);
  transition: filter var(--dur-ui) var(--ease-out-quart);
}

@media (hover: hover) {
  .member:hover .member__media img,
  .member:focus-within .member__media img { filter: grayscale(0) contrast(1); }
}

.member__name { margin-top: var(--s5); font-size: var(--t-h3); }

.member__link {
  color: inherit;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 1px;
  transition: background-size 250ms ease-in-out;
}

.member__link:hover,
.member__link:focus-visible { background-size: 100% 1px; }

.member__cred {
  margin-top: var(--s2);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  color: var(--blue-ink);
}

.member__role { margin-top: var(--s3); font-size: var(--t-sm); color: var(--ink-muted); }

/* --- Team page: full biographies ----------------------------------------- */

.bio { padding-block: var(--s8); border-top: 1px solid var(--hairline-light); }
.bio:first-of-type { border-top: 0; }

.bio__grid { display: grid; gap: var(--s6); }

@media (min-width: 860px) {
  .bio__grid { grid-template-columns: 320px 1fr; gap: var(--s8); align-items: start; }
}

@media (min-width: 1100px) { .bio__grid { grid-template-columns: 420px 1fr; gap: var(--s9); } }

/* Two biographies on the page, so they get a rule between them rather than
   running together. */
.bio + .bio { margin-top: var(--s8); }

.bio__media { border-radius: var(--radius); overflow: hidden; background: #9b9b9b; }
.bio__media img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.bio__name { font-size: var(--t-h1); }

.bio__cred {
  margin-top: var(--s3);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--blue-ink);
}

.bio__role { margin-top: var(--s4); font-size: var(--t-lead); color: var(--ink); }
.bio__text { margin-top: var(--s6); max-width: var(--w-text); }
.bio__text p + p { margin-top: var(--s5); }
.bio__text p { color: var(--ink-muted); }

/* ==========================================================================
   Providers
   ========================================================================== */

.providers {
  display: grid;
  gap: var(--s5);
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  align-items: center;
}

.provider {
  display: grid;
  place-items: center;
  padding: var(--s6) var(--s5);
  background: var(--white);
  border: 1px solid var(--hairline-light);
  border-radius: var(--radius);
  min-height: 116px;
  transition: border-color var(--dur-hover) var(--ease-out-quart);
}

/* Providers that link fill their whole tile, so the target is the card and
   not just the logo inside it. */
.provider__link {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  border-radius: var(--radius);
}

.provider img {
  /* Square marks are exported taller than wordmarks (see process-images.py),
     so the cap here is on the box, not on every logo's own height. */
  max-height: 56px;
  max-width: 82%;
  width: auto;
  object-fit: contain;
  filter: grayscale(1);
  opacity: 0.66;
  transition: filter var(--dur-ui) var(--ease-out-quart), opacity var(--dur-ui) var(--ease-out-quart);
}

@media (hover: hover) {
  .provider:hover { border-color: var(--cyan-ui); }
  .provider:hover img { filter: grayscale(0); opacity: 1; }
}

/* ==========================================================================
   Legal (privacy policy and terms)

   Long-form clauses, set narrow. The measure is the whole design here: a legal
   page nobody can read is a legal page nobody reads.
   ========================================================================== */

.legal__inner { max-width: 46rem; margin-inline: auto; }

.legal__head { margin-bottom: var(--s8); }

.legal__updated {
  margin-top: var(--s4);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.02em;
  color: var(--ink-muted);
}

.legal__section { margin-top: var(--s8); }

.legal__heading {
  font-size: var(--t-h3);
  margin-bottom: var(--s5);
  padding-bottom: var(--s3);
  border-bottom: 1px solid var(--hairline-light);
}

.legal__p { margin-top: var(--s4); }
.legal__p strong { color: var(--ink); }

.legal__note {
  margin-top: var(--s8);
  padding-top: var(--s5);
  border-top: 1px solid var(--hairline-light);
  font-size: var(--t-micro);
  color: var(--ink-muted);
}

/* ==========================================================================
   Page hero with a photograph (contact)
   ========================================================================== */

.pagehero {
  position: relative;
  padding: calc(var(--header-h) + var(--s9)) 0 var(--s9);
  background: var(--navy-800);
  color: var(--ink-invert);
  overflow: clip;
}

.pagehero__media { position: absolute; inset: 0; }
.pagehero__media img { width: 100%; height: 100%; object-fit: cover; object-position: center 45%; }

.pagehero__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(6, 21, 39, 0.95) 0%, rgba(6, 21, 39, 0.86) 45%, rgba(6, 21, 39, 0.62) 100%),
    linear-gradient(60deg, rgba(8, 28, 52, 0.7) 0%, rgba(28, 117, 188, 0.14) 70%, rgba(0, 174, 239, 0.08) 100%);
}

.pagehero__inner { position: relative; }
.pagehero__inner h1 { margin-top: var(--s5); max-width: 18ch; }
.pagehero__inner .lead { margin-top: var(--s5); color: rgba(255, 255, 255, 0.78); max-width: 46ch; }

/* ==========================================================================
   Contact
   ========================================================================== */

.contact__grid { display: grid; gap: var(--s8); }

/* Three children, two columns. The form spans both rows on the right; the
   newsletter fills the left column under the address block, which otherwise
   ended 767px above it and left the page looking unfinished. Stacked order
   below 900px is unchanged: address, form, newsletter. */
@media (min-width: 900px) {
  .contact__grid {
    grid-template-columns: 1fr 1.1fr;
    gap: var(--s9);
    align-items: start;
  }
  .contact__grid > :nth-child(1) { grid-column: 1; grid-row: 1; }
  .contact__grid > :nth-child(2) { grid-column: 2; grid-row: 1 / span 2; }
  .contact__grid > .newsletter {
    grid-column: 1;
    grid-row: 2;
    margin-top: 0;
    padding-top: var(--s7);
    border-top: 1px solid var(--hairline-light);
  }
}

.contact__address {
  margin-top: var(--s5);
  font-family: var(--font-serif);
  font-size: var(--t-h3);
  line-height: 1.45;
}

.contact__record { display: grid; margin-top: var(--s7); }

.record {
  display: grid;
  grid-template-columns: 7rem 1fr;
  gap: var(--s4);
  padding-block: var(--s4);
  border-top: 1px solid var(--hairline-light);
  align-items: baseline;
}

.record:last-child { border-bottom: 1px solid var(--hairline-light); }

.record__key {
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.record__value { margin: 0; font-size: var(--t-sm); }

.contact__privacy { margin-top: var(--s7); max-width: 46ch; }

.contact__privacyHeading {
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: var(--s3);
}

.contact__privacy p { font-size: var(--t-micro); line-height: 1.65; color: var(--ink-muted); }

/* The form gets a card so it reads as the primary action on the page without
   needing a louder colour to say so. */
.formcard {
  padding: var(--s7);
  background: var(--bone);
  border: 1px solid var(--hairline-light);
  border-radius: var(--radius);
}

.formcard__lead { margin-top: var(--s3); }

.field-row { display: grid; gap: var(--s5); }
@media (min-width: 560px) { .field-row { grid-template-columns: 1fr 1fr; } }

.form { display: grid; gap: var(--s5); margin-top: var(--s6); }
.field { display: grid; gap: var(--s2); }

.field label {
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.field input,
.field textarea {
  font: inherit;
  font-size: var(--t-sm);
  color: var(--ink);
  padding: var(--s4);
  background: var(--white);
  width: 100%;
  border: 1px solid var(--stroke-ui);
  border-radius: var(--radius);
  transition: border-color var(--dur-hover) var(--ease-out-quart);
}

.field input:hover,
.field textarea:hover { border-color: var(--cyan-ui); }

.field input:focus,
.field textarea:focus { border-color: var(--blue-ink); }

.field textarea { resize: vertical; min-height: 9rem; }

.form__note { font-size: var(--t-micro); color: var(--ink-muted); }
.form__actions { display: flex; align-items: center; gap: var(--s5); flex-wrap: wrap; }

.newsletter { margin-top: var(--s8); }
.newsletter__lead { margin-top: var(--s5); font-size: var(--t-lead); color: var(--ink-muted); }
.newsletter__action { margin-top: var(--s5); }

/* ==========================================================================
   Footer
   ========================================================================== */

.footer {
  background: var(--navy-900);
  color: var(--ink-invert);
  padding-block: var(--s9) var(--s6);
}

.footer__cta,
.footer__grid,
.footer__legal {
  width: 100%;
  max-width: var(--w-page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* The review-build banner only. Kept out of the container list above: adding a
   rule inside that selector list once orphaned .footer__legal and let the CTA
   and the footer grid run full-bleed in monospace cyan. */
.footer__preview {
  margin-top: var(--s3);
  font-family: var(--font-mono);
  letter-spacing: 0.06em;
  color: var(--cyan);
}

.footer__cta {
  display: grid;
  gap: var(--s6);
  padding-bottom: var(--s8);
  border-bottom: 1px solid var(--hairline-dark);
}

@media (min-width: 800px) {
  .footer__cta { grid-template-columns: 1fr auto; align-items: end; gap: var(--s8); }
}

.footer__ctaActions { display: flex; flex-wrap: wrap; gap: var(--s4); }

/* On a dark ground the ghost button's default muted ink disappears. */
.footer .btn--ghost { color: rgba(255, 255, 255, 0.78); border-color: var(--hairline-dark); }
.footer .btn--ghost:hover,
.footer .btn--ghost:focus-visible { color: var(--white); border-color: currentColor; }

.footer__ctaText {
  font-family: var(--font-serif);
  font-size: var(--t-h2);
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--ink-invert);
}

.footer__ctaText em { font-style: italic; color: var(--cyan); }

.footer__grid { display: grid; gap: var(--s7); padding-block: var(--s8); }

@media (min-width: 760px) { .footer__grid { grid-template-columns: 1.6fr repeat(3, 1fr); gap: var(--s6); } }

.footer__logo { height: 30px; --logo-from: #ffffff; --logo-to: #7fd4f5; }
.footer__tag { display: block; margin-top: var(--s3); color: rgba(255, 255, 255, 0.6); }
.footer__address { margin-top: var(--s5); font-size: var(--t-sm); color: var(--ink-invert-muted); }

.footer__heading {
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
  margin-bottom: var(--s4);
}

.footer__col ul { display: grid; gap: var(--s3); }
.footer__col a { font-size: var(--t-sm); }

/* The language you are already reading is a state, not a destination. */
.footer__current { font-size: var(--t-sm); color: var(--ink-invert-muted); }

.footer__preview {
  margin-top: var(--s3);
  font-family: var(--font-mono);
  letter-spacing: 0.06em;
  color: var(--cyan);
}

.footer__legal {
  padding-top: var(--s6);
  border-top: 1px solid var(--hairline-dark);
  font-size: var(--t-micro);
  color: rgba(255, 255, 255, 0.5);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--s3) var(--s6);
}

.footer__regulatory {
  margin-bottom: var(--s5);
  padding-bottom: var(--s5);
  border-bottom: 1px solid var(--hairline-dark);
  font-size: var(--t-micro);
  line-height: 1.6;
  color: var(--ink-invert-muted);
}

.footer__regulatory p + p { margin-top: var(--s3); }

.footer__credit a { color: rgba(255, 255, 255, 0.72); text-decoration: none; }
.footer__credit a:hover,
.footer__credit a:focus-visible { color: var(--cyan); }

/* ==========================================================================
   Page heroes (team, contact)
   ========================================================================== */

.pagehead {
  background: var(--navy);
  color: var(--ink-invert);
  padding: calc(var(--header-h) + var(--s8)) 0 var(--s8);
}



.pagehead h1 { margin-top: var(--s5); max-width: 18ch; }
.pagehead .lead { margin-top: var(--s5); color: var(--ink-invert-muted); max-width: var(--w-text); }

/* ==========================================================================
   Layer 2 of reduced motion: the safety net. Anything that animates by any
   route other than a token lands here.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .js .reveal { opacity: 1; transform: none; }
  .js .band__media picture { clip-path: none; }
  .js .band__media img { transform: none; }
  .js .band__media .caption { opacity: 1; }
  .dg-wall, .dg-rail { stroke-dashoffset: 0; }
  .dg-dot { opacity: 1; }
  .dg-ring__alt { stroke-dashoffset: 0; }
  .eyebrow-rule { transform: scaleX(1); }
  .hero__line > span { transform: none; }
}

/* ==========================================================================
   Print — this audience prints the team page and hands it to their accountant.
   ========================================================================== */

@media print {
  :root { --ink: #000; --ink-muted: #333; }

  .header, .menu, .burger, .skip-link, .hero__actions,
  .hero__foot, .footer__cta, .diagram__svg, .diagram__pane { display: none !important; }

  body { background: #fff; color: #000; font-size: 11pt; line-height: 1.5; }

  .section, .pagehead { padding-block: 12pt; background: #fff !important; color: #000 !important; }
  .section--navy *, .pagehead * { color: #000 !important; }
  .hero { min-height: auto; color: #000; }
  .hero__media, .hero__scrim { display: none; }

  .bio, .member { break-inside: avoid; page-break-inside: avoid; }
  .js .reveal { opacity: 1 !important; transform: none !important; }

  /* Resolve links to footnotes, skipping in-page anchors. */
  a[href^="http"]::after,
  a[href^="mailto"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #444; }
}
