/* =====================================================================
   HEADER — fixed bar, logo lockup with the animated branch mark, nav
   Maps to a WordPress header.php / get_template_part('partials/header').
   ===================================================================== */

/* THE BAR'S BACKGROUND IS TRANSLUCENT, WHICH MAKES ITS GROUND
   INDETERMINATE. Any contrast figure for text sitting on this bar has to
   be composited against whatever is behind it AT THE POSITION MEASURED,
   and that changes with scroll. Do not quote a single ratio for nav text
   without saying what it was composited over. --header-bg follows --paper
   through color-mix rather than freezing a channel triple. */
header{
  position:fixed;top:0;left:0;right:0;z-index:60;
  background:var(--header-bg);
  backdrop-filter:blur(9px);
  border-bottom:1px solid var(--rule-hair);
}

/* ---------------------------------------------------------------------
   SKIP LINK — focus reveal ONLY. The hidden state is .vh from base.css,
   applied in the markup, so there is one definition of "visually hidden"
   on this site and this rule cannot drift from it. No other focus-reveal
   variant existed anywhere in src/css before this one.

   .vh CLIPS, IT DOES NOT display:none — which is why this works at all.
   A display:none element is not focusable and a skip link built on one is
   unreachable by keyboard, which is the failure mode this pattern exists
   to avoid. The hidden state is position:absolute at 1x1, so it occupies
   no space in flow and CANNOT SHIFT LAYOUT while unfocused.

   SPECIFICITY, NOT LOAD ORDER: .skip:focus is (0,2,0) against .vh's
   (0,1,0), so it wins wherever base.css sits in the <link> list. Every
   .vh declaration it must defeat is restated here — position, width,
   height, overflow and clip — because leaving any one of them to the
   cascade leaves the link revealed but 1px tall.

   z-index CLEARS THE BAR. <header> is position:fixed at z-index 60; a
   revealed link at a lower index would be painted behind the very
   element it sits inside. position:fixed keeps it at the viewport's top
   left rather than the document's, so it is visible at any scroll depth.

   EVERY COLOUR HERE IS AN EXISTING TOKEN REFERENCE. --ground-dark with
   --on-dark is the site's established dark-fill pair, and --focus is the
   focus indicator and nothing else. No value is invented, derived,
   tinted or interpolated. */
.skip:focus{
  position:fixed;top:8px;left:8px;z-index:70;
  width:auto;height:auto;overflow:visible;clip:auto;
  padding:10px 16px;
  font-size:14.5px;font-weight:600;
  background:var(--ground-dark);
  color:var(--on-dark);
  outline:3px solid var(--focus);
  outline-offset:2px;
}
.nav{
  display:flex;align-items:center;justify-content:space-between;
  height:80px;max-width:1360px;margin:0 auto;padding:0 34px;
}
.nav nav{display:flex;gap:28px;align-items:center}
.nav nav a{font-size:14.5px;font-weight:600}
.nav nav a:not(.btn):hover{color:var(--accent)}

/* =====================================================================
   ---- PAGE-LOCAL DEVIATION REGISTER ----------------------------------
   Prefix NAV-, opened 2026-08-15 at N2 and numbered from 1. THIS IS THE
   FIRST REGISTER ON A COMPONENT SHEET. Every other register on this
   project is page-local (ABT-, TEAM-, HOME-, WL-, OA-, OO-, UTIL-) and
   lives in a page sheet; this deviation is SITE-WIDE, because the header
   inlines into all 20 pages, so filing it in any one page sheet would put
   a site-wide rule behind a page's name. That is the same category error
   as the generic name on a page-specific partial.

   NAV-1 · THE ABOUT SUB-NAV, 2026-08-15, unit N2, director Shape D.
   About is a LINK to our-team.html at every width, with children Our Team,
   Our Approach and Our Origins. Above 1027 the submenu opens on hover AND
   focus of the existing About link. Below 1028 a real <button> with
   aria-expanded discloses the children inside the collapsed panel.

   NO ELEMENT IS ADDED TO THE DESKTOP ROW, AND THE ROW IS WHY.
   MEASURED at viewport 1028, and NAME THE BOX: the row `.nav` is
   `padding:0 34px`, and padding is not available to flex children, so the
   figure that governs is the CONTENT box, 960px. Logo 215.19 + nav 743.91
   = 959.10. FREE SPACE 0.91px. Against the BORDER box (1028) the same
   layout reads 68.91px of free space and looks roomy; that figure is the
   wrong noun and must not be quoted. Injecting a 17px inline disclosure
   button takes the nav 51.92 -> 75.84 and drives FIVE OF SIX labels to two
   line boxes — free space goes to 0 and flexbox absorbs the rest by
   shrinking the items and wrapping their labels INTERNALLY, which is
   exactly the Unit 8t failure recorded at the breakpoint note below, to
   the same 51.922/75.844 figures. A seventh element does not fit.

   THEREFORE `max-width:1027px` HERE AND `matchMedia('(min-width: 1028px)')`
   IN js/nav.js DO NOT MOVE. Shape D rests on them. See §56 hazard below.

   `#primary-nav a:last-child` WAS ALREADY WRONG AND N2 ONLY MADE IT FIRE.
   Corrected to `#primary-nav > a:last-child`. Measured: as a descendant it
   returns ["Our Origins","Join Us"] once .nav-sub exists and ["Join Us"]
   without it — so the defect was LATENT, present in the rule and invisible
   in the DOM. As a child selector it returns ["Join Us"] in BOTH shapes.
   That is what makes this a correction rather than a workaround: the rule
   always meant "the last item in the nav". `#primary-nav a.btn` carries
   the SAME SHAPE with NO symptom — both forms return ["Join Us"] before
   and after, because no submenu link has .btn — and is corrected in the
   same edit rather than left as the next instance. Same class as §59: a
   selector that is wrong and renders plausibly.

   THE PANEL OVERFLOW IS THIS UNIT'S OWN REGRESSION, NOT AN INHERITED ONE,
   AND THE DISPATCH SAID OTHERWISE. The Half B dispatch carried Half A's
   "pre-existing; this unit makes it worse and also fixes it". THAT IS
   FALSE ON THE MEASUREMENT and is corrected here. At 390 wide the panel is
   402.16px today with Join Us ending at 455.16 — REACHABLE at 568, 667,
   844 and 1024. Half A reported "632, unreachable today"; 632 is the
   AFTER-adding figure, filed as the current state. Three submenu rows take
   the panel to 579.30 and Join Us to 632.30: unreachable at 568, and 34.7px
   of clearance at 667 rather than the 8px Half A predicted. N2 introduces
   it and N2 mitigates it, with max-height + overflow-y:auto on the panel.

   ACTIVE STATE IS STAMPED AT BUILD TIME, NOT READ AT RUNTIME. build.mjs
   writes one `aria-current="page"` into the `#primary-nav` substring only,
   on the FIRST anchor whose href equals the output filename. Bounded to
   that substring because a bare href replace would also stamp the footer's
   anchors and, on index.html, the logo link. First-match is what keeps it
   to exactly one on our-team.html, where About and Our Team share an href
   — About wins by document order, as ruled. THE SITE DOES NOT READ ITS OWN
   URL: no location.pathname anywhere, so the state cannot disagree with
   the document it is in, and it survives with JS off. Pages absent from
   the nav carry ZERO aria-current, which is correct — a page that is not
   in the nav has no item to mark. Visual parent-highlighting, if it is
   ever wanted, is a CLASS from the same mechanism. NEVER a second
   aria-current: two of them announce identically and leave a screen-reader
   user no way to tell which page they are on.

   NO NEW COLOUR AND tokens.css WAS NOT OPENED. The group uses --on-page,
   --ground-page, --rule-hair and --focus, all already consumed by this
   file. The submenu deliberately has NO distinct ground: on desktop it
   takes --ground-page like the panel, and below 1028 it is indented
   instead. A submenu ground that is not one of those is a stop-and-report.

   NAV-2 · THE ACTIVE ITEM STOPPED BEING COLOURED, 2026-08-16, unit G2.
   A DEFECT UNIT CORRECTING NAV-1's OWN RULE, live on dev on seven pages.
   N2 drew aria-current="page" in --accent. MEASURED on the built pages:
   --accent is rgb(105,111,232) on a header ground compositing to
   rgb(251,248,242), and the nav anchor is 14.5px/600 — under 18.66px AND
   under 700, so it classifies SMALL and its threshold is 4.5. It measured
   **3.9310. FAILING by 0.5690**, on hub, member-portal, our-approach,
   our-origins, our-team, utilities and why-longitude.

   THIS WALKED INTO A FORECLOSURE THE RECORD ALREADY STATED. "--accent is
   foreclosed on light grounds: 3.9310 on paper, 3.6759 on cream, against
   4.5" has been carried since 2026-08-08. The rule was written anyway
   because nothing in N2 asked what the state PAINTED — see §62.

   THE FIX REMOVES A DECLARATION RATHER THAN ADDING ONE. The active anchor
   now inherits --on-page like every sibling: rgb(41,38,49), **13.9920
   against 4.5**, 3.1x headroom. The distinction moves to an underline.
   NO NEW TOKEN, NO NEW COLOUR, tokens.css NOT OPENED.

   WEIGHT WAS BARRED BEFORE IT WAS CONSIDERED. Free space in the row's
   CONTENT box at 1028 is 0.91px — bolding any item widens it and wraps the
   row, which is the whole reason Shape D adds no inline element. NAV-1
   carries that measurement.

   MECHANISM, MEASURED RATHER THAN ASSUMED. All three candidates leave the
   NAV at 743.906 x 51.922, so at nav level all three look metric-free.
   They are not: at the ANCHOR box, text-decoration and box-shadow hold
   23.922px while border-bottom:2px goes to 25.922px. Border is absorbed
   only because the Join Us button is the tallest flex item at 51.922px —
   **metric-free by coincidence, contingent on a sibling that has nothing
   to do with this rule.** If that button is ever restyled, a border
   underline starts moving the row and nothing would say why.

   text-decoration BEATS box-shadow ON THE MOBILE PANEL. Below 1028 the
   anchor is display:block, width:100% = 322px, while its text measures
   48.48px — a box-to-text ratio of 6.64. A shadow or border draws the full
   322px and reads as a separator; text-decoration underlines the glyphs.
   And these anchors ALREADY carry border-bottom:1px var(--rule-hair) as
   their separator, which a border underline would have replaced.

   THE UNDERLINE INHERITS currentColor DELIBERATELY, so it can never drift
   from the text it marks: one colour, one figure, 13.9920 for both.
   ===================================================================== */

/* ---- THE ABOUT GROUP, 1028 AND UP ----
   position:relative on .nav-about is a NEW DECLARATION and the dropdown
   depends on it. Measured before it existed: the ancestor chain from a
   submenu item is nav#primary-nav=static -> div.nav=static -> header=fixed,
   so an absolutely positioned panel would have anchored to the fixed
   header and spanned the viewport. z-index needs nothing: `header` is
   z-index:60 and already creates the stacking context. */
.nav-about{position:relative;display:inline-flex;align-items:center}
.nav-sub-toggle{display:none}
.nav-sub{
  display:none;position:absolute;top:100%;left:-18px;
  min-width:196px;padding:10px 0;
  background:var(--ground-page);
  border:1px solid var(--rule-hair);
}
/* HOVER AND FOCUS-WITHIN, AND THE SECOND ONE IS NOT OPTIONAL. :hover alone
   makes this pointer-only; :focus-within opens the group as soon as the
   About link takes focus, so the children enter the tab order in document
   order and Shift+Tab leaves the way it came. There is no keyboard trap:
   nothing here takes focus that a Tab cannot leave. */
.nav-about:hover .nav-sub,
.nav-about:focus-within .nav-sub{display:block}
/* ESCAPE'S FLAG, AND IT MUST STAY BELOW THE TWO RULES ABOVE. Equal
   specificity — (0,2,0) for all three — so this wins on source order
   alone. Moving it up the file silently disables Escape on the desktop
   submenu and nothing about the page would look wrong. js/nav.js sets it
   and clears it on focusout and mouseenter; it can never latch. */
.nav-about[data-dismissed="true"] .nav-sub{display:none}
.nav-sub a{
  display:block;padding:9px 20px;font-size:14px;font-weight:600;
  white-space:nowrap;
}
.nav-sub a:hover{color:var(--accent)}
.nav-sub a:focus-visible{outline:3px solid var(--focus);outline-offset:-3px}

/* CURRENT PAGE. The stamped attribute is the single source; this rule only
   draws it. It is scoped to the nav so the footer's anchors are unaffected
   even if a future edit widens the stamp.

   THERE IS NO COLOUR DECLARATION HERE AND ITS ABSENCE IS THE FIX. N2 drew
   this state in --accent, which measures 3.9310 on the header ground at
   14.5px/600 — SMALL, threshold 4.5, FAILING by 0.5690 on all seven pages
   that carry an active item. The active anchor now inherits --on-page like
   every sibling and measures 13.9920. See NAV-2.

   UNDERLINE, NOT WEIGHT, AND NOT A BORDER. Weight is barred: the row has
   0.91px of free content-box space at 1028 and any widening wraps it, which
   is the constraint Shape D exists to respect. Of the three underline
   mechanisms, text-decoration and box-shadow leave the anchor's border box
   at 23.922px; `border-bottom:2px` takes it to 25.922px and is metric-free
   at the nav level ONLY because the 51.922px Join Us button is the tallest
   flex item and absorbs it — a coincidence resting on an unrelated sibling,
   not a property of the rule. text-decoration is chosen over box-shadow
   because it follows the GLYPHS: below 1028 the anchor is width:100% at
   322px while its text is 48.48px, so a shadow or border would draw a
   322px rule that reads as a separator — and these anchors already carry
   border-bottom:1px var(--rule-hair) as their real separator, which a
   border underline would replace. */
#primary-nav a[aria-current="page"]{
  text-decoration:underline;
  text-decoration-thickness:2px;
  text-underline-offset:6px;
}

/* ---------------------------------------------------------------------
   MOBILE NAVIGATION

   THE ONLY BREAKPOINT THIS FILE HAS IS 1027px. The paragraph below
   describes a SUPERSEDED state and quotes a number that is no longer
   live anywhere in this sheet — read it as history, and take the live
   value from the media query itself or from the CSSOM, never from here.

   In the source concept, a `max-width` query at what was then the
   breakpoint hid every link (`.nav nav a{display:none}`) and nothing
   replaced it — below it the site had NO navigation at all. Survivable
   on a one-page concept; not on a multi-page site. That threshold was
   920px; it moved to 1027px in Unit 8t and the figure is written out
   here in prose rather than as a copy-pasteable query so it cannot be
   mistaken for a rule. With comments stripped this file contains zero
   occurrences of 920 — it did before 8u as well, and that is a property
   worth preserving: §25, a comment asserting a value becomes a presence
   for a source grep, so probe the CSSOM and not the source string.

   THE TOGGLE IS HIDDEN ABOVE THE BREAKPOINT AND THE PANEL IS UNCONDITIONAL
   THERE. The collapse is scoped INSIDE the media query, so aria-expanded
   has no effect on a wide viewport — a stale "false" left by a resize
   cannot hide the desktop nav. That is the failure mode of putting the
   collapsed state on the element and the reveal inside a query: a media
   query adds no specificity, and the wide layout would be fighting the
   collapsed rule rather than replacing it.

   THE BREAKPOINT IS 1027px AND IT IS A MEASURED BOUND, NOT A ROUND
   NUMBER. It was 920px until Unit 8t, 2026-08-10, which added the
   Information Hub and Member Portal links. Six items no longer fit the
   inline row: the nav needs 743.906px and at 1024 it is given 740.813px,
   so flexbox SHRINKS the items and the labels wrap INTERNALLY rather
   than overflowing. Five of six went to two lines and the tallest item
   grew 51.922px -> 75.844px inside an 80px bar, leaving 2.078px of
   clearance.

   THAT FAILURE IS INVISIBLE TO AN OVERFLOW CHECK, WHICH IS THE WHOLE
   POINT OF RECORDING IT. Document overflow and nav scrollWidth-minus-
   clientWidth both read 0 at every width, before and after, on all five
   pages — 120 rows, no exceptions. Nothing overflows because the wrap
   absorbs it. A gate built only on overflow passes this cleanly and
   ships a two-line nav.

   1028 is the lowest width that stays on one line and 1027 the highest
   that wraps, bisected. Collapsing at <=1027 hands those widths to the
   panel, which stacks and cannot wrap. IF A NAV LABEL IS EVER ADDED,
   RENAMED OR RESIZED, RE-BISECT THIS — do not assume 1027 survives, and
   do not check it with an overflow probe. Count line boxes with a Range
   over each anchor's text node: the anchors are flex items and are
   therefore BLOCKIFIED, so getClientRects() on them returns the border
   box and reports one line no matter how many there are. The first probe
   written for this unit did exactly that and reported zero wraps at
   every width.

   js/nav.js's matchMedia MUST TRACK THIS VALUE at (min-width:1028px).
   It is what clears a stale aria-expanded on the way back up to the
   desktop layout; left at 921 it would stop firing across the real
   boundary and strand the toggle announcing "expanded" while it is
   display:none.

   N2 ADDED A SECOND STATE TO THAT LISTENER AND A THIRD REASON NOT TO MOVE
   THIS NUMBER ALONE. The About submenu's own aria-expanded is cleared by
   the same matchMedia callback, so a divergence now strands TWO controls
   rather than one. And Shape D itself is chosen on a measurement taken AT
   1028 — 0.91px of free space in the row's content box — so moving the
   breakpoint without re-measuring that headroom invalidates the reason the
   desktop submenu has no inline disclosure button. Re-bisect, re-measure
   the content-box free space, and change both files in one edit. NAV-1
   above carries the figures.
   --------------------------------------------------------------------- */
.nav-toggle{display:none}

@media(max-width:1027px){
  .nav-toggle{
    display:flex;align-items:center;gap:10px;
    background:none;border:0;cursor:pointer;padding:8px 4px;
    font-family:var(--mono);font-size:10px;letter-spacing:.22em;
    text-transform:uppercase;color:var(--on-page);
  }
  .nav-toggle:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
  .nav-bars{display:block;width:22px;height:16px;position:relative}
  .nav-bars i{
    position:absolute;left:0;right:0;height:2px;background:var(--on-page);
    transition:transform .3s ease,opacity .2s ease;
  }
  .nav-bars i:nth-child(1){top:0}
  .nav-bars i:nth-child(2){top:7px}
  .nav-bars i:nth-child(3){top:14px}
  .nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(1){transform:translateY(7px) rotate(45deg)}
  .nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(2){opacity:0}
  .nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(3){transform:translateY(-7px) rotate(-45deg)}

  /* THE PANEL GROUND IS OPAQUE, DELIBERATELY. The header bar itself is
     translucent with a backdrop-filter, which is fine for an 80px strip
     over a mostly-empty page top. A full-height panel of links over
     arbitrary page content has no determinate ground, so no contrast
     figure for the links would be checkable. Opacity is what makes the
     ratio a fact rather than a function of what happens to be behind it. */
  #primary-nav{
    display:none;
    position:absolute;top:80px;left:0;right:0;
    flex-direction:column;align-items:flex-start;gap:0;
    background:var(--ground-page);
    border-bottom:1px solid var(--rule-hair);
    padding:8px 34px 26px;
  }
  .nav-toggle[aria-expanded="true"] + #primary-nav{display:flex}
  /* THIS ONE STAYS A DESCENDANT SELECTOR, DELIBERATELY. It now reaches
     NINE anchors rather than five — the six top-level items plus the three
     inside .nav-sub — and that is the point: the submenu links are panel
     rows below 1028 and need the same box, size and separator as their
     siblings. Measured: `#primary-nav a` 9, `#primary-nav > a` 5. The two
     rules below are the ones that had to become child selectors. */
  #primary-nav a{
    display:block;width:100%;padding:15px 0;font-size:17px;
    border-bottom:1px solid var(--rule-hair);
  }
  /* CHILD COMBINATOR, CORRECTED AT N2 — see NAV-1. Read as a descendant
     this matched ["Our Origins","Join Us"] the moment .nav-sub existed,
     stripping Our Origins of the separator every other panel row keeps.
     The rule always meant "the last item in the nav", never "the last
     anchor anywhere inside it". */
  #primary-nav > a:last-child{border-bottom:0}
  /* SAME CORRECTION, NO SYMPTOM — AND THAT IS WHY IT IS HERE. Measured
     before and after the group landed, `#primary-nav a.btn` and
     `#primary-nav > a.btn` BOTH return exactly ["Join Us"], because no
     submenu link carries .btn. The defect is latent, not live. It is fixed
     in the same edit because it is the same shape as the rule above, and
     that shape has now failed once on this file. */
  #primary-nav > a.btn{
    width:auto;margin-top:20px;padding:14px 30px;
    font-size:14.5px;border-bottom:0;
  }

  /* ---- THE ABOUT GROUP, BELOW 1028 ----
     The wrapper is a flex item and must fill the panel row like an anchor,
     or the group indents away from its siblings. The disclosure button sits
     on the same row as the About link, right-aligned, and is the ONLY thing
     that reveals the children at this width — the link itself navigates. */
  .nav-about{display:block;width:100%;position:relative}
  .nav-about > a{padding-right:52px}
  .nav-sub-toggle{
    position:absolute;top:0;right:0;width:48px;height:59px;
    display:flex;align-items:center;justify-content:center;
    background:none;border:0;padding:0;cursor:pointer;
  }
  .nav-sub-toggle:focus-visible{outline:3px solid var(--focus);outline-offset:-3px}
  .nav-chev{
    width:9px;height:9px;border-right:2px solid var(--on-page);
    border-bottom:2px solid var(--on-page);
    transform:translateY(-3px) rotate(45deg);transition:transform .2s ease;
  }
  .nav-sub-toggle[aria-expanded="true"] .nav-chev{transform:translateY(2px) rotate(-135deg)}
  /* EVERY DESKTOP BOX PROPERTY IS RESET HERE, AND THE POSITION IS THE ONE
     THAT MATTERS. The desktop `.nav-sub` rule lives OUTSIDE this media
     query, so `position:absolute` applies at every width unless it is
     undone. Left absolute, the submenu opens OUT OF FLOW below 1028: it
     overlays Information Hub and Member Portal, the panel does not grow,
     and the max-height clamp below never engages because there is nothing
     to clamp. Measured with the bug present — panel 402.16 and Join Us at
     455.16 with the submenu both closed AND open, identical, while
     aria-expanded read "true" and the submenu was display:block. THE STATE
     WAS CORRECT AND THE LAYOUT WAS WRONG, which is why an attribute check
     alone would have passed this. */
  .nav-sub{
    display:none;position:static;
    min-width:0;padding:0;background:none;border:0;
  }
  .nav-sub-toggle[aria-expanded="true"] + .nav-sub{display:block}
  /* Indented so the child rows read as subordinate without a second
     ground — no new token, and the separator stays the shared hairline. */
  .nav-sub a{padding-left:20px;font-size:15.5px}

  /* THE PANEL MUST SCROLL, AND THIS UNIT IS WHY. Before N2 the panel was
     402.16px with Join Us ending at 455.16, reachable at 568/667/844/1024.
     Three submenu rows take it to 579.30 and Join Us to 632.30, which is
     OFF-SCREEN at 568. `header` is position:fixed and this panel is
     absolute inside it, so the document scrolling underneath does not move
     it — without a scroller of its own the last item is simply
     unreachable. 80px is the header bar; the rest of the viewport is the
     panel's. THIS IS N2's OWN REGRESSION, MITIGATED IN THE SAME EDIT. */
  #primary-nav{max-height:calc(100vh - 80px);overflow-y:auto}
}

/* TRACKS THE BREAKPOINT ABOVE. Both halves of the pair moved 920 -> 1027
   together; a revision touching one half only is NOT applied, and the
   bars would keep their transition under reduce between 921 and 1027. */
@media(max-width:1027px) and (prefers-reduced-motion:reduce){
  .nav-bars i{transition:none}
}

/* ---- the lockup ----

   LOGO HOLD, 2026-08-09. `.lgm` below is the held wordmark. EVERYTHING
   FROM `.lgw` DOWN THROUGH THE `.bmark` BLOCK MATCHES NOTHING TODAY and
   is deliberately retained as the restore path — see the comment in
   partials/header.html. Do not delete it and do not "clean up" the dead
   selectors; a revert needs them and an unmatched rule costs nothing.

   `js/reveal.js` still queries `.bmark` and now observes ZERO elements.
   That is harmless — the observer simply never fires — and it is
   recorded so a later reader does not read it as a broken animation. */

/* THE HELD WORDMARK. Painted with --ink and MASKED by the footer's
   asset, because that file bakes fill:#FFFFFF and would be invisible on
   this ground. The mask contributes no colour; the token does.

   SIZE IS DERIVED FROM THE HEADER'S OWN RHYTHM, NOT INHERITED FROM THE
   FOOTER. History: the inline lockup rendered 141.67 x 38.16; the mask
   replaced it at 28px / 140.51px wide, and the director raised it to
   36px on 2026-08-09, which the asset's aspect (1213.4/241.8 = 5.0182)
   puts at ~180.7px.

   THAT IS A GROWING FOOTPRINT IN THE TIGHTEST ROW ON THE SITE, so unlike
   the 28px step it is NOT safe by construction — the 320 element scan is
   the evidence, not the arithmetic. Figures are in the 8m report.

   aspect-ratio DRIVES THE WIDTH so a future height change cannot silently
   distort the mark — the failure mode that squashed the utilities lockups
   when a fixed height met a clamped width. */
.lgm{
  display:block;
  height:36px;
  aspect-ratio:1213.4 / 241.8;
  background:var(--ink);
  -webkit-mask-image:url(../../assets/longitude-logo-white.svg);
          mask-image:url(../../assets/longitude-logo-white.svg);
  -webkit-mask-size:contain;          mask-size:contain;
  -webkit-mask-repeat:no-repeat;      mask-repeat:no-repeat;
  -webkit-mask-position:left center;  mask-position:left center;
}

/* NARROW-WIDTH HEIGHT STEP-DOWN FOR THE LOCKUP — MEASURED, NOT GUESSED.
   At 36px the mark is 180.6px wide. The nav row's content box is 252px at
   320 and the menu toggle takes 72.9px, so the pair sums to 253.5px and
   OVERFLOWS BY 1.5px — at 320 only; from 375 up there is 53.5px of slack.

   THAT OVERFLOW WAS INVISIBLE TO A DOCUMENT-LEVEL CHECK. scrollWidth read
   320 because body clips it, which is exactly why the element scan
   excludes body and html from the scroll-parent walk. Only the
   element-level scan saw it.

   PLACED AFTER THE .lgm RULE DELIBERATELY. Both selectors are (0,1,0)
   and a media query adds NO specificity, so this only wins by coming
   LATER in the file. Written above the base rule it silently loses and
   the mark stays 36px — which is exactly what happened on the first
   attempt, and the element scan caught it.

   THE FIX IS HEIGHT, NOT aspect-ratio. Dropping to 30px gives 150.5px and
   a 28.6px margin at 320; the ratio still drives the width, so the mark
   cannot distort. Do not "fix" a future overflow here by removing
   aspect-ratio or by setting an explicit width. */
@media(max-width:360px){
  .lgm{height:30px}
}

.logo{display:inline-flex;align-items:center;gap:0;padding-right:34.56px}
.lgw{display:flex;flex-direction:column}
.lg1{
  font-family:var(--serif);font-size:22.68px;font-weight:700;
  letter-spacing:.06em;line-height:1;position:relative;
}
.lg2{
  display:flex;justify-content:space-between;
  font-size:7.56px;font-weight:600;letter-spacing:.1em;
  color:var(--on-page-soft);margin-top:3px;padding:0 6%;
}

/* THE DEGREE MARK'S GEOMETRY IS DERIVED, NOT CHOSEN. Every number here
   is the original x 1.08, the same ratio as .lg1. The -16.31px offset is
   the blue node's own position in the viewBox "38.5 20.5 145 158":
   (100 - 20.5) x height/158, which is what lands the node centre on the
   cap line. RECOMPUTE IT FROM THE HEIGHT if the height changes — scaling
   the font alone slides the node off the cap line. */
.lg1 .deg{
  position:absolute;
  left:calc(100% + 0.73px);
  top:calc(var(--capline) - 16.31px);
  height:32.40px;width:29.73px;overflow:visible;
}

/* ---- branch-mark build-out: outward from blue, once, then settled ---- */
.bmark .nd{
  opacity:0;transform:scale(.62);
  transform-box:fill-box;transform-origin:center;
  transition:opacity .34s ease-out,transform .34s cubic-bezier(.2,.8,.3,1);
}
/* open at rest, then takes the accent as the mark completes. BOTH HALVES
   OF THIS PAIR TAKE TOKENS. In the source concept both were hard-coded
   hex, so the node kept its old colour through a palette pass while every
   token-level check reported success — measured, not supposed. */
.bmark .n-blue{opacity:1;transform:none;fill:var(--paper);transition:none}
.bmark.built .n-blue{fill:var(--accent);transition:fill .23s ease-out .55s}

.bmark .ln{stroke-dasharray:100}
.bmark .l1{stroke-dashoffset:100}      /* draws blue -> stone */
.bmark .l2,.bmark .l3{stroke-dashoffset:-100}   /* draw stone -> outward */
.bmark.built .ln{stroke-dashoffset:0}
.bmark.built .l1{transition:stroke-dashoffset .40s cubic-bezier(.32,.72,.3,1) .71s}
.bmark.built .l2{transition:stroke-dashoffset 1.06s cubic-bezier(.32,.72,.3,1) 1.11s}
.bmark.built .l3{transition:stroke-dashoffset 1.06s cubic-bezier(.32,.72,.3,1) 1.21s}
.bmark.built .nd{opacity:1;transform:none}
/* four nodes bloom together — 70ms apart, no emphasis beat on any one */
.bmark.built .n-gold {transition-delay:1.00s}
.bmark.built .n-stone{transition-delay:1.07s}
.bmark.built .n-slate{transition-delay:1.14s}
.bmark.built .n-open {transition-delay:1.21s}

/* REDUCED MOTION — the end state, fully present, no motion. Note the
   .n-blue fill has to be RESTATED here: the base rule sets it to --paper
   and only .built moves it, so suppressing the transition alone would
   leave the node at its pre-build colour. */
@media(prefers-reduced-motion:reduce){
  /* THE .built VARIANTS ARE REQUIRED, NOT DUPLICATION. `.bmark .nd` is
     (0,2,0) and loses to `.bmark.built .n-blue` (0,3,0) below, so without
     these the suppression is inert on exactly the node the build-out
     animates. Measured before this was added: transition-property read
     `fill` / 0.23s under reduce at 1280 AND 900. The added selectors are
     (0,3,0), tying the .built rules and winning on source order because
     this block sits after them. */
  .bmark .nd,.bmark .n-blue,
  .bmark.built .nd,.bmark.built .n-blue{opacity:1;transform:none;transition:none}
  .bmark .n-blue{fill:var(--accent)}
  .bmark .ln,.bmark .l1,.bmark .l2,.bmark .l3,
  .bmark.built .ln,.bmark.built .l1,.bmark.built .l2,.bmark.built .l3{stroke-dashoffset:0;transition:none}
}
