/* ===========================================================================
   SVFxTrades shell — header, nav, footer, hero, buttons, cards.
   Shared by every page outside the terminal. Load after canon.css.

   Two navs: .nav-marketing for visitors, .nav-member after sign-in.
   gate.js swaps them and enforces the gate.
   =========================================================================== */

* { box-sizing: border-box; }

.wrap {
  /* The brand's body weight. Geist at 700 is the house setting for prose at
     this size, and .card-d and .row dd below both hard-code it - but .lede,
     .note and .btn set no weight at all, so they inherited whatever the page
     gave them. Nine pages carried `style="font-weight:700"` on this very
     element and 41 did not, which is why prose and buttons rendered 400 and
     visibly thinner on most of the site. One rule owns it now. */
  font-weight: 700;
  max-width: var(--column);
  margin: 0 auto;
  padding: 0 var(--layout-margin-desktop);
}

.skip { position: absolute; left: -9999px; }
.skip:focus {
  position: static; display: inline-block;
  /* Black on accent (6.78:1), not white (3.10:1) — the skip link is an
     accessibility affordance and cannot be the one thing that fails AA. */
  padding: 8px 12px; background: var(--accent); color: var(--bg);
}

/* ─── Header ────────────────────────────────────────────────────────────── */

header.site {
  height: var(--header-height-desktop);
  border-bottom: var(--hair);
  display: flex; align-items: center;
  background: var(--bg);
}
header.site .wrap {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; gap: 24px;
}

/* The nav must be allowed to shrink: a fixed gap plus unshrinkable items
   overflowed the header below ~1100px. */
.nav-links { display: flex; align-items: center; gap: 22px; min-width: 0; flex: 0 1 auto; overflow: hidden; }
.nav-links a {
  font-family: var(--font-label); font-size: 10px; font-weight: 400;
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  text-decoration: none; color: var(--ink-2); white-space: nowrap;
}
.nav-links[data-nav="member"] a { font-size: 14px; }
.nav-links a:hover { color: var(--accent); }
.nav-links a[aria-current="page"] { color: var(--ink); }

.nav-end { display: flex; align-items: center; gap: 12px; }

/* The member nav is hidden until gate.js confirms a session, and vice versa. */
[data-nav="member"] { display: none; }
header.site[data-nav="member"] { display: none; }
body[data-session="member"] [data-nav="marketing"] { display: none; }
body[data-session="member"] [data-nav="member"] { display: flex; }
body[data-session="member"] header.site[data-nav="member"] { display: flex; }

/* The footer needs its own pair. `.foot-col nav` below sets `display: flex`
   at (0,1,1), which outranks the (0,1,0) `[data-nav="member"]` rule above, so
   without these the footer shows the marketing AND member links at once -
   which is exactly what it did between the two commits on 2026-10-21. */
.foot-col nav[data-nav="member"] { display: none; }
body[data-session="member"] .foot-col nav[data-nav="marketing"] { display: none; }
body[data-session="member"] .foot-col nav[data-nav="member"] { display: flex; }


/* ─── Hero nav — the homepage header, shared by every marketing page ─────── */

.hero-nav {
  position: sticky; top: 0; z-index: 100;
  display: flex; align-items: stretch; gap: 0;
  background: transparent;
  padding: 0;
}
.hn-logo {
  background: var(--bg); border: 1.5px solid rgba(255,255,255,.22);
  display: flex; align-items: center; padding: 0 18px;
  flex: 1; height: 60px; text-decoration: none;
}
.hn-logo img { height: 28px; width: auto; display: block; }
.hn-nav { display: flex; flex: 5; height: 60px; margin-left: 8px; }
.hn-group {
  position: relative; flex: 1; min-width: 0; height: 60px;
  background: var(--bg); border: 1.5px solid rgba(255,255,255,.22);
  display: flex; align-items: center; padding: 0 22px; cursor: default; outline: none;
}
.hn-label {
  font-family: var(--font-label); font-size: 12px; font-weight: 500;
  letter-spacing: .22em; text-transform: uppercase; color: var(--ink);
  transition: color 160ms ease;
}
.hn-group:hover .hn-label, .hn-group:focus-within .hn-label { color: var(--accent); }
.hn-menu {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0;
  background: var(--bg);
  border: 1.5px solid rgba(255,255,255,.22); border-top: 1.5px solid var(--accent);
  z-index: 200; display: none; flex-direction: column;
}
.hn-group:hover .hn-menu, .hn-group:focus-within .hn-menu { display: flex; }
.hn-menu a {
  display: flex; align-items: center; padding: 12px 16px;
  border-bottom: 1.5px solid rgba(255,255,255,.14);
  font-family: var(--font-label); font-size: 12px; font-weight: 400;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink); text-decoration: none;
  transition: background 160ms ease, color 160ms ease;
}
.hn-menu a:last-child { border-bottom: none; }
.hn-menu a[aria-current="page"] { color: var(--accent); background: rgba(253,94,15,.08); }
.hn-menu a:hover { background: var(--accent); color: var(--bg); font-weight: 600; }
.hn-cta {
  display: inline-flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--accent); color: var(--bg);
  padding: 0 18px; flex: 1; height: 60px;
  font-family: var(--font-label); font-size: 12px; font-weight: 600;
  letter-spacing: .22em; text-transform: uppercase; text-decoration: none;
  transition: background 180ms ease;
}
.hn-cta:hover { background: var(--ink); }

/* Two actions in the header, ranked. Sign up is the conversion action and
   keeps the filled accent; Log in is the retention action and steps back to
   an outline. The critique found the opposite — Log in filled and the only
   header action, with Sign up buried as item 7 of a hover dropdown, so the
   conversion action sat behind the retention one. The dropdown's Sign up is
   gone now that the header carries it outright. Colour is --ink on --bg, the
   body pair, not white on accent (3.10:1). */
.hn-cta.ghost {
  background: transparent; color: var(--ink);
  border: 1px solid rgba(255,255,255,.22);
  flex: 0 0 auto; gap: 0;
}
.hn-cta.ghost:hover { background: transparent; border-color: var(--ink); color: var(--accent); }

/* The session variants, scoped to .hn-cta. The generic rules near the top of
   this file are (0,1,0) and `.hn-cta { display: inline-flex }` above is too -
   but later, so it wins, and the member CTAs rendered for signed-out visitors
   until this was added. Any [data-nav] variant needs a rule scoped to its own
   component, because every component here sets its own display. */
.hn-cta[data-nav="member"] { display: none; }
body[data-session="member"] .hn-cta[data-nav="marketing"] { display: none; }
body[data-session="member"] .hn-cta[data-nav="member"] { display: inline-flex; }

/* The hamburger. Drawn in CSS so it inherits currentColor with the label and
   needs no asset. Desktop shows the word, mobile shows the mark. */
.hn-burger { display: none; width: 18px; height: 12px; position: relative; flex: 0 0 auto; }
.hn-burger::before, .hn-burger::after,
.hn-burger span {
  content: ""; position: absolute; left: 0; right: 0; height: 1.5px;
  background: currentColor; transition: background 160ms ease;
}
.hn-burger::before { top: 0; }
.hn-burger span    { top: 5.25px; }
.hn-burger::after  { bottom: 0; }

/* Log in lives in the header on desktop and inside the menu panel on mobile.
   Both exist in the markup; exactly one is ever shown. */
.hn-menu-login { display: none; }
/* ...including for a member. The generic `body[data-session="member"]
   [data-nav="member"]` rule is (0,2,0) and would beat the (0,1,0) line above,
   putting the panel's hub link on screen at desktop width where the panel's
   Log in is deliberately not shown. Re-shown in the mobile block below. */
body[data-session="member"] .hn-menu-login[data-nav="member"] { display: none; }

/* ─── Mobile header ──────────────────────────────────────────────────────
   Three cells, not four. Measured at 390px, the four-cell row put Sign up
   at 60px against 48px neighbours because its label wrapped, and the row
   ran 18px off-screen at 360px and 58px at 320px — a sticky header dragging
   the whole page sideways.

   The Owner's call: logo, menu mark, Sign up. Sign up keeps its accent block
   because it is the conversion action and the critique's P0 was that it had
   been buried; Log in steps into the panel, where a returning member will
   look for it. One 8px gutter between every cell, one 56px height, nothing
   wraps, and it fits 320px with room.
   ───────────────────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .hero-nav { gap: 8px; align-items: stretch; }

  .hn-logo { flex: 1 1 auto; min-width: 0; height: 56px; padding: 0 16px; }

  .hn-nav  { flex: 0 0 auto; margin-left: 0; height: 56px; }

  /* Static, so the panel below anchors to .hero-nav and spans the full
     width instead of the 56px button. */
  .hn-group {
    position: static;
    width: 56px; height: 56px; padding: 0;
    justify-content: center; border-left: 1.5px solid rgba(255,255,255,.22);
  }
  .hn-burger { display: block; }

  /* Hidden from the eye, kept in the accessibility tree — the label is this
     control's accessible name, so it must not be display:none. */
  .hn-label {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }

  .hn-menu { top: calc(100% + 8px); left: 0; right: 0; }
  .hn-menu a { padding: 16px; min-height: 56px; font-size: 13px; }

  /* The header's own Log in goes; the panel's appears. */
  .hn-cta.ghost { display: none; }
  /* The member pair collapses the same way: the hub stays in the row, the
     secondary action goes to the panel and the footer. Three cells, as the
     note above this block records. */
  body[data-session="member"] .hn-cta.hn-cta-2nd[data-nav="member"] { display: none; }
  .hn-menu-login {
    display: flex;
    border-top: 1.5px solid var(--accent);
    color: var(--accent);
  }

  /* One of the two, never both - the same marketing/member split the header
     CTAs use, restated here because the base-layer guard above hides the
     member item outright. */
  .hn-menu-login[data-nav="member"] { display: none; }
  body[data-session="member"] .hn-menu-login[data-nav="marketing"] { display: none; }
  body[data-session="member"] .hn-menu-login[data-nav="member"] { display: flex; }

  .hn-cta {
    height: 56px; flex: 0 0 auto; margin-left: 0;
    padding: 0 16px; gap: 8px; white-space: nowrap;
    font-size: 11px; letter-spacing: .14em;
  }
}

/* Below 360px the accent block gives up its tracking before it gives up the
   word — one phone size narrower than any the row now breaks at. */
@media (max-width: 359px) {
  .hn-logo { padding: 0 12px; }
  .hn-cta  { padding: 0 12px; letter-spacing: .08em; }
}

/* ─── Main and headings ─────────────────────────────────────────────────── */

main { padding: var(--spacer-md) 0 var(--spacer-lg); }
.h1 { font-size: clamp(40px, 8vw, var(--fs-h1)); }
.h2 { font-size: clamp(24px, 4vw, var(--fs-h2)); }
.h3 { font-size: var(--fs-h3); }
.eyebrow { display: block; margin-bottom: 28px; }
.lede { max-width: 74ch; margin-top: 20px; color: var(--ink-2); }
.note { margin-top: 20px; max-width: 74ch; color: var(--ink-4); }
.rule { height: 1px; background: var(--hairline); border: 0; margin: var(--spacer-sm) 0; }

/* ─── Buttons ───────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 16px 24px; background: var(--accent); color: var(--bg);
  text-decoration: none; border: 1px solid var(--accent);
  font-family: var(--font-label);
  /* 13px, raised from 10px on 2026-10-27 (Owner: button text reads small next to
     body copy). The cause was not the token - canon.css types `.btn` at
     `--fs-button-14` and this sheet, which loads after it, silently overrode that
     with a hardcoded 10px. So the design system already said 14 and the shell was
     the drift.
     Measured rather than guessed: body prose is 14px lowercase, cap height ~10px.
     Uppercase at 10px gives a cap height of ~7.2px, which is why it read as a
     footnote rather than a control. 13px uppercase lands at ~9.4px - a peer of
     body text, not louder than it.
     13 and not the token's 14 because this rule also sets `white-space: nowrap`
     and `.btn.sm` (117 of the 171 .btn elements) has only 16px of side padding;
     14px uppercase plus tracking overflows the narrowest buttons at 390px. If the
     nowrap or the padding ever changes, 14px becomes available and is the more
     honest value. */
  font-size: 13px; font-weight: 400;
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  cursor: pointer; white-space: nowrap;
}
.btn:hover { background: #E04D00; border-color: #E04D00; color: var(--bg); }
.btn.ghost { background: transparent; color: var(--fg); border-color: var(--hairline); }
.btn.ghost:hover { background: transparent; border-color: var(--fg); color: var(--fg); }
.btn.sm { padding: 10px 16px; }
.actions { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-top: 36px; }

/* A standalone row of destinations — /log-in/, /sign-up/ and 404.html close
   with one. It had no layout in the base layer of either sheet: canon.css
   types `.links a` and sets a `gap` on `.links`, but nothing ever gave it
   `display: flex`, so that gap did nothing, and shell.css's own `.links` rule
   sits inside the touch/narrow media block. Until 2026-10-21 three pages
   carried an inline copy of the design system that happened to supply it, so
   the hole only showed when those came out: 404.html's four destinations ran
   together as inline text. Same shape as .actions above; the underline is the
   affordance, since these are text links in a row rather than buttons. */
.links { display: flex; flex-wrap: wrap; gap: 12px 24px; align-items: center; margin-top: 36px; }
.links a {
  text-decoration: none;
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 3px;
}
.links a:hover { border-bottom-color: var(--fg); }

/* ─── Card grids ────────────────────────────────────────────────────────── */

.grid { display: grid; gap: 0; border-top: var(--hair); border-left: var(--hair); margin-top: var(--spacer-xs); }
.grid.c2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.c3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.c4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.card {
  background: var(--bg); padding: 28px 24px;
  display: flex; flex-direction: column; gap: 12px;
  text-decoration: none; color: inherit;
  border-right: var(--hair); border-bottom: var(--hair);
  transition: background 180ms ease;
}
a.card:hover { background: var(--paper); }
.card-num {
  font-family: var(--font-label); font-size: 10px;
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--ink-4);
}
.card-t { font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 700; line-height: 1.1; letter-spacing: -.015em; }
.card-d { margin: 0; color: var(--ink-2); font-weight: 700; flex: 1; }
.card-go {
  margin-top: auto; font-family: var(--font-label); font-size: 10px;
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--ink);
}
a.card:hover .card-go { color: var(--accent); }

/* ─── Definition rows ───────────────────────────────────────────────────── */

.rows { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border-top: var(--hair); border-left: var(--hair); }
.row { background: var(--bg); padding: 28px 24px; border-right: var(--hair); border-bottom: var(--hair); }
.row dt {
  margin: 0 0 12px; font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 700;
  line-height: 1.1; letter-spacing: -.015em; text-transform: none; color: var(--ink);
}
.row dd { margin: 0; color: var(--ink-2); font-weight: 700; }
.row dt a { color: inherit; font-size: inherit; font-weight: inherit; text-decoration: underline; text-decoration-color: rgba(255,255,255,.25); text-underline-offset: 5px; }
.row dt a:hover { color: var(--accent); text-decoration-color: var(--accent); }
.row dd a { font-weight: inherit; text-decoration: underline; text-underline-offset: 3px; }

/* A surface screenshot inside a .row cell, on the free preview page.
   One class, not a system: the caption reuses .card-num, which is already this
   file's small uppercase label, rather than introducing a second one.
   The images are captured at 1280x800 by tools/shot.html, so they carry a 1.6
   aspect ratio; aspect-ratio is declared so the cell does not reflow between
   the layout pass and the image decoding. */
.row-shot { margin: 22px 0 0; }
.row-shot img {
  width: 100%; height: auto; aspect-ratio: 1280 / 800;
  border: var(--hair); background: var(--bg);
}
.row-shot figcaption { margin-top: 10px; }

/* ─── Decorative page art ────────────────────────────────────── */

/* Added 2026-10-23 on the Owner's decision, and it is the ONLY new figure
   pattern in this file. It exists because the site had exactly one image slot -
   .row-shot above - and that slot is a PROOF surface: a bordered screenshot of
   a real product page, captioned with the route it was photographed at.

   Generated art must never be able to sit there. The standing rule is that
   generated imagery never stands in for proof, so decoration and evidence need
   to be distinguishable at a glance, by someone who is not reading carefully.
   Three differences do that, and all three are deliberate:

     1. NO BORDER. .row-shot frames its image with var(--hair); a framed image
        on this site means "this is a real screen". Art bleeds, unframed.
     2. NO CAPTION. .row-shot has a figcaption naming the route. Art has nothing
        to cite, so it is not a <figure> at all - a figure implies a caption and
        a content relationship.
     3. A BAND, NOT A SCREEN. .row-shot is 1280x800 (1.6:1), the shape of an
        application window. This is 3.56:1, which no screenshot ever is.

   Accessibility: the <img> carries alt="" and role="presentation" so assistive
   tech skips it entirely. That is correct for decoration and it is also the
   honest encoding - there is no information in the image to convey.

   aspect-ratio is declared so the cell does not reflow between the layout pass
   and the image decoding, the same reason .row-shot declares its own. The ratio
   is expressed against --column rather than as a bare number so it tracks the
   measure instead of repeating it. object-fit: cover lets the source be any
   wide ratio the generator produces without the band changing shape; cropping
   is acceptable precisely because the art is abstract and has no subject to
   lose.

   The vertical margin is var(--space-8), 36px - the top of this project's space
   scale, which stops at 36px. An earlier draft of this block referenced
   var(--r-5, 56px): no --r-* token exists in canon.css, so the fallback would
   have silently supplied a value off the scale and nobody would have seen the
   missing variable. If a band ever needs more air than 36px, add a token for it
   rather than a literal here. */
.page-art {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1496 / 420;
  object-fit: cover;
  margin: var(--space-8) 0;
  background: var(--bg);
}

/* The art is the quietest thing on the page, not the loudest. A decorative band
   that out-contrasts the prose it sits beside has inverted the hierarchy of a
   site whose entire argument is the text. */
.page-art { opacity: .72; }

@media (prefers-reduced-motion: no-preference) {
  /* Intentionally empty: the art never animates. Recorded so that a later pass
     does not read the absence as an oversight and add a parallax or a fade. */
}

/* ─── Forms ─────────────────────────────────────────────────────────────── */

.form { max-width: 480px; margin-top: 36px; }
/* 480px suits three short fields. A form whose job is a paragraph of input -
   the Backtest Lab's rule box - reads as a slot in the corner of the page at
   that width. 760px is the measure the long-form guides use for prose. */
.form.wide { max-width: 760px; }

/* The first error surface in the shell. The house status red (#B42318) only
   reaches 3.17:1 on this black ground, so it is lightened here to clear AA at
   6.9:1 — flagged for the Owner, since it adds a value the palette does not
   yet record. Not the accent: that colour belongs to the submit button. */
.form-error {
  margin: 0 0 20px;
  padding: 12px 14px;
  border-left: 1px solid #EF6B5F;
  background: rgba(239,107,95,.08);
  font-family: var(--font-prose); font-size: var(--fs-prose);
  color: #EF6B5F;
}

.field { margin-bottom: 20px; }
.field label {
  display: block; margin-bottom: 8px;
  font-family: var(--font-label); font-size: 10px;
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--ink);
}
.field input, .field select {
  width: 100%; padding: 14px 16px;
  border: var(--hair); background: var(--paper); color: var(--ink);
  font-family: var(--font-prose); font-size: var(--fs-prose);
}
.field input:focus, .field select:focus { outline: 2px solid var(--accent); outline-offset: -2px; }
.field-help { margin: 8px 0 0; color: var(--ink-4); font-size: var(--fs-prose); }

/* ─── Touch ─────────────────────────────────────────────────────────────────
   Measured on the live build at 390px, 2026-10-21. A finger is a ~7mm contact
   patch with no hover state and no cursor, so three things a mouse never
   needed become mandatory: targets it can hit, space between them, and an
   answer within 50ms that the tap registered.

   `pointer: coarse` is the real test — it catches a touch device at any
   width, including a tablet in landscape. The width query is kept beside it
   for desktop browsers dragged narrow, which is how this gets reviewed.
   ──────────────────────────────────────────────────────────────────────── */

/* 1. Tap feedback. There was exactly one `:active` rule on the whole site, so
      a tap looked identical to no tap until the page changed. Touch has no
      hover to fall back on: the press state IS the feedback. Transform and
      opacity only — both composite on the GPU, so this stays off the main
      thread and cannot cause jank. */
.btn:active,
.hn-cta:active,
.nav-links a:active,
.hn-menu a:active,
.foot-col a:active,
.foot-legal a:active,
.foot-top-link:active,
a.card:active,
.brand-lockup:active,
.hn-logo:active {
  transform: translateY(1px);
  opacity: .78;
  transition: none;  /* the press must land instantly; easing it hides it */
}

@media (pointer: coarse), (max-width: 900px) {

  /* 2. iOS Safari zooms the viewport on focus for ANY field under 16px and
        does not zoom back out. Every input on this site was 14px — 11 of them
        across six pages, including the sign-in field — so signing in threw
        the page out of alignment mid-task. The 16px floor is the fix; field
        height was already 50px and is untouched. Declared on the elements
        rather than on `.field` so the terminal's own inputs, which inherit
        their size from canon.css, are covered too. */
  input, select, textarea,
  .field input, .field select {
    font-size: 16px;
  }

  /* 3. Footer navigation was the least tappable thing on the site: links
        rendered 15-18px tall against a 44px minimum, 13 of them per page
        across 42 pages. The type size is deliberate and stays — only the hit
        area grows, which is the whole point of the visual-size vs hit-area
        distinction. The 8px gap stays as the separation between targets. */
  /* Revised 2026-10-21 on the Owner's call: the footer's own links go to
     36px, not 44px. 44px is the WCAG 2.5.5 AAA figure and it made a column
     of eleven stacked links read as a list of gaps — the Owner reported it
     as "extra spacing between links". 2.5.8 AA asks 24px, so 36px keeps a
     comfortable margin over the floor while giving the column back. The
     same change is made to the homepage's injected copy of these rules in
     gate.js, so the bundle page and the 42 static pages stay identical. */
  .foot-col a,
  .foot-legal a,
  .foot-top-link {
    display: inline-flex;
    align-items: center;
    min-height: 36px;
  }

  /* `.links` is a standalone row of destinations on /log-in/, /sign-up/ and
     404 — a navigation row, not prose, so the same floor applies. It stays
     at 44px: it is a short horizontal row, not a stacked column, so its
     height costs nothing and the Owner's report was about the footer. */
  .links a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  .links { display: flex; flex-wrap: wrap; gap: 8px 20px; align-items: center; }

  /* Each of these is the whole content of its `<dt>` — a standalone
     destination, not a link inside a sentence, so the inline-link exemption
     does not apply. They measured 31px. */
  .row dt a { display: inline-flex; align-items: center; min-height: 44px; }
  /* The legal row wraps on a phone, so its targets need vertical separation
     too — 20px between columns, 8px between wrapped rows. */
  .foot-legal { gap: 8px 20px; }

  /* 4. `Log in` and `Sign up` sat flush against each other at a 0px gap: two
        48px targets with nothing between them, one of them the conversion
        action. A mis-tap lands on the other. 8px is the WCAG 2.5.8 floor and
        is enough here because both targets are already well over 44px. */
  .hn-cta + .hn-cta { margin-left: 8px; }
}

/* ─── Disclaimer ────────────────────────────────────────────────────────── */

.disclaimer {
  border-top: var(--hair); margin-top: var(--spacer-md); padding-top: 24px;
  color: var(--ink-4); max-width: 74ch;
}

/* ─── Footer ────────────────────────────────────────────────────────────── */

footer.site { border-top: var(--hair); padding: var(--spacer-xs) 0 28px; }

.foot-top {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr));
  gap: 48px;
  padding-bottom: var(--spacer-xs);
}
/* The image must be bounded by its track, not by its own intrinsic width: a
   fixed height with width:auto gave it 220px inside a minmax(0,…) track that
   can resolve narrower, so it escaped and painted over the next column. */
.foot-brand .brand-lockup img { width: 80%; max-width: 494px; height: auto; }
.foot-motto { margin: 20px 0 0; color: var(--ink-4); max-width: 44ch; font-weight: 700; }
.foot-col-h {
  display: block; margin: 0 0 20px;
  font-family: var(--font-label); font-size: 14px; font-weight: 700;
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--ink-4);
}
.foot-col nav { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.foot-col a {
  font-family: var(--font-label); font-size: 12px; font-weight: 400;
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  text-decoration: none; color: var(--ink);
}
.foot-col a:hover { color: var(--accent); }
.foot-col a[aria-current="page"] { color: var(--ink-4); }

.foot-base {
  border-top: var(--hair); padding-top: 24px;
  display: flex; flex-wrap: wrap; gap: 16px; justify-content: space-between;
}

.foot-base { border-top: var(--hair); padding-top: 24px;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 32px; }
.foot-legal { display: flex; flex-wrap: wrap; gap: 20px; justify-content: flex-end; }
.foot-legal a, .foot-top-link {
  font-family: var(--font-label); font-size: 10px; letter-spacing: var(--tracking-label);
  text-transform: uppercase; text-decoration: none; color: var(--ink-4);
}
.foot-legal a:hover, .foot-top-link:hover { color: var(--accent); }
.foot-top-link { background: none; border: 0; cursor: pointer; padding: 0; }

@media (max-width: 900px) {
  .foot-top { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 36px; }
  .foot-brand { grid-column: 1 / -1; }
  .foot-base { grid-template-columns: 1fr; gap: 12px; }
  .foot-legal { justify-content: flex-start; }
}

/* The nav fits from 900px up (68 + 500 + 204 + gaps = 820 at a 918px wrap).
   Below that it used to be hidden outright, with the footer named as the
   fallback. That left the 25 pages carrying only .nav-links — the whole member
   area, including all 22 library guides — with no header navigation on a
   phone: the reader had to scroll a full article to reach any other page.
   It now wraps onto its own scrollable row instead of disappearing. The
   session rules above still decide which of the two navs is shown. */
@media (max-width: 900px) {
  header.site { height: auto; }
  header.site .wrap { flex-wrap: wrap; gap: 0 16px; padding-top: 10px; }

  /* Six links need 443px and the row has 345px, so this wraps to two rows
     rather than scrolling. A scroller was tried first and measured badly:
     "Terminal" sat entirely off-screen and "On-Watch" was cut mid-word on
     first paint, so a third of the member area was unreachable unless you
     guessed the row moved. A fade affordance does not fix an item nobody can
     see. header.site is not sticky, so the extra row costs scroll depth once
     and nothing after that. */
  .nav-links {
    order: 3;
    flex: 1 0 100%;
    flex-wrap: wrap;
    gap: 0 18px;
    margin-top: 2px;
    overflow: visible;
  }

  /* 12px is the ramp's bottom step; 10px sat below the readable floor, and
     the vertical padding carries each link to a 44px touch target. */
  .nav-links a,
  .nav-links[data-nav="member"] a {
    font-size: 12px;
    padding: 13px 0;
    display: inline-flex;
    align-items: center;
  }
  .nav-links a[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--accent); }

  .grid.c2, .grid.c3, .grid.c4, .rows { grid-template-columns: 1fr; }
  main { padding: var(--spacer-xs) 0 var(--spacer-md); }
  .wrap { padding: 0 var(--layout-margin-mobile); }
}
