/* ============================================================
   MATTERA · v3 — light editorial theme
   Paper-white canvas · LT Superior Serif display · Geist body
   IBM Plex Mono for labels and § data callouts (carried from v2)

   TONE SYSTEM — the load-bearing idea in this file.
   Every colour is a token. Light is the default on :root; `.tone-dark`
   re-points the SAME token names at a deep-navy palette. So a component
   written once ("border: 1px solid var(--line)") renders correctly in
   both tones with no duplicated rules and no `.tone-dark .thing {}`
   overrides. This is what makes v3's dark band cheap instead of a
   second stylesheet — and it is why v2's colour-agnostic animation
   stages port across untouched.

   Class hooks (.reveal, .display, .lead, .eyebrow, .container, .section,
   .radial, .nav) match v2 so assets/v3/v3.js works unchanged.
   ============================================================ */

/* ---------- tone tokens that cross-fade ----------
   Plain custom properties do not interpolate — they snap. Registering these as
   <color> is what turns the page-wide tone flip into ONE 500ms interpolation
   declared on <html> (see html.tone-live) instead of a transition on every
   painted element. Descendants that merely CONSUME a token need no transition
   of their own, which is why nothing below this block had to change: the
   `background: var(--paper)` shorthand the file already uses everywhere
   follows the animated value on its own.

   The literal declarations in :root below are unchanged and still authoritative.
   Where @property is unsupported the tokens are simply unregistered and snap —
   exactly today's behaviour, nothing goes uncoloured.

   NOT registered, deliberately: --ink-rgb / --shadow-rgb are number triplets
   rather than colours (registering them as <color> would invalidate every
   rgba(var(--ink-rgb), a) at once), and --brand-mark is the logo's own value,
   not a palette choice — it reads on both tones. */
@property --paper        { syntax: "<color>"; inherits: true; initial-value: #FFFFFF; }
@property --paper-2      { syntax: "<color>"; inherits: true; initial-value: #FAF8F5; }
@property --paper-3      { syntax: "<color>"; inherits: true; initial-value: #F1EEE9; }
@property --ink          { syntax: "<color>"; inherits: true; initial-value: #14181D; }
@property --ink-2        { syntax: "<color>"; inherits: true; initial-value: #4C5663; }
@property --ink-3        { syntax: "<color>"; inherits: true; initial-value: #7C8593; }
@property --ink-4        { syntax: "<color>"; inherits: true; initial-value: #A8B0BB; }
@property --line         { syntax: "<color>"; inherits: true; initial-value: rgba(20,24,29,.11); }
@property --line-soft    { syntax: "<color>"; inherits: true; initial-value: rgba(20,24,29,.055); }
@property --line-strong  { syntax: "<color>"; inherits: true; initial-value: rgba(20,24,29,.22); }
@property --ember        { syntax: "<color>"; inherits: true; initial-value: #3E8F52; }
@property --ember-bright { syntax: "<color>"; inherits: true; initial-value: #2F9E56; }
@property --warn         { syntax: "<color>"; inherits: true; initial-value: #B4642F; }
@property --btn-bg       { syntax: "<color>"; inherits: true; initial-value: #1A2F4A; }
@property --btn-bg-hover { syntax: "<color>"; inherits: true; initial-value: #24405F; }
@property --btn-fg       { syntax: "<color>"; inherits: true; initial-value: #FFFFFF; }
@property --brand-word   { syntax: "<color>"; inherits: true; initial-value: #000000; }
@property --brand-blue   { syntax: "<color>"; inherits: true; initial-value: #184371; }
@property --nav-glass    { syntax: "<color>"; inherits: true; initial-value: rgba(255,255,255,.46); }
@property --glass-edge   { syntax: "<color>"; inherits: true; initial-value: rgba(20,32,48,.14); }

:root {
  /* ---- paper (light tone) ---- */
  --paper:       #FFFFFF;   /* primary canvas */
  --paper-2:     #FAF8F5;   /* warm off-white band — alternating sections */
  --paper-3:     #F1EEE9;   /* recessed panels, insets */

  /* ---- ink ---- */
  --ink:         #14181D;   /* headings, primary text */
  --ink-2:       #4C5663;   /* body copy */
  --ink-3:       #7C8593;   /* muted labels, eyebrows */
  --ink-4:       #A8B0BB;   /* faintest — annotations, meta */

  /* ---- brand navy, carried from v2 ---- */
  --navy:        #1A2F4A;   /* buttons, radial linework, accents */
  --navy-lift:   #24405F;   /* navy hover / raised */
  /* Straight from the supplied artwork (mattera-logo.svg): the glyph carries
     .cls-1 { fill:#82bfff } and the wordmark declares no fill, so it renders
     black. Not interpreted, not harmonised with the site palette — these ARE
     the logo. (docs/brand-strategy-kit.md still describes a cream glyph on
     forest green; that document predates v2 and is wrong on both counts.) */
  --brand-mark:  #82bfff;
  --brand-word:  #000000;
  /* The hero H1's "PAGA". A token rather than a literal because it is the one
     brand colour that must re-tone: #184371 is 10.09:1 on paper and 1.77:1 on
     the dark canvas. */
  --brand-blue:  #184371;

  /* ---- solid controls ----
     One pair feeds .btn-primary, .hero-form button, .val-start and ::selection.
     They used to be `var(--navy)` plus a `.tone-dark <descendant>` override
     each; that shape only fires INSIDE a dark section, so under a page-wide
     dark tone every one of them would have painted navy-on-navy. Expressing
     them as tone tokens is what makes the whole set follow automatically. */
  --btn-bg:       var(--navy);
  --btn-bg-hover: var(--navy-lift);
  --btn-fg:       #FFFFFF;

  /* ---- lines ---- */
  --line:        rgba(20,24,29,.11);
  --line-soft:   rgba(20,24,29,.055);
  --line-strong: rgba(20,24,29,.22);
  /* The scrolled nav's glass tint and the .glass-card hairline. Tokens for the
     same reason as the controls above. */
  --nav-glass:   rgba(255,255,255,.46);
  --glass-edge:  rgba(20,32,48,.14);

  /* Ink as a raw RGB triplet, so the animation stages can build their own
     alphas — rgba(var(--ink-rgb), .12) — instead of hardcoding v2's cream.
     This is what lets one set of stage rules read correctly on paper, on the
     dark tone, and inside a .surface-blue island. */
  --ink-rgb:    20,24,29;
  --shadow-rgb: 20,32,48;   /* the stages' dry offset shadow */

  /* ---- signal colours (semantic in the viz stages) ----
     Deepened vs v2's values so they hold contrast against white. */
  --ember:        #3E8F52;  /* supported / confirmed */
  --ember-bright: #2F9E56;  /* the rare highlight that should pop */
  --warn:         #B4642F;  /* gaps, unsupported, deadlines */

  /* Each stack: real font -> metric-matched fallback (fonts.css) -> generic,
     so a late swap changes glyph shapes but never layout. */
  --display: "LT Superior Serif", "LT Superior Serif Fallback", Georgia, serif;
  --sans:    "Geist", "Geist Fallback", system-ui, sans-serif;
  --mono:    "IBM Plex Mono", "IBM Plex Mono Fallback", ui-monospace, monospace;

  /* Responsive gutter system — carried verbatim from v2 (mattera-v2.css:55).
     Well-tuned and tone-independent: below ~1589px the clamp ramp wins and
     content holds ~90%; above it the framed block caps at 1500px so the
     gutters absorb all extra width. */
  --frame:       max(clamp(16px, 2.8vw, 56px), calc((100vw - 1500px) / 2));
  --edge-offset: clamp(12px, 2.2vw, 44px);
  --gutter:      calc(var(--frame) + var(--edge-offset));
  --section-y:   clamp(84px, 11vw, 168px);

  /* ---- hero rhythm ----
     These three set the hero's whole vertical composition, and with it the
     size of the radial dial: the dial's box is anchored to the heading's top
     and the trust line's bottom, so the span between those two IS the box.
     --nav-h must match the nav's real height. */
  --nav-h:         76px;
  /* trust line -> hero foot. DERIVED so the box's clearance above (from the
     nav rule) and below (to the next section) come out equal.
        topGap = heroH - nav - gapBot - inkOff - dialSpan + tuck
        botGap = gapBot + inkOff - tuck
     setting them equal gives the expression below. A fixed value here is what
     let the 28px tuck eat the whole bottom margin: 31 + 6 - 28 left 9px under
     the box against 164px above it. */
  --hero-gap-bot:  max(
                     24px,
                     calc((var(--hero-h) - var(--nav-h) - var(--dial-span)
                           + 2 * var(--dial-tuck) - 12px) / 2)
                   );

  /* v2's OWN dial sizing, reproduced exactly:
        v2: min(88% of its half-width column, 715px, 100svh - 140px)
     Its columns were a 1fr 1fr grid, so 88% of half the viewport = 44vw.
     This matters because v2 sized the dial off viewport WIDTH while v3 was
     sizing off HEIGHT — two different curves, which crossed. The dial came
     out larger than v2 on a 1512x982 laptop and smaller on a 1920x969
     monitor. Targeting v2's own formula makes it match on both. */
  --dial-span:     min(44vw, 715px, calc(100svh - 140px));

  /* How far the box overshoots the left column's type at BOTH ends. Aligning
     them dead-flush read as a coincidence rather than a decision; a small
     overshoot tucks the column inside the frame and makes the box look like it
     contains the composition. Plain px on purpose — the JS reads this value
     with parseFloat, and a clamp() would not resolve to a length there. */
  --dial-tuck:     28px;

  /* nav rule -> heading cap. Derived, not chosen: the box is the type span
     PLUS a tuck at each end, so for the box to equal --dial-span the type span
     must be (--dial-span - 2 x tuck) and the heading sits wherever that puts
     it. The + 2 x tuck term is what keeps the DIAL the same size once the tuck
     is added, instead of the box quietly growing by 36px. The 64px floor
     protects the spacing if a viewport is ever too short. */
  --hero-gap-top:  max(
                     64px,
                     calc(var(--hero-h) - var(--nav-h) - var(--hero-gap-bot) - 6px
                          - var(--dial-span) + 2 * var(--dial-tuck))
                   );

  /* The hero is exactly one viewport tall, so the next section begins precisely
     at the fold. That is not a stylistic flourish — it is where the breathing
     room comes from. The content is a fixed height; the only way to buy space
     above the headline (and the matching space below it) is to let the section
     claim the full screen and hand the surplus to the gaps.

     svh, not vh or dvh: svh is the viewport with mobile browser chrome VISIBLE
     — the smallest it gets — so the hero never gets taller than the screen when
     the URL bar is showing, and never resizes mid-scroll the way dvh does.

     No upper cap. A cap would break fold-alignment on tall displays, which is
     the whole point. The dial stays capped at --dial-span, so on a tall screen
     the extra height becomes breathing room rather than a giant graphic.

     .hero uses this as min-height, so on a very short viewport the section
     grows past the fold instead of crushing the content. */
  --hero-h:        100svh;

  --ease:     cubic-bezier(.22,.61,.36,1);
  --ease-out: cubic-bezier(.16,1,.3,1);
}

/* ---------- the dark tone ----------
   Same token names, deep-navy values — and NOTHING on the page carries them
   by default. The palette hangs off one selector only:

     html.tone-page-dark  — the whole page, while the dark run crosses the
                            viewport. Added by v3.js; see navState() there.

   .tone-dark is now a MARKER, not a palette. The two sections that wear it
   (.statement, .process) are ordinary light sections until the page tone
   flips, at which point they go dark along with everything else. That is the
   point: the page is light until it is dark, rather than containing a black
   block that is always black. It is also what removes the seam at the foot of
   the run — when the tone flips back, .process lightens WITH .value, so there
   is never a dark edge meeting a light one.

   The class on <html> is NOT called .tone-dark on purpose — v3.js scans
   querySelectorAll(".tone-dark") for geometry and the nav, and would pin both
   forever. Keeping the marker also keeps `.tone-dark + .tone-dark` and
   `.section + .section:not(.tone-dark)` working unchanged.

   The band's photographic layers are opacity-gated on this same class in
   v3-sections.css, so the halftone speckle arrives with the tone instead of
   sitting there in light mode. */
html.tone-page-dark {
  --paper:       #0D1826;
  --paper-2:     #101F31;
  --paper-3:     #16283D;

  --ink:         #ECF1F8;
  --ink-2:       #A9BCD2;
  --ink-3:       #7A90A9;
  --ink-4:       #5A7089;

  --line:        rgba(236,241,248,.14);
  --line-soft:   rgba(236,241,248,.07);
  --line-strong: rgba(236,241,248,.28);

  --ink-rgb:    236,241,248;
  --shadow-rgb: 6,11,20;

  --ember:        #4FB06A;
  --ember-bright: #58D07E;
  --warn:         #D98A4E;

  /* Previously six separate `.tone-dark <descendant>` compensation rules.
     As tokens they also cover the page-wide tone, where those descendant
     selectors would never have matched. */
  --btn-bg:       #ECF1F8;
  --btn-bg-hover: #FFFFFF;
  --btn-fg:       #0D1826;
  --brand-word:   #ECF1F8;
  --brand-blue:   #7FB3E8;
  --nav-glass:    rgba(0,0,0,.28);
  --glass-edge:   rgba(221,232,248,.14);

  background: var(--paper);
  color: var(--ink);
}

/* The cross-fade itself, declared ONLY on the element whose values change.
   `tone-live` is added by v3.js two frames after the first measurement, so a
   reload part-way down the dark run — or a bfcache restore, or the browser's
   own scroll restoration — paints its final tone instead of playing an
   unwanted light-to-dark fade over a page that was already meant to be dark.

   transition-property takes no wildcard for custom properties; the list has to
   be enumerated. Nothing else in the file may declare a transition on these —
   a consumer with its own transition re-targets every frame and lags the page
   by a full duration. */
html.tone-live {
  transition:
    --paper .5s var(--ease),        --paper-2 .5s var(--ease),
    --paper-3 .5s var(--ease),      --ink .5s var(--ease),
    --ink-2 .5s var(--ease),        --ink-3 .5s var(--ease),
    --ink-4 .5s var(--ease),        --line .5s var(--ease),
    --line-soft .5s var(--ease),    --line-strong .5s var(--ease),
    --ember .5s var(--ease),        --ember-bright .5s var(--ease),
    --warn .5s var(--ease),         --btn-bg .5s var(--ease),
    --btn-bg-hover .5s var(--ease), --btn-fg .5s var(--ease),
    --brand-word .5s var(--ease),   --brand-blue .5s var(--ease),
    --nav-glass .5s var(--ease),    --glass-edge .5s var(--ease);
}
/* A colour cross-fade with no geometric movement is not what reduced-motion
   targets, and both alternatives are worse: an instant flip is a full-page
   flash mid-scroll, and no flip at all restores the hard seam this replaces.
   Shortened rather than removed. */
@media (prefers-reduced-motion: reduce) {
  html.tone-live { transition-duration: 1ms; }
}

/* ---------- Blue textured surface ----------
   v2's canvas was not one flat navy: a WebGL PaperTexture shader blended
   #1A2F4A -> #264D7A with a fine fibre grain, and the court rails lifted a
   brighter azure over it. That depth is the thing worth keeping, so it is
   rebuilt here in pure CSS — layered radial gradients for the colour drift,
   an SVG fractal-noise tile for the fibre — with no second WebGL context.

   It also opens a LOCAL DARK SCOPE: any component inside inherits v2's
   original palette roles, which is why the animation stages (authored for a
   navy canvas) drop straight in and read correctly even on a white page. */
.surface-blue {
  --paper:       #1D3556;
  --paper-2:     #24406A;
  --paper-3:     #283F5F;

  --ink:         #DDE8F8;
  --ink-2:       #B8CCEA;
  --ink-3:       #7EA4C8;
  --ink-4:       #5D84A8;
  --ink-rgb:     221,232,248;
  --shadow-rgb:  6,11,20;

  --line:        rgba(221,232,248,.16);
  --line-soft:   rgba(221,232,248,.09);
  --line-strong: rgba(221,232,248,.30);

  --ember:        #4A9E5A;
  --ember-bright: #45C66F;
  --warn:         #C8954A;

  /* Controls on a blue island. Needed now that .val-doc is one: without these
     a .val-start inside it inherits the PAGE tone's navy button and paints
     #1A2F4A on a #1e3860 card. */
  --btn-bg:       #ECF1F8;
  --btn-bg-hover: #FFFFFF;
  --btn-fg:       #1D3556;

  position: relative;
  isolation: isolate;
  color: var(--ink);
  /* v2's canvas is an EVEN mid-navy with fine grain — no vignette, no light
     source. The earlier radial-gradient pair read as a spotlight and sat far
     too dark; this is a shallow linear drift across v2's actual range
     (#1D3556 page base, #264D7A texture front) and nothing more. */
  background: linear-gradient(168deg, #274a74 0%, #22406a 52%, #1e3860 100%);
}
/* Fibre grain. v2 runs this at opacity .04 over a WebGL fibre pass; at .38
   with an overlay blend it stops being paper and becomes television static —
   which is precisely what it looked like. Finer noise, a fraction of the
   strength, and soft-light instead of overlay so it modulates the blue
   rather than punching holes through it. */
.surface-blue::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  pointer-events: none;
  opacity: .085;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.95' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  background: var(--paper);
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink-2);
  font-family: var(--sans);
  font-size: 16.5px;
  line-height: 1.62;
  font-feature-settings: "kern" 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

::selection { background: var(--btn-bg); color: var(--btn-fg); }

img, svg, video { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }

/* ---------- Layout ---------- */
.container { width: 100%; padding-inline: var(--gutter); position: relative; }
.section   { padding-block: var(--section-y); position: relative; z-index: 1; }

/* Hairline between same-tone sections only. A tone change is its own
   boundary — a rule there would read as a seam. */
.section + .section:not(.tone-dark) { border-top: 1px solid var(--line); }
.tone-dark + .tone-dark { border-top: 1px solid var(--line-soft); }

.band-warm { background: var(--paper-2); }

/* ---------- Typography ---------- */

/* LT Superior Serif is high-contrast; it wants tight tracking at display
   sizes and none at text sizes. Used at ONE weight (400) throughout —
   hierarchy comes from size and colour, never from faux weight. */
.display {
  font-family: var(--display);
  font-weight: 400;
  line-height: 1.03;
  letter-spacing: -0.017em;
  margin: 0;
  color: var(--ink);
  text-wrap: balance;
}
h1.display { font-size: clamp(43px, 5.5vw, 88px); letter-spacing: -0.025em; line-height: .99; }
h2.display { font-size: clamp(32px, 4.1vw, 60px); }
h3.display { font-size: clamp(21px, 2.1vw, 29px); letter-spacing: -0.01em; line-height: 1.16; }

/* Italic is a real cut in this family — used for the one emphatic phrase. */
.display em, .serif-em { font-style: italic; }

.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-3);
  display: inline-flex;
  align-items: center;
  gap: 11px;
}
.eyebrow::before { content: ""; width: 20px; height: 1px; background: currentColor; opacity: .55; }
.eyebrow.center::before { display: none; }

.lead {
  font-size: clamp(16.5px, 1.22vw, 19.5px);
  line-height: 1.6;
  color: var(--ink-2);
  font-weight: 400;
  text-wrap: pretty;
  margin: 0;
}

.sec-head { max-width: 62ch; }
.sec-head .eyebrow { margin-bottom: 22px; }
.sec-head .display + .lead { margin-top: 20px; }
.sec-head.center { max-width: 68ch; margin-inline: auto; text-align: center; }
.sec-head.center .lead { margin-inline: auto; }

/* Mono data callouts — § 226.7 · MEAL · 31%. The most distinctive piece of
   Mattera's voice; carried from v2 unchanged in character. */
.mono-label {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 15px 24px;
  border: 1px solid transparent;
  border-radius: 0;
  white-space: nowrap;
  transition: background .25s var(--ease), color .25s var(--ease),
              border-color .25s var(--ease), transform .4s var(--ease-out);
}
.btn:active { transform: translateY(1px); }
.btn .arr { transition: transform .4s var(--ease-out); }
.btn:hover .arr { transform: translateX(4px); }

.btn-primary {
  background: var(--btn-bg);
  color: var(--btn-fg);
  border-color: var(--btn-bg);
}
.btn-primary:hover { background: var(--btn-bg-hover); border-color: var(--btn-bg-hover); }

.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line-strong); }
.btn-ghost:hover { border-color: var(--ink); }

.btn-sm { padding: 11px 18px; font-size: 11px; }

/* ---------- Reveal system ----------
   Contract shared with v3.js (.reveal -> .in, optional [data-d] stagger).
   Default state is VISIBLE so the page is fully readable with JS off or
   before the script runs; html.js-fx (set inline in <head>) opts into the
   animated variant only when motion is allowed. */
.reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: no-preference) {
  html.js-fx .reveal {
    opacity: 0;
    transform: translate3d(0, 18px, 0);
    transition: opacity .82s var(--ease-out), transform .82s var(--ease-out);
  }
  html.js-fx .reveal.in { opacity: 1; transform: translate3d(0, 0, 0); }
  html.js-fx .reveal[data-d="1"] { transition-delay: .08s; }
  html.js-fx .reveal[data-d="2"] { transition-delay: .16s; }
  html.js-fx .reveal[data-d="3"] { transition-delay: .24s; }
  html.js-fx .reveal[data-d="4"] { transition-delay: .32s; }
  html.js-fx .reveal[data-d="5"] { transition-delay: .40s; }

  /* The hero paints immediately — no entrance fade, so the page never looks
     dim or empty on load. Below-the-fold .reveal still animates on scroll. */
  html.js-fx .hero .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ---------- Nav ----------
   Light by default. v3.js adds .over-dark while the nav sits over a
   .tone-dark section (inverting v2's unused data-navtone scanner). */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  /* Always ruled, not only once scrolled. */
  border-bottom: 1px solid var(--line);
  transition: background .45s var(--ease), border-color .45s var(--ease),
              color .45s var(--ease), backdrop-filter .45s var(--ease);
  color: var(--ink);
}
.nav-inner {
  height: 76px;
  display: flex;
  align-items: center;
  gap: 24px;
  padding-inline: var(--gutter);
}

/* The glass. Opacity is deliberately low and the blur carries the legibility
   instead — a heavy tint stops being glass and becomes a bar with a colour,
   which is what .82/.72 read as. Raising the blur as the tint drops keeps
   whatever passes underneath diffuse enough that 11px mono stays readable
   while the section beneath still clearly shows through. */
.nav.scrolled {
  background: var(--nav-glass);
  /* saturate() was the colour tint. At 180% it pushed the SATURATION of
     whatever passed beneath the bar, so a band with any blue in it came
     through as visible blue hue rather than as a neutral dimming — reading as
     though the nav itself were tinted. 105% is effectively neutral. Blur comes
     down with it, since the blur is what reads as "glassy": less of it moves
     the bar a step closer to plain transparency. */
  backdrop-filter: saturate(105%) blur(15px);
  -webkit-backdrop-filter: saturate(105%) blur(15px);
  border-bottom-color: var(--line);
}
.nav.over-dark { color: #ECF1F8; border-bottom-color: rgba(236,241,248,.16); }
.nav.over-dark.scrolled {
  /* Neutral black, not navy, and lighter than before. The band beneath is now
     a true black ground, so a navy tint was the one blue thing in the frame —
     exactly the hue that read as a colour cast on the bar. */
  background: rgba(0,0,0,.28);
  border-bottom-color: rgba(236,241,248,.14);
}

.nav .brand { display: flex; align-items: center; }
/* v2's "mattera" wordmark at v2's size. It is set in the brand navy rather
   than the body ink — the footer monogram already uses navy, and the two
   marks reading as different colours was the tell. Over a dark section the
   nav flips it to the light ink instead. */
/* Complete lockup: glyph + wordmark, in the artwork's own coordinates
   (viewBox 0 0 643.53 86.05 — the glyph occupies x 0..170.89 and the wordmark
   x 205..643.53, so the spacing between them is the designer's, not mine).
   152px keeps the glyph at 40.4px, just clearing the brand kit's 40px floor. */
/* 135px, not 152: the wordmark occupies 438.53 of the 643.53 viewBox, so this
   renders it at 92px — exactly the size it was before the glyph was added.
   At 152px the whole lockup had grown ~13%. */
.nav .brand-logo { width: 135px; height: auto; display: block; }
.bl-mark { fill: var(--brand-mark); transition: fill .45s var(--ease); }
.bl-word { fill: var(--brand-word); transition: fill .45s var(--ease); }
/* Over a dark section only the WORDMARK inverts — #82bfff already reads on
   navy, so the mark keeps its brand colour on both tones. */
.nav.over-dark .bl-word { fill: #ECF1F8; }

.nav-links { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.nav-link {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: currentColor;
  opacity: .62;
  padding: 9px 13px;
  transition: opacity .25s;
}
.nav-link:hover { opacity: 1; }
/* Over the dark run the bar is only 44% tinted, so whatever is underneath
   comes through — and the statement band puts a bright manila folder directly
   beneath these links. At .62 they went soft exactly there. Lifting the TEXT
   rather than the tint buys the contrast back without touching the glass. */
.nav.over-dark .nav-link { opacity: .82; }

.nav-right { display: flex; align-items: center; gap: 10px; margin-left: 8px; }

/* Nav CTA inherits the surrounding tone rather than hard-coding two states. */
.nav .btn-nav {
  border: 1px solid currentColor;
  color: currentColor;
  background: transparent;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .09em;
  text-transform: uppercase;
  padding: 11px 18px;
  transition: background .25s var(--ease), color .25s var(--ease);
}
.nav .btn-nav:hover { background: var(--ink); color: var(--paper); }
.nav.over-dark .btn-nav:hover { background: #ECF1F8; color: #0D1826; }

.nav-burger { display: none; background: none; border: none; padding: 8px; }
.nav-burger span {
  display: block; width: 22px; height: 1.5px;
  background: currentColor; margin: 5px 0;
  transition: .3s var(--ease);
}

/* ---------- Mobile nav ---------- */
.mnav {
  position: fixed; inset: 76px 0 auto 0; z-index: 99;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  padding: 18px var(--gutter) 28px;
  display: none;
  flex-direction: column;
  gap: 4px;
  transform: translateY(-8px);
  opacity: 0;
  pointer-events: none;
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.mnav a {
  font-family: var(--mono); font-size: 12px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-2); padding: 14px 0;
  border-bottom: 1px solid var(--line-soft);
}
.mnav .btn { margin-top: 18px; justify-content: center; }
.mnav.open { opacity: 1; transform: none; pointer-events: auto; }

@media (max-width: 900px) {
  .nav-links { display: none; }
  .nav .nav-right .btn-nav { display: none; }
  .nav-burger { display: block; margin-left: auto; }
  .mnav { display: flex; }
}

/* ---------- Rules & small parts ---------- */
.hr { border: 0; border-top: 1px solid var(--line); margin: 0; }

.chip {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
  border: 1px solid var(--line);
  padding: 7px 12px;
  white-space: nowrap;
}

/* Focus: visible on both tones, never removed. */
:focus-visible {
  outline: 2px solid var(--ember-bright);
  outline-offset: 3px;
}
