/* ============================================================================
   ALVENERA — "The Certainty Gradient"
   ----------------------------------------------------------------------------
   Design system for the Alvenera site.

   The site and the app are one palette now. The app ships two themes named for
   what they are rather than for how bright they are — Paper, the pale green of
   cheque safety paper, and Petrol, that same paper unlit — and the site is
   built from both: a petrol room in which the light screens are the only lit
   objects.

   Colour says one thing here: how true a figure is. Three signals, because a
   ledger's states are not good and bad but checked, taken on trust, and not yet
   real.

     verdigris   reconciled, held, on plan
     brass       projected, pending, due — everything that has not happened
     vermilion   overdrawn, over budget, runway breach

   Three voices carry the whole page:
     Fraunces          — display. Editorial, optical-size aware, set light and tight.
     Instrument Sans   — prose and UI. Neutral, slightly warm, never shouts.
     Spline Sans Mono  — every figure, index, and label. A ledger is made of
                         numbers in columns; they get their own typeface and are
                         always tabular, so nothing shifts as they animate. A code
                         face was here before, and made money look like program
                         output.

   Sections alternate ink -> paper -> ink. That alternation is the page's pacing;
   each section paints its own ground so the rhythm survives any reordering.
   ========================================================================== */

/* ------------------------------------------------------------ 0. The faces */

/* Self-hosted, subset to Latin-1 plus the marks the site actually sets, and
   axis-limited to the ranges the CSS below asks for. Regenerate with
   `python build/make-assets.py fonts`.

   These came from Google Fonts until the privacy notice had to apologise for
   it in so many words. Two extra origins on the critical path is also the
   wrong way to open a page whose whole argument is that nobody else is
   involved. */

@font-face {
  font-family: "Fraunces";
  src: url("/fonts/fraunces-roman.woff2") format("woff2-variations");
  font-weight: 200 700;
  font-style: normal;
  font-display: swap;
  /* Matched to the Iowan Old Style / Georgia fallback so the swap does not
     move a line. */
  ascent-override: 96%;
  descent-override: 26%;
}
@font-face {
  font-family: "Fraunces";
  src: url("/fonts/fraunces-italic.woff2") format("woff2-variations");
  font-weight: 200 700;
  font-style: italic;
  font-display: swap;
  ascent-override: 96%;
  descent-override: 26%;
}
@font-face {
  font-family: "Instrument Sans";
  src: url("/fonts/instrument-roman.woff2") format("woff2-variations");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  ascent-override: 94%;
  descent-override: 24%;
}
@font-face {
  font-family: "Instrument Sans";
  src: url("/fonts/instrument-italic.woff2") format("woff2-variations");
  font-weight: 400 700;
  font-style: italic;
  font-display: swap;
  ascent-override: 94%;
  descent-override: 24%;
}
@font-face {
  font-family: "Spline Sans Mono";
  src: url("/fonts/spline-roman.woff2") format("woff2-variations");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

/* ---------------------------------------------------------------- 1. Tokens */

:root {
  /* Ink — the site's ground, and the app's Petrol theme. Green-biased rather
     than a neutral near-black, so it belongs to the same world as the paper. */
  --ink-900: #060F0D;
  --ink-800: #0C1A17;
  --ink-700: #142723;
  --ink-600: #1B322C;
  --ink-500: #24403A;

  /* Paper — the app's Paper theme, borrowed for the light movements. Not white:
     a ledger has always been printed on tinted stock, and a panel only reads as
     raised if the page under it is not also white. */
  --paper-000: #F6F9F7;
  --paper-100: #E7EDEA;
  --paper-200: #DEE7E3;
  --paper-300: #C7D5CF;

  /* Mint — the mark's own colour, plus the two shades it needs to stay legible:
     the light one for text on ink, the deep one for text on paper. */
  --mint: #2ED3A0;
  --mint-lo: #62E0B6;
  --mint-deep: #0B6B52;
  --mint-wash: #DDF2EA;

  /* The three signals, each in the pair it needs to stay legible: the light
     value for text on petrol, the deep one for text on paper. Every one of
     these was checked against both grounds and clears AA at 4.5:1. */
  --gain: #62E0B6;
  --gain-ink: #0B6B52;
  --spend: #F07A5F;
  --spend-ink: #A9331C;

  /* Brass: the colour of the dashed half of the line, and the reason the site
     can draw a forecast without it reading as a fact. */
  --brass: #D9A441;
  --brass-ink: #835C1E;
  --brass-wash: #F2E7D2;

  /* Kept as aliases so the components that named the old semantics still work. */
  --amber: var(--brass);
  --amber-ink: var(--brass-ink);
  --violet: #C98BB9;
  --azure: #6FB4DC;

  /* Type roles, re-pointed per section by [data-ground]. */
  --fg-1: #DEEAE4;
  --fg-2: #9DB3AB;
  --fg-3: #879D97;
  --accent: var(--mint);
  --ground: var(--ink-800);
  --raised: rgba(255, 255, 255, .04);
  --raised-2: rgba(255, 255, 255, .07);
  --rule: rgba(157, 179, 171, .17);
  --rule-strong: rgba(157, 179, 171, .32);
  --shadow-lift: 0 24px 60px -20px rgba(0, 0, 0, .6), 0 2px 8px rgba(0, 0, 0, .3);

  /* Families */
  --display: "Fraunces", "Iowan Old Style", Georgia, serif;
  --sans: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --mono: "Spline Sans Mono", ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;

  /* Motion. One easing does almost all the work: a long expo-out that starts
     fast and settles without a bounce. Anything reversible (hover, toggles)
     uses the symmetric curve instead, so it feels the same going back. */
  --ease: cubic-bezier(.16, 1, .3, 1);
  --ease-sym: cubic-bezier(.65, 0, .35, 1);
  --t-fast: 180ms;
  --t-base: 320ms;
  --t-slow: 620ms;
  --t-reveal: 640ms;

  /* Measure and rhythm */
  --shell: 1240px;
  --gutter: clamp(20px, 5vw, 64px);
  --bay: clamp(88px, 11vw, 168px);
  --radius: 18px;
  --radius-lg: 28px;
  --radius-sm: 10px;
}

/* A section declares which ground it sits on; every component below reads the
   role tokens, never the raw palette, so one attribute flips a whole movement. */
[data-ground="paper"] {
  --fg-1: #0F2019;
  --fg-2: #3E5750;
  --fg-3: #556A60;
  --accent: var(--mint-deep);
  --ground: var(--paper-100);
  --raised: var(--paper-000);
  --raised-2: var(--paper-000);
  --rule: rgba(15, 32, 25, .13);
  --rule-strong: rgba(15, 32, 25, .24);
  --gain: var(--gain-ink);
  --spend: var(--spend-ink);
  --brass: var(--brass-ink);
  --amber: var(--brass-ink);
  --violet: #7A4079;
  --azure: #2A6489;
  --shadow-lift: 0 1px 2px rgba(15, 32, 25, .05), 0 18px 44px -12px rgba(15, 32, 25, .14);
}

[data-ground="abyss"] { --ground: var(--ink-900); }

/* ------------------------------------------------------------ 2. Reset/base */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 104px;
}

body {
  margin: 0;
  background: var(--ink-800);
  color: var(--fg-1);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg, video { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }

::selection { background: var(--mint); color: var(--ink-900); }

:focus-visible {
  outline: 2px solid var(--mint);
  outline-offset: 3px;
  border-radius: 4px;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: fixed; top: 12px; left: 12px; z-index: 200;
  transform: translateY(-200%);
  background: var(--mint); color: var(--ink-900);
  padding: 10px 18px; border-radius: 999px;
  font: 600 14px/1 var(--sans);
  transition: transform var(--t-base) var(--ease);
}
.skip-link:focus { transform: none; }

/* ------------------------------------------------------------ 3. Typography */

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 300;
  font-variation-settings: "SOFT" 0, "WONK" 1, "opsz" 120;
  letter-spacing: -.025em;
  line-height: 1.02;
  margin: 0;
  text-wrap: balance;
}

h1 {
  font-size: clamp(2.5rem, 5.6vw, 4.4rem);
  line-height: 1.0;
  letter-spacing: -.035em;
}

h2 {
  font-size: clamp(2.05rem, 4.4vw, 3.75rem);
  line-height: 1.02;
  letter-spacing: -.032em;
}

h3 {
  font-size: clamp(1.22rem, 1.9vw, 1.55rem);
  line-height: 1.15;
  letter-spacing: -.02em;
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 30;
}

/* The one place italics are allowed: a single emphasised phrase per headline,
   in Fraunces' WONK italic, so the eye lands where the argument turns. */
.turn {
  font-style: italic;
  font-variation-settings: "SOFT" 10, "WONK" 1, "opsz" 120;
  color: var(--accent);
}

p { margin: 0 0 1.1em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

.lede {
  font-size: clamp(1.05rem, 1.45vw, 1.28rem);
  line-height: 1.55;
  color: var(--fg-2);
  max-width: 36ch;
}
.lede--wide { max-width: 54ch; }

.prose { color: var(--fg-2); max-width: 64ch; }
.prose strong { color: var(--fg-1); font-weight: 600; }
.prose--sm { font-size: 14.5px; }
.prose a { color: var(--accent); box-shadow: inset 0 -1px 0 currentColor; }

/* Mono is the ledger voice: indices, labels, figures, timestamps. */
.mono {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "zero" 1;
}

.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-3);
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
}
.eyebrow::before {
  content: "";
  width: 22px; height: 1px;
  background: var(--accent);
  flex: none;
}
.eyebrow--bare::before { display: none; }

.figure {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  letter-spacing: -.03em;
  font-size: clamp(1.7rem, 3vw, 2.5rem);
  line-height: 1;
  color: var(--fg-1);
}

/* --------------------------------------------------------------- 4. Layout */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.bay {
  background: var(--ground);
  color: var(--fg-1);
  padding-block: var(--bay);
  position: relative;
}

/* The signature: every section is introduced by a hairline that spans the full
   measure with its index sitting on it, like the rule at the top of a ledger
   page. It is the same object at every scale, which is what makes the page read
   as one system rather than as a stack of blocks. */
.bay__head {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(24px, 4vw, 56px);
  padding-top: 46px;
  border-top: 1px solid var(--rule);
  position: relative;
}
.bay__head::before {
  content: attr(data-index);
  position: absolute;
  top: 14px; left: 0;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .16em;
  line-height: 1;
  color: var(--accent);
}

@media (min-width: 900px) {
  .bay__head { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); align-items: end; }
  .bay__head--solo { grid-template-columns: 1fr; }
}
/* The FAQ head sits above a sticky single column, so it takes the rule and the
   index without the two-column body. It was the only section on the page using
   a bare .eyebrow instead - the one break in the signature. */
.bay__head--solo { padding-top: 38px; gap: 0; }

.stack   { display: grid; gap: clamp(14px, 1.6vw, 22px); align-content: start; }
.stack-l { display: grid; gap: clamp(28px, 4vw, 52px); align-content: start; }

.split { display: grid; gap: clamp(36px, 5vw, 84px); align-items: center; }
@media (min-width: 960px) {
  .split { grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr); }
  .split--flip > :first-child { order: 2; }
}

.grid-3 { display: grid; gap: clamp(14px, 1.6vw, 20px); grid-template-columns: 1fr; }
@media (min-width: 700px)  { .grid-3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .grid-3 { grid-template-columns: repeat(3, 1fr); } }

/* ----------------------------------------------------------- 5. Scroll line */

/* Not a progress bar — a running balance. The line advances along the top of
   the viewport and the mono readout beside it counts the page down, which is
   the same gesture the product performs on a ledger. */
.balance-line {
  position: fixed;
  inset: 0 0 auto 0;
  height: 1px;
  background: var(--rule);
  z-index: 90;
  pointer-events: none;
}
.balance-line__fill {
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, var(--mint-deep), var(--mint));
  transform: scaleX(0);
  transform-origin: 0 50%;
  will-change: transform;
}

/* --------------------------------------------------------------- 6. Header */

.masthead {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 80;
  padding-block: 18px;
  transition: padding var(--t-slow) var(--ease), background var(--t-slow) var(--ease),
              border-color var(--t-slow) var(--ease);
  border-bottom: 1px solid transparent;
  /* Declared up front rather than introduced by .is-stuck, so the layer is
     created once at load instead of being promoted mid-scroll - and never
     interpolated, which is what a transition on this property costs. */
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
}
.masthead.is-stuck {
  padding-block: 11px;
  background: rgba(6, 15, 13, .82);
  background: color-mix(in srgb, var(--ink-900) 82%, transparent);
  border-bottom-color: rgba(157, 178, 192, .14);
}

.masthead__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.brand { display: inline-flex; align-items: center; gap: 12px; }
.brand__mark { width: 34px; height: 34px; flex: none; }
.brand__word {
  font-family: var(--mono);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: .3em;
  color: #DEEAE4;
  text-transform: uppercase;
  padding-left: 2px;
}
/* The wordmark's V climbs and falls like the mark above it, so it carries the
   accent — the same rule the app's drawn lockup follows. */
.brand__word i { font-style: normal; color: var(--mint); }

.nav { display: none; align-items: center; gap: 6px; }
/* 1200, not narrower: with the Help link the French row (« Confidentialité », « Migration », « Aide »)
   ran past the language switch and the button below that. The drawer carries every
   link until there is room for all of them. */
@media (min-width: 1200px) { .nav { display: flex; } }

.nav__link {
  position: relative;
  padding: 8px 14px;
  border-radius: 999px;
  font-size: 14.5px;
  color: #9DB3AB;
  white-space: nowrap;
  transition: color var(--t-base) var(--ease-sym);
}
.nav__link::after {
  content: "";
  position: absolute;
  left: 14px; right: 14px; bottom: 4px;
  height: 1px;
  background: var(--mint);
  transform: scaleX(0);
  transform-origin: 100% 50%;
  transition: transform var(--t-base) var(--ease);
}
.nav__link:hover { color: #DEEAE4; }
/* The one masthead link that leads off the home page, marked while you are there. */
.nav__link[aria-current="page"] { color: #DEEAE4; }
.nav__link[aria-current="page"]::after { transform: scaleX(1); }
.nav__link:hover::after { transform: scaleX(1); transform-origin: 0 50%; }

.masthead__actions { display: flex; align-items: center; gap: 10px; }

/* Language toggle — a real control, because the product is bilingual and its
   audience is. Two cells and a thumb that slides between them. */
.lang {
  position: relative;
  display: inline-flex;
  padding: 3px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(157, 178, 192, .16);
}
.lang__thumb {
  position: absolute;
  top: 3px; left: 3px;
  width: calc(50% - 3px);
  height: calc(100% - 6px);
  border-radius: 999px;
  background: rgba(255, 255, 255, .1);
  transition: transform var(--t-base) var(--ease);
}
.lang[data-lang="fr"] .lang__thumb { transform: translateX(100%); }
.lang__opt {
  position: relative;
  z-index: 1;
  display: inline-block;
  width: 40px;
  padding: 5px 0;
  text-align: center;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .12em;
  color: #879D97;
  transition: color var(--t-base) var(--ease-sym);
}
.lang__opt:hover { color: #C4D3CD; }
.lang__opt[aria-current] { color: #DEEAE4; }

/* Mobile drawer */
.burger {
  display: grid;
  place-items: center;
  width: 40px; height: 40px;
  border-radius: 12px;
  border: 1px solid rgba(157, 178, 192, .18);
}
@media (min-width: 1200px) { .burger { display: none; } }
.burger span {
  display: block; width: 16px; height: 1.5px; background: #DEEAE4;
  transition: transform var(--t-base) var(--ease), opacity var(--t-fast) linear;
}
.burger span + span { margin-top: 4px; }
[aria-expanded="true"].burger span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
[aria-expanded="true"].burger span:nth-child(2) { opacity: 0; }
[aria-expanded="true"].burger span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

.drawer {
  position: fixed;
  inset: 0;
  z-index: 79;
  /* Plain value first: where color-mix() is unsupported the declaration below
     is dropped entirely, and a transparent full-screen menu is unreadable
     rather than merely unstyled. */
  background: rgba(6, 15, 13, .96);
  background: color-mix(in srgb, var(--ink-900) 96%, transparent);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  display: grid;
  align-content: center;
  padding: 0 var(--gutter);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-base) var(--ease-sym), visibility var(--t-base);
}
.drawer.is-open { opacity: 1; visibility: visible; }
.drawer a {
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(2rem, 9vw, 3rem);
  letter-spacing: -.03em;
  padding: 10px 0;
  border-bottom: 1px solid var(--rule);
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}
.drawer.is-open a { opacity: 1; transform: none; }
.drawer.is-open a:nth-child(1) { transition-delay: 60ms; }
.drawer.is-open a:nth-child(2) { transition-delay: 110ms; }
.drawer.is-open a:nth-child(3) { transition-delay: 160ms; }
.drawer.is-open a:nth-child(4) { transition-delay: 210ms; }
.drawer.is-open a:nth-child(5) { transition-delay: 260ms; }
.drawer.is-open a:nth-child(6) { transition-delay: 310ms; }
.drawer.is-open a:nth-child(7) { transition-delay: 360ms; }

/* The menu's own call to action. It is a button, so it drops the oversized
   display face and the rule the navigation links carry. */
.drawer__cta {
  justify-self: start;
  margin-top: 28px;
  font-family: var(--sans);
  font-size: 16.5px;
  letter-spacing: -.005em;
  border-bottom: 0;
  padding: 18px 34px;
}
/* The second of two: close under the first, not another section's gap away. */
.drawer__cta--next { margin-top: 12px; }

/* --------------------------------------------------------------- 7. Buttons */

.btn {
  --btn-bg: var(--mint);
  --btn-fg: var(--ink-900);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 15px 26px;
  border-radius: 999px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -.005em;
  white-space: nowrap;
  isolation: isolate;
  overflow: hidden;
  transition: transform var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease);
  /* The magnetic pull arrives as two custom properties rather than as a whole
     transform, so the press state below composes with it. Written as one
     transform, an inline style from the script outranked :active and primary
     buttons had no press feedback at all on a desktop. */
  transform: translate(var(--mx, 0px), var(--my, 0px));
}
/* Promoted while it is actually being moved, not for the life of the page. */
.btn:hover, .btn:focus-visible { will-change: transform; }
.btn::before {
  /* The bloom: a soft radial that tracks the pointer, so the surface looks lit
     from wherever the cursor is rather than uniformly bright. */
  content: "";
  position: absolute;
  inset: -60%;
  z-index: -1;
  background: radial-gradient(220px circle at var(--px, 50%) var(--py, 50%),
              rgba(255, 255, 255, .55), transparent 62%);
  opacity: 0;
  transition: opacity var(--t-base) var(--ease-sym);
}
.btn:hover { box-shadow: 0 14px 34px -12px rgba(46, 211, 160, .6); }
.btn:hover::before { opacity: 1; }
.btn:active { transform: translate(var(--mx, 0px), var(--my, 0px)) scale(.975); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--fg-1);
  border: 1px solid var(--rule-strong);
}
.btn--ghost::before { background: radial-gradient(220px circle at var(--px, 50%) var(--py, 50%), rgba(46, 211, 160, .2), transparent 62%); }
.btn--ghost:hover { box-shadow: none; border-color: var(--accent); }

/* Release status. A pill rather than a banner: the fact belongs beside the
   name, as a property of the product, not as an announcement bar the visitor
   has to dismiss before reading anything. The dot pings slowly — one signal of
   life on a page that is otherwise still. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px 5px 10px;
  border-radius: 999px;
  border: 1px solid rgba(46, 211, 160, .32);
  background: rgba(46, 211, 160, .08);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--mint-lo);
  white-space: nowrap;
}
.pill__dot {
  position: relative;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--mint);
  flex: none;
}
.pill__dot::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  border: 1px solid var(--mint);
  animation: ping 2800ms var(--ease-sym) infinite;
}
@keyframes ping {
  0%        { transform: scale(.55); opacity: .9; }
  70%, 100% { transform: scale(2);   opacity: 0; }
}

/* In the masthead the pill sits with the wordmark; on narrow screens the row
   belongs to the brand, the language toggle and the menu, and the hero states
   the same fact two lines below. */
.masthead .pill { display: none; }
@media (min-width: 780px) { .masthead .pill { display: inline-flex; } }

.hero__status { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.masthead__brand { display: flex; align-items: center; gap: 14px; }

.btn--lg { padding: 18px 34px; font-size: 16.5px; }
/* "Tell me when Android and iOS ship" is wider than a 360px phone allows once
   the padding is added, and .btn clips rather than overflows. Wrap it there. */
@media (max-width: 480px) {
  .btn--lg { white-space: normal; text-align: center; max-width: 100%; }
}
.btn--sm { padding: 10px 18px; font-size: 14px; }
/* Narrow screens now keep the call to action, so the row has to earn the
   space back somewhere else: the wordmark stands down and the mark carries the
   brand alone. Without this the masthead is wider than a phone, and since the
   body clips overflow the whole page appeared cut off at the right edge. */
@media (max-width: 560px) {
  .btn--sm { padding: 9px 15px; font-size: 13.5px; }
  .masthead__inner { gap: 12px; }
  .masthead__actions { gap: 8px; }
  .masthead .brand__word { display: none; }
  .lang__opt { width: 33px; letter-spacing: .08em; }
  .burger { width: 38px; height: 38px; }
}
.btn__arrow { transition: transform var(--t-base) var(--ease); }
.btn:hover .btn__arrow { transform: translateX(4px); }

.btn-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }

/* A quieter call to action: text with a rule that redraws on hover. */
.link-cta {
  display: inline-flex;
  justify-self: start;
  width: fit-content;
  align-items: center;
  gap: 9px;
  font-size: 15px;
  font-weight: 600;
  color: var(--accent);
  padding-bottom: 3px;
  position: relative;
}
.link-cta::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px; background: currentColor;
  transform-origin: 100% 50%;
  transition: transform var(--t-base) var(--ease);
}
.link-cta:hover::after { transform: scaleX(0); transform-origin: 0 50%; }
.link-cta svg { transition: transform var(--t-base) var(--ease); }
.link-cta:hover svg { transform: translateX(4px); }

/* ----------------------------------------------------------------- 8. Cards */

.card {
  position: relative;
  background: var(--raised);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: clamp(22px, 2.4vw, 30px);
  overflow: hidden;
  transition: border-color var(--t-slow) var(--ease), transform var(--t-slow) var(--ease),
              background var(--t-slow) var(--ease);
}
/* A 3px capping rule in the accent — lifted straight from the app's stat cards,
   which is what ties the site's surfaces to the product's. */
.card--capped::before {
  content: "";
  position: absolute; inset: 0 0 auto 0;
  height: 3px;
  background: var(--cap, var(--accent));
  transform-origin: 0 50%;
  transition: transform var(--t-slow) var(--ease);
}
.js .card--capped::before { transform: scaleX(0); }
.js .card--capped.is-in::before,
.js .is-in .card--capped::before { transform: scaleX(1); }

.card:hover { border-color: var(--rule-strong); }
.card__icon {
  width: 42px; height: 42px;
  border-radius: 13px;
  display: grid; place-items: center;
  background: var(--tint-wash, rgba(46, 211, 160, .16));
  color: var(--tint, var(--accent));
  margin-bottom: 18px;
}

/* One tint per feature card, driving the capping rule and the icon together.
   These were six pairs of inline styles, each carrying an unguarded
   color-mix(); as classes they are one place to change, and one reason fewer
   to allow inline styles in the policy. */
.tint-mint    { --cap: var(--mint);    --tint: var(--mint);    --tint-wash: rgba(46, 211, 160, .16); }
.tint-azure   { --cap: var(--azure);   --tint: var(--azure);   --tint-wash: rgba(111, 180, 220, .16); }
.tint-violet  { --cap: var(--violet);  --tint: var(--violet);  --tint-wash: rgba(201, 139, 185, .16); }
.tint-gain    { --cap: var(--gain);    --tint: var(--gain);    --tint-wash: rgba(98, 224, 182, .16); }
.tint-brass   { --cap: var(--brass);   --tint: var(--brass);   --tint-wash: rgba(217, 164, 65, .16); }
.tint-mint-lo { --cap: var(--mint-lo); --tint: var(--mint-lo); --tint-wash: rgba(98, 224, 182, .16); }
.card__body { color: var(--fg-2); font-size: 15.5px; line-height: 1.58; margin-top: 10px; }

/* Feature cards tilt very slightly toward the pointer. The rotation ceiling is
   deliberately under 4deg: enough to feel like a physical object catching
   light, not enough to become a gimmick. */
.tilt:hover, .tilt:focus-within { will-change: transform; }

/* The specification list in the privacy panel. Term left, value right, on the
   same hairline rhythm as the ledger rows — a datasheet, deliberately, because
   the claim being made there is a technical one. */
.spec { margin: 0; display: grid; }
.spec > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  padding: 11px 0;
  border-top: 1px solid var(--rule);
}
.spec > div:first-child { border-top: 0; padding-top: 0; }
.spec dt { color: var(--fg-2); font-size: 14.5px; }
.spec dd {
  margin: 0;
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: .02em;
  color: var(--fg-1);
  text-align: right;
}

/* ------------------------------------------------------- 9. Ledger surfaces */

/* The product's own card language, rebuilt for the web at 1:1 with the app so
   the screenshots on this page are the app, not an illustration of it. */
.ledger {
  background: var(--paper-000);
  color: #0F2019;
  border-radius: 16px;
  box-shadow: 0 1px 2px rgba(22, 35, 46, .06), 0 8px 20px rgba(22, 35, 46, .045);
  overflow: hidden;
}
.ledger__row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  border-top: 1px solid var(--paper-300);
}
.ledger__row:first-child { border-top: 0; }
.ledger__date { width: 42px; text-align: center; flex: none; font-size: 11px; color: #556A60; }
.ledger__name { flex: 1 1 auto; min-width: 0; font-size: 14px; font-weight: 600; }
.ledger__amt { text-align: right; flex: none; }
.ledger__amt b { display: block; font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: 13.5px; font-weight: 700; }
.ledger__amt span { font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: 11px; color: var(--fg-3); }
/* Brass on a dashed rule, at full strength - which is exactly what the column
   beside this one promises the app does. Dimming the row to .55 put the amount
   at 2.6:1 and the running balance at 2.3:1, and made the demo contradict its
   own caption. */
.ledger__row--future {
  border-top-style: dashed;
  border-top-color: var(--brass-ink);
}
.ledger__row--future .ledger__name,
.ledger__row--future .ledger__date,
.ledger__row--future .ledger__amt b,
.ledger__row--future .ledger__amt span { color: var(--brass-ink); }

.chip {
  display: inline-block;
  margin-top: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
}
.chip--green   { background: #DDF2EA; color: #0B6B52; }
.chip--blue    { background: #E3EEF5; color: #2A6489; }
.chip--amber   { background: var(--brass-wash); color: var(--brass-ink); }
.chip--violet  { background: #F0E6F0; color: #7A4079; }
.chip--neutral { background: #E3EAE7; color: #556A60; }

.amt-gain  { color: #0B6B52; }
.amt-spend { color: #A9331C; }

/* Device — the phone that holds a real screen. Kept as a frame, not a
   photograph, so it stays crisp at every size and weighs nothing. */
.device {
  position: relative;
  width: 100%;
  max-width: 288px;
  border-radius: 40px;
  padding: 10px;
  background: linear-gradient(160deg, #1B322C, #0C1A17 60%);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .75), 0 0 0 1px rgba(157, 178, 192, .16),
              inset 0 1px 0 rgba(255, 255, 255, .12);
}
.device__screen {
  border-radius: 31px;
  background: var(--paper-100);
  overflow: hidden;
  padding: 16px 12px 12px;
  display: grid;
  gap: 10px;
  color: #0F2019;
}
.device__notch {
  position: absolute;
  top: 10px; left: 50%;
  transform: translateX(-50%);
  width: 92px; height: 20px;
  border-radius: 0 0 14px 14px;
  background: #0C1A17;
  z-index: 2;
}
.device__bar {
  display: flex;
  justify-content: space-around;
  padding-top: 12px;
  margin-top: auto;
  border-top: 1px solid var(--paper-300);
  color: #556A60;
}
.device__bar i { display: block; width: 18px; height: 18px; border-radius: 5px; background: currentColor; opacity: .35; }
.device__bar i.on { background: var(--mint-deep); opacity: 1; }

.device__topbar { display: flex; align-items: center; justify-content: space-between; }
.device__topbar strong { font-size: 17px; letter-spacing: -.025em; }
.device__add {
  width: 30px; height: 30px;
  border-radius: 10px;
  background: var(--mint-deep);
  display: grid; place-items: center;
}

/* The full-size product shot: the app at close to its real width, so chips,
   figures and the reconciliation letters stay readable rather than becoming
   texture. Centred in its column, because a phone floated left in a wide
   column reads as an accident. */
.device--full { max-width: 352px; }
.device--full .device__screen { padding: 20px 14px 14px; gap: 14px; }
.stage { display: grid; justify-items: center; }

/* ----------------------------------------------------- 10. Projection panel */

/* The hero object. It draws a running balance, then keeps drawing past today
   in a dashed line — which is literally the feature the headline promises. The
   demo and the claim are the same artefact. */
.panel {
  position: relative;
  border-radius: var(--radius-lg);
  padding: clamp(20px, 2.4vw, 30px);
  background: linear-gradient(150deg, rgba(46, 211, 160, .1), rgba(255, 255, 255, .03) 42%),
              rgba(255, 255, 255, .04);
  border: 1px solid rgba(157, 178, 192, .18);
  box-shadow: var(--shadow-lift);
  /* No backdrop-filter here. It sat over the hero's two 90px blurs and was
     parallaxed, so every frame re-sampled a blurred surface through a second
     filter - the most expensive paint on the page, wrapped around the largest
     contentful one. Over a near-black ground it bought nothing visible. */
}
.panel__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
  flex-wrap: wrap;
}
/* Narrow: the date stamp goes above the figure rather than fighting it for a
   half-width column that neither can use. */
@media (max-width: 640px) {
  .panel__head { flex-direction: column-reverse; gap: 10px; }
  .panel__head > p:last-child { text-align: left; }
}
.panel__chart { position: relative; }
.panel__chart svg { width: 100%; height: auto; overflow: visible; }

/* The posted line draws itself. --len is the path's own measured length, handed
   over by JS, so the keyframe works on any geometry; if JS never runs the custom
   property stays unset, the declaration is invalid, and the line simply renders
   complete — which is the right fallback. */
.draw { stroke-dasharray: var(--len); stroke-dashoffset: var(--len); }
.is-in .draw { animation: draw 1500ms var(--ease) forwards; }
@keyframes draw { to { stroke-dashoffset: 0; } }

/* The projected half is wiped in from the "today" rule, continuing the gesture. */
.js .wipe {
  transform-box: view-box;
  transform-origin: 392px 0;
  transform: scaleX(0);
}
.is-in .wipe { animation: wipe 1300ms var(--ease) 900ms forwards; }
@keyframes wipe { to { transform: scaleX(1); } }

.js .area { opacity: 0; }
.is-in .area { animation: fade 1400ms var(--ease) 400ms forwards; }
@keyframes fade { to { opacity: 1; } }

/* The marker that lands on the projected end point once the line arrives. */
.js .marker {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: 50% 50%;
}
.is-in .marker { animation: markerIn 700ms var(--ease) 2000ms forwards; }
@keyframes markerIn {
  from { opacity: 0; transform: translateY(8px) scale(.92); }
  to   { opacity: 1; transform: none; }
}

.panel__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--fg-3);
}
.panel__legend span { display: inline-flex; align-items: center; gap: 8px; }
.panel__legend i { width: 16px; height: 2px; border-radius: 2px; background: var(--mint); }
.panel__legend i.dash {
  background: none;
  border-top: 2px dashed var(--brass);
  height: 0;
}

/* Stat cells beneath the chart: mono figures that count up on reveal. */
.cells {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  margin-top: 18px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.cells > div { background: var(--ground); padding: 14px 14px 15px; }
.cells .figure { font-size: clamp(1.05rem, 2vw, 1.4rem); }
.cells .eyebrow { font-size: 11px; letter-spacing: .12em; margin-bottom: 8px; }

/* The proof strip: the same cell object, given room to breathe and a fourth
   column. Reusing it rather than inventing a "stat band" is what keeps the
   page feeling like one system. */
.cells--wide { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 0; }
.cells--wide > div {
  padding: clamp(20px, 2.4vw, 30px);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 18px;
}
.cells--wide .figure { font-size: clamp(1.6rem, 3.4vw, 2.5rem); }
.cells--wide .eyebrow { font-size: 11.5px; align-items: start; }
@media (min-width: 860px) { .cells--wide { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* The instrument gauge in the masthead: the page's own running balance, read
   out in the same mono the product uses for figures. */
.readout {
  display: none;
  font-size: 11px;
  letter-spacing: .1em;
  color: #879D97;
  padding-right: 6px;
}
.readout b { color: #9DB3AB; font-weight: 500; }
@media (min-width: 1320px) { .readout { display: inline-block; } }

/* ------------------------------------------------------------ 11. Hero bays */

.hero {
  position: relative;
  padding-top: clamp(132px, 17vw, 210px);
  padding-bottom: clamp(70px, 9vw, 130px);
  background: var(--ink-800);
  overflow: hidden;
}
/* Two very soft mint auroras, set far apart and heavily blurred. They are the
   only light source in the room; everything else is a surface catching it. */
.hero::before, .hero::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  pointer-events: none;
}
.hero::before {
  width: 60vw; height: 60vw; max-width: 780px; max-height: 780px;
  top: -22%; right: -14%;
  background: radial-gradient(circle, rgba(46, 211, 160, .2), transparent 68%);
}
.hero::after {
  width: 46vw; height: 46vw; max-width: 560px; max-height: 560px;
  bottom: -26%; left: -12%;
  background: radial-gradient(circle, rgba(47, 111, 153, .22), transparent 70%);
}
.hero > * { position: relative; z-index: 1; }

.hero__grid { display: grid; gap: clamp(48px, 6vw, 70px); align-items: center; }
@media (min-width: 1040px) {
  .hero__grid { grid-template-columns: minmax(0, 1.06fr) minmax(0, 1fr); }
}

.hero__stage { position: relative; }

.trust {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
  margin-top: 8px;
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .05em;
  color: var(--fg-3);
}
.trust span { display: inline-flex; align-items: center; gap: 8px; }
.trust svg { color: var(--mint); flex: none; }

/* ------------------------------------------------------------ 12. Ticker */

/* A single hairline strip of the product's vocabulary, drifting. It divides the
   hero from the argument without a heading, and it carries the bilingual and
   Quebec-specific proof (OFX, Desjardins, AES-256) as texture rather than as a
   list someone has to read. */
.ticker {
  /* Off-screen for most of a page this long. Browsers stop animating inside a
     skipped subtree, so this is the entire fix. */
  content-visibility: auto;
  contain-intrinsic-size: auto 45px;
  border-block: 1px solid var(--rule);
  background: var(--ink-900);
  overflow: hidden;
  padding-block: 16px;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.ticker__track {
  display: flex;
  width: max-content;
  gap: 44px;
  animation: drift 46s linear infinite;
}
.ticker:hover .ticker__track { animation-play-state: paused; }
.ticker__track span {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-3);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 44px;
}
.ticker__track span::after { content: "◆"; color: var(--mint); font-size: 7px; }
@keyframes drift { to { transform: translateX(-50%); } }

/* ---------------------------------------------------------- 13. Numbered list */

.steps { counter-reset: step; display: grid; gap: 0; }
.step {
  counter-increment: step;
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr);
  column-gap: clamp(16px, 2.4vw, 32px);
  row-gap: 6px;
  padding-block: clamp(24px, 3vw, 36px);
  border-top: 1px solid var(--rule);
  align-items: start;
}
.step:last-child { border-bottom: 1px solid var(--rule); }
.step::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .1em;
  color: var(--accent);
  padding-top: 6px;
}
/* Title and body both live in the text column. Without the explicit placement
   the body auto-flows into the next row's first cell — the 48px index column —
   and collapses to one word per line. */
.step__title,
.step__body { grid-column: 2; }
.step__title { font-size: 1.15rem; font-weight: 600; letter-spacing: -.01em; margin-bottom: 6px; }
.step__body { color: var(--fg-2); font-size: 15.5px; max-width: 58ch; }
/* The three-column reading (index / title / body) needs the full measure to
   work; in a split column it crushes the body to a ribbon. So it is opt-in,
   used only where the list spans the page, and every other list stays two
   columns with the body under its title. */
@media (min-width: 900px) {
  .steps--wide .step { grid-template-columns: 48px minmax(0, 15rem) minmax(0, 1fr); align-items: baseline; }
  .steps--wide .step__title { grid-column: 2; margin-bottom: 0; }
  .steps--wide .step__body { grid-column: 3; }
}

/* ------------------------------------------------------------ 14. Accordion */

.faq { border-top: 1px solid var(--rule); }
.faq__item { border-bottom: 1px solid var(--rule); }
.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  width: 100%;
  text-align: left;
  padding: clamp(20px, 2.4vw, 28px) 0;
  font-size: clamp(1.02rem, 1.5vw, 1.2rem);
  font-weight: 600;
  letter-spacing: -.012em;
  color: var(--fg-1);
  transition: color var(--t-base) var(--ease-sym);
}
.faq__q:hover { color: var(--accent); }
.faq__sign { position: relative; width: 16px; height: 16px; flex: none; }
.faq__sign::before, .faq__sign::after {
  content: "";
  position: absolute; inset: 50% 0 auto 0;
  height: 1.5px; background: currentColor;
  transition: transform var(--t-base) var(--ease);
}
.faq__sign::after { transform: rotate(90deg); }
.faq__item.is-open .faq__sign::after { transform: rotate(0deg); }
.faq__a {
  overflow: hidden;
  height: 0;
  /* height:0 alone hid it from the eye but left all eleven answers readable
     straight through by a screen reader, while the button said "collapsed". */
  visibility: hidden;
  transition: height var(--t-slow) var(--ease),
              visibility 0s linear var(--t-slow);
}
.faq__item.is-open .faq__a {
  visibility: visible;
  transition-delay: 0s, 0s;
}
.faq__a > div {
  padding-bottom: clamp(20px, 2.4vw, 28px);
  color: var(--fg-2);
  max-width: 62ch;
  font-size: 15.8px;
}

/* ----------------------------------------------------------- 15. Closing CTA */

.close-cta {
  position: relative;
  background: var(--ink-900);
  overflow: hidden;
  text-align: center;
}
.close-cta::before {
  content: "";
  position: absolute;
  left: 50%; bottom: -46%;
  width: 120vw; height: 90vw;
  max-height: 900px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at 50% 100%, rgba(46, 211, 160, .3), transparent 62%);
  pointer-events: none;
}
.close-cta > * { position: relative; z-index: 1; }
.close-cta .eyebrow { justify-content: center; }
.close-cta .btn-row { justify-content: center; }

/* --------------------------------------------------------------- 16. Footer */

.footer {
  background: var(--ink-900);
  border-top: 1px solid var(--rule);
  padding-block: clamp(52px, 6vw, 84px) 34px;
  color: var(--fg-2);
  font-size: 14.5px;
}
.footer__grid {
  display: grid;
  gap: clamp(34px, 4vw, 56px);
  grid-template-columns: 1fr;
}
@media (min-width: 780px)  { .footer__grid { grid-template-columns: 1.6fr repeat(2, 1fr); } }
@media (min-width: 1040px) { .footer__grid { grid-template-columns: 2fr repeat(3, 1fr); } }

.footer h4 {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-3);
  margin: 0 0 16px;
}
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.footer li a { transition: color var(--t-base) var(--ease-sym); }
.footer li a:hover { color: var(--mint); }

.footer__base {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 28px;
  align-items: center;
  justify-content: space-between;
  margin-top: clamp(40px, 5vw, 64px);
  padding-top: 22px;
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .04em;
  color: var(--fg-3);
}

/* ------------------------------------------------------------- 17. Article */

/* Long-form pages (privacy, error) reuse the same system at a narrower measure
   so they never look like a different site. */
.article { max-width: 74ch; }
.article h2 { font-size: clamp(1.5rem, 2.6vw, 2.1rem); margin-top: 2.2em; margin-bottom: .5em; }
.article h2:first-of-type { margin-top: 1.4em; }
.article p, .article li { color: var(--fg-2); font-size: 16.5px; }
.article ul { padding-left: 1.1em; display: grid; gap: 8px; margin: 0 0 1.3em; }
.article li::marker { color: var(--accent); }
.article code {
  font-family: var(--mono);
  font-size: .88em;
  background: var(--raised-2);
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: 2px 7px;
}

/* --------------------------------------------------------------- 18. Motion */

/* The reveal. Content is masked by its own box and rises into it, the way a
   posted entry appears on a ledger line — not a generic fade-up. Children in a
   [data-stagger] group inherit an incremental delay from JS. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity var(--t-reveal) var(--ease),
    transform var(--t-reveal) var(--ease);
  transition-delay: var(--d, 0ms);
}
.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
}
/* Belt and braces: if an observer never fires - a stalled load, a browser
   reporting nothing intersecting - the script stamps .reveal-done on <html>
   and everything is simply visible. Content must never be stranded at
   opacity 0. */
.reveal-done [data-reveal] { opacity: 1; transform: none; }

/* Headlines reveal per line rather than as a block, which is what makes a
   display setting feel typeset rather than animated.

   The container must be a grid, not a block: the line masks are block-level, so
   in a block container the whitespace between them in the markup would each
   generate an empty line box and blow the setting apart. A grid container drops
   whitespace-only children, so the leading stays exactly as specified. */
.lines { display: grid; }
.line-mask { display: block; overflow: hidden; padding-bottom: .1em; margin-bottom: -.1em; }
.js .line-mask > span {
  display: block;
  transform: translateY(105%);
  transition: transform 1200ms var(--ease);
  transition-delay: var(--d, 0ms);
}
.is-in .line-mask > span { transform: none; }

/* ------------------------------------------------------ 14. Storage consent */

/* The first-visit notice. It sits on the ink ground whatever movement is behind
   it, because it is the site speaking rather than a section of the page — and
   because the one thing it must not look like is content that can be scrolled
   past and forgotten.

   Anchored to the bottom rather than thrown over the middle: nothing here is
   urgent enough to interrupt reading, and a visitor who ignores it entirely has
   still had nothing written to their device. */
.consent {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 78;
  background: rgba(6, 15, 13, .94);
  background: color-mix(in srgb, var(--ink-900) 94%, transparent);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border-top: 1px solid rgba(157, 179, 171, .17);
  padding: 18px var(--gutter) calc(18px + env(safe-area-inset-bottom, 0px));
  max-height: 45vh;
  overflow-y: auto;
  transform: translateY(101%);
  transition: transform var(--t-base) var(--ease);
}
.consent.is-in { transform: none; }
.consent[hidden] { display: none; }

.consent__inner {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 28px;
}

.consent__copy { flex: 1 1 34ch; min-width: 0; }

.consent__lede {
  margin: 0;
  font-size: 14px;
  line-height: 1.55;
  color: #DEEAE4;
  max-width: 82ch;
}
.consent__lede em { font-style: normal; color: var(--mint-lo); }

.consent__note {
  margin: 6px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: rgba(222, 234, 228, .62);
}
.consent__note a {
  color: var(--mint-lo);
  text-underline-offset: 3px;
}

.consent__actions {
  display: flex;
  gap: 10px;
  flex: 0 0 auto;
}

/* On a phone the buttons take the full width rather than crowding onto the end
   of a sentence, and the decline sits first so it is never the harder tap. */
@media (max-width: 640px) {
  .consent__actions { width: 100%; }
  .consent__actions .btn { flex: 1 1 0; justify-content: center; }
}

/* ------------------------------------------------------- 19. Notify form */

/* The one thing the site asks anybody for. It replaced a mailto: link, which
   did nothing at all for a visitor reading their mail in a browser tab - the
   page's entire purpose, resting on a protocol handler that may not exist.

   Built to work with the script blocked: a plain form that posts, redirects
   and gets. With script it swaps in place and never loses the page position. */

.notify {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  width: 100%;
  max-width: 520px;
  margin-inline: auto;
}
.notify__field { flex: 1 1 15rem; min-width: 0; display: grid; gap: 0; }

.notify__input {
  width: 100%;
  padding: 17px 20px;
  border-radius: 999px;
  border: 1px solid var(--rule-strong);
  background: var(--raised);
  color: var(--fg-1);
  font-size: 16px;                 /* 16px or iOS zooms the page on focus */
  font-family: var(--sans);
  transition: border-color var(--t-base) var(--ease-sym),
              background var(--t-base) var(--ease-sym);
}
.notify__input::placeholder { color: var(--fg-3); }
.notify__input:hover { border-color: var(--rule-strong); }
.notify__input:focus {
  outline: none;
  border-color: var(--mint);
  background: var(--raised-2);
}
.notify__input:focus-visible { outline: 2px solid var(--mint); outline-offset: 2px; }
.notify__input[aria-invalid="true"] { border-color: var(--spend); }

.notify .btn { flex: 0 0 auto; }
@media (max-width: 560px) {
  .notify__field { flex: 1 1 100%; }
  .notify .btn { flex: 1 1 100%; }
}

/* Honeypot: off-screen rather than display:none, because some bots skip
   anything that is not rendered. Never focusable, never announced. */
.notify__trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.notify__error {
  grid-column: 1 / -1;
  margin: 8px 4px 0;
  font-size: 13.5px;
  color: var(--spend);
  text-align: left;
}
.notify__note {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--fg-3);
  max-width: 52ch;
  margin-inline: auto;
  text-align: center;
}

/* The answer. Same measure and rhythm as the form it replaces, so the block
   does not jump when it swaps. */
.notify-done {
  display: grid;
  gap: 10px;
  justify-items: center;
  padding: 22px 24px;
  border: 1px solid rgba(46, 211, 160, .32);
  border-radius: var(--radius);
  background: rgba(46, 211, 160, .07);
  max-width: 520px;
  margin-inline: auto;
  width: 100%;
}
.notify-done__mark {
  width: 38px; height: 38px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--mint);
  color: var(--ink-900);
}
.notify-done__title { font-size: 1.05rem; font-weight: 600; color: var(--fg-1); margin: 0; }
.notify-done__body { margin: 0; font-size: 14.5px; color: var(--fg-2); text-align: center; max-width: 44ch; }

/* --------------------------------------------------------- 20. Utilities */

/* Promoted from 59 inline style attributes. They are here rather than in the
   markup so the values have one home, and so the Content-Security-Policy can
   refuse inline styles outright instead of allowing them for the page's own
   sake. Each one earns its place by appearing in a view. */

/* Section padding for the pages that have no hero above them. */
.bay--article { padding-top: clamp(140px, 16vw, 210px); }
.bay--status  { padding-top: clamp(150px, 18vw, 240px); min-height: 78vh; }
.bay--tight   { padding-block: clamp(56px, 7vw, 96px); }

/* Reveal delays, so a group of two can be offset without a stagger group. */
.d-120 { --d: 120ms; }
.d-180 { --d: 180ms; }

/* Mono stamps: the small uppercase lines that date and qualify a page. */
.stamp {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .12em;
  color: var(--fg-3);
}
.stamp--status { margin-top: 18px; font-size: 11.5px; color: var(--mint-lo); }
.stamp--fine   { font-size: 11.5px; letter-spacing: .06em; text-align: center; }
.stamp--wide   { font-size: 11.5px; letter-spacing: .1em; margin-top: 6px; }

.center       { text-align: center; }
.measure-34   { max-width: 34ch; }
.measure-50   { max-width: 50ch; }
.split--top   { align-items: start; }
.mb-8         { margin-bottom: 8px; }
.mb-22        { margin-bottom: 22px; }
.pull         { margin-top: clamp(10px, 1.4vw, 14px); }

.txt-mint      { color: var(--mint); }
.txt-mint-deep { color: var(--mint-deep); }
.txt-fg1       { color: var(--fg-1); }
.txt-fg3       { color: var(--fg-3); }

.figure--tight { letter-spacing: -.04em; }

/* The FAQ's left column stays with the questions while they are read. */
.sticky-col { position: sticky; top: 120px; }

/* The projection panel's date stamp, and the note under its spec sheet. */
.panel__stamp {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .12em;
  color: var(--fg-3);
  text-align: right;
  margin: 0;
}
.panel__note { margin-top: 22px; font-size: 14.5px; }

/* The closing section. */
.close-cta__stack { justify-items: center; max-width: 820px; }

/* The device mock's own header row, and the reconciliation letters that mark
   a row as checked against a statement or keyed by hand. */
.ledger__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 14px 10px;
}
.ledger__head-title { font-size: 14px; }
.ledger__all {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--mint-deep);
  font-weight: 600;
}
.recon--r { color: var(--mint-deep); }
.recon--m { color: var(--brass-ink); }

/* The footer's blurb and its pre-launch status line. */
.footer__blurb  { margin-top: 20px; max-width: 34ch; }

/* One-column cells, used for the request id on the error page. */
.cells--single { grid-template-columns: 1fr; max-width: 520px; }
.error__id { font-size: 14px; word-break: break-all; margin: 0; }

/* Licenses: the copyright lines beside each component name. */
.mono-xs { font-size: 13.5px; }

/* The status page's code, set at hero scale because it is the page's subject. */
.status__code { font-size: clamp(2.4rem, 5.4vw, 4.2rem); }
.status__path {
  font-family: var(--mono);
  font-size: 13.5px;
  color: var(--fg-3);
  word-break: break-all;
}

/* ------------------------------------------------------------------ 21. Help */

/* The user guide. Its articles come from the app's own help file, a format of
   plain lines with no inline markup, so everything here styles elements the
   view writes, never anything an article could carry itself.

   An index of cards and a two-column reader: the article, and a pinned list of
   every topic beside it on a wide screen, under it on a phone. */

.help-search { display: none; gap: 12px; max-width: 560px; }
.js .help-search { display: grid; }
.help-search__input { padding: 15px 22px; }
.help-search__input::-webkit-search-cancel-button { filter: grayscale(1); opacity: .6; }
.help-search__none { color: var(--fg-2); font-size: 15px; margin: 4px 0 0; }

/* The filter hides with [hidden]; .step and the grids set their own display,
   which would otherwise win over the browser's. */
[data-help-item][hidden],
[data-help-group][hidden] { display: none !important; }

.help-group { display: grid; gap: clamp(16px, 2vw, 24px); }
.help-group__title {
  font-size: clamp(1.45rem, 2.4vw, 1.95rem);
  padding-top: 18px;
  border-top: 1px solid var(--rule);
}
.help-group__intro { margin: -4px 0 0; }

.help-tour { list-style: none; margin: 0; padding: 0; }
.help-link { color: var(--fg-1); transition: color var(--t-base) var(--ease-sym); }
.help-link:hover { color: var(--accent); }

.help-card { display: grid; align-content: start; gap: 8px; color: var(--fg-1); }
.help-card:hover { background: var(--raised-2); }
.help-card__title {
  font-family: var(--sans);
  font-size: 1.06rem;
  font-weight: 600;
  letter-spacing: -.01em;
  line-height: 1.3;
  font-variation-settings: normal;
}
.help-card:hover .help-card__title { color: var(--accent); }
.help-card__summary { color: var(--fg-2); font-size: 15px; line-height: 1.5; margin: 0; }

.help-contact .prose a,
.help-contact a { color: var(--accent); box-shadow: inset 0 -1px 0 currentColor; }

/* ----- The reader */

.help-layout { display: grid; gap: clamp(48px, 6vw, 72px); }
@media (min-width: 1040px) {
  .help-layout { grid-template-columns: 250px minmax(0, 1fr); align-items: start; }
  .help-layout > .help-nav { order: -1; position: sticky; top: 112px; max-height: calc(100vh - 136px); overflow-y: auto; }
}

.help-article { min-width: 0; max-width: 74ch; }

.help-crumbs {
  display: flex; flex-wrap: wrap; gap: 10px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-3);
  margin-bottom: 22px;
}
.help-crumbs a { color: var(--accent); }
.help-crumbs a:hover { box-shadow: inset 0 -1px 0 currentColor; }

.help-article__title { font-size: clamp(2.1rem, 4.6vw, 3.4rem); }
.help-article__summary {
  margin: 16px 0 0;
  font-size: clamp(1.05rem, 1.45vw, 1.2rem);
  color: var(--fg-3);
  max-width: 56ch;
}

.help-toc {
  margin-top: 30px;
  padding: 18px 22px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  background: var(--raised);
}
.help-toc ul { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 6px; }
.help-toc a { color: var(--fg-2); font-size: 15px; }
.help-toc a:hover { color: var(--accent); }

.help-body { margin-top: 34px; }
.help-body .help-lead { color: var(--fg-1); font-size: clamp(1.08rem, 1.5vw, 1.22rem); line-height: 1.6; }
.help-body h2 { scroll-margin-top: 110px; }
.help-anchor {
  margin-left: .35em;
  color: var(--fg-3);
  opacity: 0;
  font-family: var(--mono);
  font-size: .6em;
  vertical-align: middle;
  transition: opacity var(--t-base) var(--ease-sym);
}
.help-body h2:hover .help-anchor,
.help-anchor:focus-visible { opacity: 1; }

.help-steps { list-style: none; margin: 0 0 1.3em; padding: 0; display: grid; gap: 0; }
.help-steps li {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  padding: 14px 0;
  border-top: 1px solid var(--rule);
  color: var(--fg-2);
  font-size: 16.5px;
}
.help-steps li:last-child { border-bottom: 1px solid var(--rule); }
.help-steps__n {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .1em;
  color: var(--accent);
  padding-top: 5px;
}

/* A screenshot: a phone-sized frame, centred in the column. Drawn at about two thirds of
   its captured width so a phone capture reads as a phone rather than filling a desktop
   column; max-width keeps it inside the gutter on a narrow screen. */
.help-figure {
  margin: 8px auto 34px;
  width: min(100%, 310px);
  display: grid;
  gap: 12px;
  justify-items: center;
}
.help-figure a { display: block; width: 100%; border-radius: 22px; }
.help-figure a:hover img { border-color: var(--accent); }
.help-figure img {
  width: 100%;
  height: auto;
  border-radius: 22px;
  border: 1px solid var(--rule-strong);
  box-shadow: var(--shadow-lift);
  background: var(--ink-900);
  transition: border-color var(--t-base) var(--ease-sym);
}
.help-figure figcaption {
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--fg-3);
  text-align: center;
}

/* An aside in the app is a tinted panel with a rule down its edge. Brass would
   say "forecast" here, so the rule is the accent. */
.help-note {
  margin: 0 0 1.3em;
  padding: 16px 20px;
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--raised);
}
.help-note p { color: var(--fg-1); margin: 0; }

.help-related { margin-top: clamp(48px, 6vw, 72px); display: grid; gap: 20px; }
.help-related__grid { display: grid; gap: 14px; }
@media (min-width: 700px) { .help-related__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.help-pager {
  margin-top: 40px;
  display: grid;
  gap: 14px;
}
@media (min-width: 700px) { .help-pager { grid-template-columns: 1fr 1fr; } }
.help-pager__link {
  display: grid;
  gap: 6px;
  padding: 16px 20px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  transition: border-color var(--t-base) var(--ease-sym);
}
.help-pager__link:hover { border-color: var(--accent); }
.help-pager__link--next { text-align: right; grid-column: -2; }
.help-pager__link--next .eyebrow { justify-content: flex-end; }
.help-pager__title { font-weight: 600; color: var(--fg-1); }

.help-nav { display: grid; align-content: start; gap: 6px; font-size: 14.5px; }
.help-nav__group {
  margin: 16px 0 2px;
  color: var(--fg-1);
  font-weight: 600;
  font-size: 13.5px;
}
.help-nav ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.help-nav li a {
  display: block;
  padding: 5px 10px;
  margin-left: -10px;
  border-radius: 8px;
  color: var(--fg-2);
  line-height: 1.35;
  transition: color var(--t-base) var(--ease-sym), background var(--t-base) var(--ease-sym);
}
.help-nav li a:hover { color: var(--fg-1); background: var(--raised); }
.help-nav li a[aria-current="page"] { color: var(--accent); background: var(--raised-2); }
.help-nav__home { margin-top: 18px; color: var(--accent); font-weight: 600; }

/* --------------------------------------------------------- 22. Reduced motion */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  [data-reveal] { opacity: 1; transform: none; }
  .line-mask > span { transform: none; }
  .draw { stroke-dasharray: none; stroke-dashoffset: 0; }
  .wipe { transform: none; }
  .area, .marker { opacity: 1; }
  .ticker__track { animation: none; }
  .pill__dot::after { display: none; }
  .consent { transform: none; }
}
