/* ==========================================================================
   CapyCrew - "The CapyCity Dispatch"
   The shipped editorial design. Ink on paper, print apparatus, a live city
   plate washed back to paper strength behind the type.

   Loaded on every page from base.html, AFTER site.css, so the shell it
   defines - masthead, colophon, stage, display type - wins on source order
   while site.css keeps styling the interior page bodies (.paper-* on the
   whitepaper, .store-*, .hub-*) that have not been re-set yet.

   Two things follow from that and are deliberate:
     - No bare `.btn` rule. site.css owns `.btn` for the interior pages; this
       sheet styles `.btn-ink` and `.btn-line`, which carry their own geometry.
     - Nothing here is scoped to a page, so an interior page picks up the new
       masthead, colophon and display face automatically.
   ========================================================================== */

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

:root {
  --body: "Space Grotesk", system-ui, sans-serif;
  --mono: "DM Mono", ui-monospace, monospace;
  --serif: "Fraunces", Georgia, "Times New Roman", serif;

  /* The display face. One branch of what was an A/B in the concept; the serif
     stance is the one that shipped, so its five tokens are folded in here
     rather than hanging off a data-attribute nothing sets any more. */
  --display: var(--serif);
  --display-vs: "opsz" 110, "wght" 620, "SOFT" 26, "WONK" 1;
  --display-ls: -.018em;
  --display-lh: .95;
  --em-style: italic;

  /* ---- paper ---- */
  --paper: #f4f0e8;
  --paper-2: #fffdf8;
  --paper-3: #ebe5d8;
  --ink: #101010;
  --ink-2: #4a473f;
  --ink-3: #6f6a5e;            /* 4.7:1 on paper only - see below */
  /* --ink-3 is the furniture tone, and it earns its 4.74:1 against opaque
     paper. Over the open plate it does not - 2.8:1 - so a label in --ink-3
     must have paper of its own behind it: .figures, .margin-note, .notice,
     .table-wrap, .spread, .masthead and .colophon all do, and the thinnest of
     them (.masthead, .94 of --paper) still carries it at 4.6:1 because the
     wash composites before the panel does. Every label that sits on the open
     plate - bylines, captions, hints, the folio, the route numbers and
     statuses - is set in --ink-2 instead. */
  --rule: rgba(16, 16, 16, .16);
  --rule-2: rgba(16, 16, 16, .34);
  --forest: #1c4a3b;           /* accent for text: 8.9:1 */
  --acid: #c2ee2c;             /* fill only, always with ink on top */
  --amber: #e4712f;            /* graphic only, never small text */
  --shadow: 0 18px 40px rgba(16, 16, 16, .13);
  --shadow-2: 0 30px 64px rgba(16, 16, 16, .18);

  --shell: 1300px;
  --gutter: clamp(18px, 4vw, 44px);
  --band-y: clamp(78px, 10vh, 136px);
  --ease: cubic-bezier(.2, .75, .25, 1);
  color-scheme: light;
}
/* ==================== CITY PLATE PALETTE ====================
   CapyCity is a lit, cel-shaded scene rather than a flat print of one, so the
   plate needs a whole paint palette instead of four ink tones.

   THESE PAINTS ARE AUTHORED FOR WHAT SURVIVES THE WASH, NOT FOR THE SWATCH.
   The plate sits under .city-haze, which composites it toward --paper #f4f0e8.
   Paper is near-neutral, so the wash scales every paint's colour toward grey in
   proportion to its own alpha: what reaches the eye is about 0.22 of the paint
   plus 0.78 of paper. The consequence is not obvious and it is worth stating
   plainly, because the first version of this palette got it wrong:

     what survives is the paint's CHANNEL SPREAD (max - min), scaled by 0.22.

   Not its saturation, and not its darkness. A deep forest #2a6a54 has a spread
   of 64, so 14 units of colour arrive and the wall lands on rgb(199,211,199) -
   grey. Vermilion #ff4b3e has a spread of 193, so 42 arrive and it still reads
   as red. Dark saturated paints are the trap: they look rich in the swatch and
   vanish on the plate. Every paint here that has to READ as a colour is bright
   and vivid; the dark paints are here for VALUE, which is the other half of the
   job - under a .78 wash pure black lands on rgb(190,187,181) and pure white on
   rgb(246,243,236), so there are only ~56 units of range and a scene that uses
   the middle of it has no shapes in it. Roofs, glass, tyres, grates and posts
   go near-black on purpose so the massing reads even washed out.

   So the plate is a hand-coloured print: saturated inks on cream stock. The
   Dispatch's own --acid #d6ff3f and --red #ff4b3e do the accent work, on the
   awnings, the fits and the traffic, which keeps the plate and the page the
   same publication.

   js/capycity.js reads all 63 names below off the stage's computed style by
   name, so the plate and the page can never drift apart - which also means
   these names are a contract. Do not reuse --mark, --plate, --head, --trim or
   --chrome for page chrome, however much they sound like print apparatus: they
   are the road markings, the number plates, the headlamps, the window trim and
   the bumpers. Adding a paint means adding it here AND to the NAMES list in
   capycity.js, or it silently falls back to #8b8b8b.

   The two --city-* tones are the CSS skyline's, used only when there is no
   canvas at all. */
:root {
  --city-bld: #1f5a8c;  --city-ghost: #ff4b3e;

  /* sky: real blue overhead, dissolving toward paper at the horizon. The three
     stops carry the gradient; the clouds are lit off --cloud and shaded toward
     --sky-low, so the spread between mid and cloud is what makes them visible
     at all. Do not close that gap. */
  --sky-top: #1275c0;   --sky-mid: #4fb0e0;    --sky-low: #b9e0ee;
  --sun: #ffe9a3;       --cloud: #ffffff;

  /* ground: dark asphalt against pale flags, which is the widest value step in
     the scene and the one that draws the avenue. */
  --road: #39424c;      --road-2: #454f5a;     --mark: #fff8d8;
  --kerb: #8c8676;      --kerb-top: #efe8d2;
  --walk: #f2ead6;      --walk-2: #e3d9bf;     --grate: #23282e;

  /* buildings: brick, ochre, teal, cream, indigo, saffron - six hues that are
     still six hues after the wash, which the old forest/sage/putty set was not */
  --bld-a: #d94f3d;     --bld-b: #e8933a;      --bld-c: #2f9e8f;
  --bld-d: #f0e2c0;     --bld-e: #3d5fa8;      --bld-f: #e6c548;
  --trim: #fffaea;      --roof: #2b3138;       --roof-2: #1b1f24;
  --glass: #17313d;     --glass-lit: #ffd968;
  --awning-a: #ff4b3e;  --awning-b: #1f7fbf;   --awning-c: #d6ff3f;

  /* planting */
  --trunk: #6b4a30;     --leaf-a: #35a04a;     --leaf-b: #1f7f3c;
  --leaf-c: #7cc94a;    --soil: #4a3a28;

  /* traffic: four vivid, one white, one graphite - the pale and dark bodies are
     what stop a queue reading as one long coloured smear */
  --car-1: #ff4b3e;     --car-2: #1f7fbf;      --car-3: #ffc93c;
  --car-4: #f4f1e6;     --car-5: #2fa88f;      --car-6: #2b3138;
  --taxi: #ffb01f;      --tyre: #1b1f24;       --rim: #d8d3c4;
  --chrome: #eae5d6;    --plate: #fffaea;
  --head: #fff6cf;      --tail: #ff3a2a;

  /* street furniture */
  --post: #3a4149;      --lamp-glow: #ffe9a3;
  --sig-red: #ff2f21;   --sig-amber: #ffb01f;  --sig-green: #2fd05f;
  --sig-off: #262b30;

  /* the crew: the capybaras stay believably capybara, so the colour is carried
     by the eight fits rather than by the fur */
  --capy: #b98a5e;      --capy-2: #a2744c;     --capy-dark: #6d4a2e;
  --capy-nose: #3a2a20;
  --fit-1: #ff4b3e;     --fit-2: #1f7fbf;      --fit-3: #d6ff3f;
  --fit-4: #ffc93c;     --fit-5: #2fa88f;      --fit-6: #f06ba8;
  --fit-7: #f4f1e6;     --fit-8: #7d5cc9;
}
/* ==================== BASE ==================== */
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  background: var(--paper);
  color: var(--ink);
  font: 400 16px/1.6 var(--body);
  overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }
img, video { display: block; max-width: 100%; }
:focus-visible { outline: 2px solid var(--forest); outline-offset: 3px; }

.shell { width: min(var(--shell), calc(100% - var(--gutter) * 2)); margin-inline: auto; }

h1, h2, h3, .wordmark, .ghost, blockquote {
  font-family: var(--display);
  font-variation-settings: var(--display-vs);
  letter-spacing: var(--display-ls);
  line-height: var(--display-lh);
  font-weight: 400;
  margin: 0;
  text-wrap: balance;
}
h1 { font-size: clamp(50px, 7vw, 116px); }
h2 { font-size: clamp(34px, 4.4vw, 68px); }
h3 { font-size: 15px; letter-spacing: .02em; line-height: 1.3; }
h1 em, h2 em, blockquote em { font-style: var(--em-style); color: var(--forest); }

/* All furniture - kickers, folios, captions, labels - is mono.

   margin-block, not margin: two of these selectors are also written onto .shell
   elements (`shell strip-inner` in the masthead ticker, `sheet-head shell` on
   every band head), and this block is later in the file than .shell's
   `margin-inline: auto` at :167, so a shorthand `margin: 0` won the cascade and
   left both flush at x 0 while the column beside them started at the gutter -
   the ticker on every page, and `SUPPLY MAP / GENESIS` and its siblings on the
   whitepaper. Only the block-axis default margin is unwanted here; every element
   in this list is a p/h*/div whose inline UA margin is already 0. Same trap and
   same fix as .figures-inner below - see the note there. */
.kicker, .contents-head, .notes-head, .colophon-label, .hint,
.strip-inner, .note-head, .sheet-head, .spread-meta, .route-no, .stamp {
  font: 500 10.5px/1.5 var(--mono);
  letter-spacing: .19em;
  text-transform: uppercase;
  margin-block: 0;
}
.kicker { color: var(--forest); }
.kicker i, .byline i, .frame figcaption i { font-style: normal; color: var(--ink-2); padding: 0 5px; }
.imprint i { font-style: normal; color: var(--ink-3); padding: 0 5px; }

.standfirst {
  max-width: 34ch; margin: 26px 0 0;
  font-family: var(--serif); font-variation-settings: "opsz" 28, "wght" 400, "SOFT" 40, "WONK" 0;
  font-size: clamp(19px, 1.75vw, 25px); line-height: 1.34; color: var(--ink-2);
}
.byline { margin: 22px 0 0; font: 500 10.5px var(--mono); letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-2); }
.band-note { max-width: 46ch; margin: 22px 0 0; color: var(--ink-2); font-size: 15px; }
.figure-note { max-width: 62ch; margin: 26px 0 0; color: var(--ink-2); font-size: 13.5px;
  font-style: italic; }
/* ==================== PRINT APPARATUS ====================
   Hairline rules that draw themselves in, footnote markers, and the plate
   (a framed image with registration crosses) used everywhere on the page. */
.rule { display: block; height: 1px; margin: 30px 0 0; background: var(--ink);
  opacity: .8; transform: scaleX(0); transform-origin: left center;
  transition: transform .8s var(--ease); }
.rule.is-in { transform: scaleX(1); }

.fn { color: var(--forest); }
.fn sup { font: 500 9px var(--mono); padding-left: 2px; vertical-align: super; }
.fn:hover sup { text-decoration: underline; }

/* Inline links in running copy. The reset at the top of this sheet takes every
   link down to `color: inherit; text-decoration: none`, which is right for nav
   and cards but leaves a link inside a paragraph completely unmarked. .fn is
   excluded: a footnote marker is already forest and carries its own hover. */
.standfirst a:not(.fn), .band-note a:not(.fn), .figure-note a:not(.fn),
.columns a:not(.fn), .margin-note a:not(.fn), .notice a:not(.fn),
.pull-attr a:not(.fn), .imprint a:not(.fn) {
  color: var(--forest); text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.standfirst a:not(.fn):hover, .band-note a:not(.fn):hover, .figure-note a:not(.fn):hover,
.columns a:not(.fn):hover, .margin-note a:not(.fn):hover, .notice a:not(.fn):hover,
.pull-attr a:not(.fn):hover, .imprint a:not(.fn):hover {
  color: var(--ink); text-decoration-color: transparent;
  box-shadow: inset 0 -6px 0 var(--acid);
}

.plate { margin: 0; }
.plate-frame { position: relative; overflow: hidden; background: var(--paper-2);
  border: 1px solid var(--rule-2); box-shadow: var(--shadow); }
.plate-frame video, .plate-frame img { width: 100%; height: 100%; object-fit: cover; }

/* Registration crosses sit in the corners, just inside the trim. */
.reg { position: absolute; width: 13px; height: 13px; pointer-events: none; z-index: 2;
  mix-blend-mode: multiply; opacity: .85; }
.reg::before, .reg::after { content: ""; position: absolute; background: var(--paper-2); }
.reg::before { left: 50%; top: 0; bottom: 0; width: 1px; transform: translateX(-.5px); }
.reg::after { top: 50%; left: 0; right: 0; height: 1px; transform: translateY(-.5px); }
.reg-tl { left: 9px; top: 9px; } .reg-tr { right: 9px; top: 9px; }
.reg-bl { left: 9px; bottom: 9px; } .reg-br { right: 9px; bottom: 9px; }

.plate figcaption, .frame figcaption, .good figcaption, .spread figcaption {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 9px; border-top: 1px solid var(--rule); }
.plate figcaption b, .good figcaption b { font: 500 10.5px var(--mono); letter-spacing: .16em;
  text-transform: uppercase; color: var(--forest); }
.plate figcaption span, .good figcaption span { font-size: 13px; color: var(--ink-2); font-style: italic; }

/* ==================== BUTTONS ====================
   Geometry is repeated into both variants rather than shared by a bare `.btn`,
   because site.css still owns `.btn` for the interior pages this sheet has not
   re-set. A bare rule here would restyle every store and hub button too. */
/* A button row. site.css also defines .cta-row, with the same shape and a 30px
   top margin; this copy is here so a page that stops loading the old sheet keeps
   its rows. .front-lead .cta-row below is the front-page variant. */
.cta-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }

.btn-ink, .btn-line {
  display: inline-flex; align-items: center; gap: 8px; min-height: 46px; padding: 0 22px;
  border: 1px solid transparent; font: 500 11px var(--mono); letter-spacing: .15em;
  text-transform: uppercase; text-align: center;
  transition: background .25s, color .25s, border-color .25s,
    transform .25s var(--ease), box-shadow .25s;
}
.btn-ink em, .btn-line em { font-style: normal; opacity: .6; }
.btn-ink { background: var(--ink); color: var(--paper); }
.btn-ink:hover { background: var(--forest); transform: translateY(-2px); box-shadow: var(--shadow); }
.btn-line { border-color: var(--ink); color: var(--ink); }
.btn-line:hover { background: var(--acid); border-color: var(--acid); transform: translateY(-2px); }
/* ==================== ENVIRONMENT: the city as a press plate ====================
   CapyCity runs live behind the type. js/capycity.js mounts its canvas into
   #scene-stage, reads the palette above off it, and flies the camera down the
   avenue on page scroll. Here the city is printed rather than displayed: washed
   back to paper strength and screened through grain, because on this direction
   type always leads.

   Full-bleed and on every page. The stage element itself is rendered by
   base.html; it is aria-hidden and pointer-events: none, so it is scenery in
   both the accessibility tree and the hit test. */
#scene-stage { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
  /* The scene's own sky ramp, so the first paint and the WebGL frame that
     replaces it are the same sky instead of two different creams. */
  background: linear-gradient(180deg, var(--sky-top) 0%, var(--sky-mid) 44%, var(--sky-low) 100%); }
#scene-stage canvas { position: absolute; inset: 0; width: 100%; height: 100%; }

/* The wash, and the reason the page is readable. Solid paper at the head and
   foot of every screen, thinning to a window through the middle band - but
   never past .78. That floor is measured against black rather than against the
   palette, because the toon ramp multiplies every paint down by its darkest
   step: .78 paper over pure black is rgb(190,187,181), which carries 16.5px
   --ink-2 body copy at 4.85:1, --forest kickers at 5.25:1 and --ink headlines
   at 9.96:1.

   Then .city-grain multiplies over the wash - z-index 3 against the wash's 2 -
   and takes about 2.9% off the backdrop where both line sets cross, so what a
   line of type actually sits on is rgb(185,182,176): --ink-2 4.57:1, --forest
   4.95:1, --ink 9.38:1. Still over 4.5, but by 0.07, not by 0.35. So .78 is a
   floor with almost nothing under it, and the two numbers that can eat the rest
   are in this block and the next: thin the wash or thicken the grain and the
   body copy fails. Both figures are kept here because the wash-only one is what
   you get if you measure the gradient on its own and wonder why it disagrees.

   Small mono furniture in --ink-3 does not clear that - 2.66:1 - so it either
   sits on a panel of its own or moves to --ink-2; see the note on --ink-3 at the
   top of this file.

   THE VERTICAL PROFILE BELOW IS NOT A TUNING KNOB. The stage is position:fixed
   inside a document that scrolls, so a line of body copy passes through every
   vertical position in this gradient on its way up the screen. Every stop is
   therefore load-bearing, including the solid ones at the head and foot - which
   look redundant behind the .94 masthead and the opaque colophon and are not,
   because the text that scrolls under them is not the masthead's.

   The HORIZONTAL axis is the one place there is slack, and .city-haze takes it
   as a mask. Type lives inside .shell, which is centred and never wider than
   --shell, so beyond that column plus 40px of safety there is no body copy at
   any scroll position and nothing to protect. The mask multiplies the wash's
   alpha, so the margins land at about .84 x .62 = .52 and the city reads at
   roughly twice its strength out there - the sky, the skyline and the cloud bank
   all sit in that band. Both stops collapse to zero width once the viewport is
   narrower than --shell + 80px, which is where the margins stop existing, so
   narrow screens keep the full wash without a media query. */
.city-haze { position: absolute; inset: 0; z-index: 2; background:
  linear-gradient(180deg, var(--paper) 0%, rgba(244, 240, 232, .84) 16%,
    rgba(244, 240, 232, .78) 46%, rgba(244, 240, 232, .85) 76%, var(--paper) 100%);
  --haze-hold: max(0px, calc((100% - var(--shell)) / 2 - 40px));
  -webkit-mask-image: linear-gradient(90deg, rgba(0, 0, 0, .62) 0,
    #000 var(--haze-hold), #000 calc(100% - var(--haze-hold)), rgba(0, 0, 0, .62) 100%);
  mask-image: linear-gradient(90deg, rgba(0, 0, 0, .62) 0,
    #000 var(--haze-hold), #000 calc(100% - var(--haze-hold)), rgba(0, 0, 0, .62) 100%); }

/* Fine laid-paper tooth, multiplied over everything. */
.city-grain { position: absolute; inset: 0; z-index: 3; mix-blend-mode: multiply; opacity: .55;
  background-image: repeating-linear-gradient(0deg, transparent 0 2px, rgba(16, 16, 16, .035) 2px 3px),
    repeating-linear-gradient(90deg, transparent 0 3px, rgba(16, 16, 16, .022) 3px 4px); }

/* CSS-only skyline for anyone who never gets a canvas, with the amber
   misregistration ghost this direction is built around. capycity.js raises
   data-renderer="webgl" the moment its canvas is in - including under
   prefers-reduced-motion, where it renders one still frame and stops - so the
   print only ever shows when there is genuinely no city to show. */
.city-fallback { position: absolute; inset: auto 0 6%; z-index: 1; height: 46%; opacity: .34;
  background: var(--city-bld);
  clip-path: polygon(0 100%, 0 54%, 7% 54%, 7% 30%, 19% 30%, 19% 66%, 33% 66%, 33% 17%,
    48% 17%, 48% 60%, 63% 60%, 63% 34%, 79% 34%, 79% 8%, 90% 8%, 90% 44%, 100% 44%, 100% 100%); }
.city-fallback::after { content: ""; position: absolute; inset: 0; transform: translate(7px, -5px);
  background: var(--city-ghost); opacity: .5; clip-path: inherit; }
#scene-stage[data-renderer="webgl"] .city-fallback { display: none; }

/* is-dead is the hard failure: no THREE, or the context refused. The skyline
   is then the only city the issue has, so it is printed at full strength and
   the wash thins to let it read. .74 is safe here for the reason .78 is the
   floor everywhere else: with no canvas the backdrop is the sky ramp with a
   .34 skyline over it, never black, so body copy lands at 6.6:1 rather than the
   4.1:1 that .74 over black would give. The plate stays decorative either way -
   it is aria-hidden, and no reader is told what they are missing. */
#scene-stage.is-dead .city-fallback { opacity: .58; }
#scene-stage.is-dead .city-haze { background:
  linear-gradient(180deg, var(--paper) 0%, rgba(244, 240, 232, .8) 20%,
    rgba(244, 240, 232, .74) 62%, var(--paper) 100%); }

/* Everything that is not the plate rides above it. .site-content is the shipped
   shell's wrapper; .issue is the front page's own main element. */
.site-content, .issue, .masthead, .colophon { position: relative; z-index: 1; }
/* ==================== FOLIO RAIL ====================
   Front page only - its anchors are the front page's sections. */
.folio { position: fixed; z-index: 25; left: 20px; top: 50%; transform: translateY(-50%);
  display: grid; gap: 1px;
  /* The rail is the one piece of type that lives in the margin, and the margin
     is exactly where .city-haze thins its mask - so the folio cannot borrow the
     plate's wash the way the rest of the page does. It carries its own, by the
     same rule the top of this file sets for small mono furniture: put it on a
     panel. Worst case is the thinned wash over a black plate, rgb(127,125,121);
     .9 paper over that is rgb(232,229,221), which holds --ink-2 at 7.4:1. The
     grain never reaches it either - that sits inside #scene-stage at z-index 3,
     and this is at 25. Against the full-strength wash the panel is invisible.
     Padding only, no negative margin: .folio-rule is absolute at left: 0, so
     moving this box moves the progress rule with it. */
  padding: 10px 12px 10px 15px;
  background: rgba(244, 240, 232, .9); }
.folio-rule { position: absolute; left: 0; top: 3px; bottom: 3px; width: 1px; background: var(--rule); }
.folio-rule i { position: absolute; left: -1px; top: 0; width: 3px; background: var(--ink);
  height: calc(100% * var(--page-progress, 0)); transition: height .18s linear; }
.folio a { display: flex; align-items: baseline; gap: 8px; padding: 5px 0;
  font: 500 9.5px var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-2);
  transition: color .25s, transform .25s var(--ease); }
/* The section name stays folded away until the margin can actually hold it. The
   rail sits at left: 20px and a name starts 37px further in, so it needs about
   125px of clear paper; the shell only leaves that once the viewport passes
   1560px - below 1388px the gutter is what sets the margin, and at 1440px it is
   70px, which puts the name straight under the headline. So below 1560px the
   folio is what a printed one is: numbers in the margin. The name is kept for
   screen readers but taken out of layout, because an invisible link box is
   still a link box, and at 1440px it was covering the first 55px of the lede. */
.folio a span { position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
@media (min-width: 1560px) {
  .folio a span { position: static; width: auto; height: auto; overflow: visible;
    clip-path: none; opacity: 0; transform: translateX(-5px);
    transition: opacity .3s var(--ease), transform .3s var(--ease); }
  .folio:hover a span, .folio a.is-here span { opacity: 1; transform: none; }
}
.folio a:hover, .folio a.is-here { color: var(--forest); transform: translateX(3px); }
.folio a.is-here b { box-shadow: inset 0 -6px 0 var(--acid); }

/* ==================== MASTHEAD ====================
   The masthead is sticky, so anchor targets keep clear of it. */
[id] { scroll-margin-top: 96px; }

.masthead { position: sticky; top: 0; z-index: 30; background: rgba(244, 240, 232, .94);
  backdrop-filter: blur(12px); border-bottom: 2px solid var(--ink); }

.mast-strip { overflow: hidden; max-height: 40px; border-bottom: 1px solid var(--rule);
  transition: max-height .4s var(--ease), opacity .3s var(--ease); }
.strip-inner { display: flex; align-items: center; gap: 22px; height: 32px; color: var(--ink-3);
  white-space: nowrap; }
.strip-inner span { font-size: 9.5px; }
.strip-end { margin-left: auto; font-style: italic; text-transform: none; letter-spacing: .06em; }

.mast-inner { display: flex; align-items: center; gap: 30px; height: 68px;
  transition: height .4s var(--ease); }
.wordmark { font-size: 30px; letter-spacing: -.01em; transition: font-size .4s var(--ease); }

.mast-nav { display: flex; gap: 24px; margin-left: auto; }
.mast-nav a { position: relative; padding: 3px 1px; font: 500 10.5px var(--mono); letter-spacing: .15em;
  text-transform: uppercase; color: var(--ink-2); transition: color .2s, box-shadow .25s var(--ease); }
.mast-nav a:hover { color: var(--ink); box-shadow: inset 0 -8px 0 var(--acid); }
.mast-nav a.is-here { color: var(--ink); box-shadow: inset 0 -8px 0 var(--acid); }

.mast-cta { padding: 10px 15px; background: var(--ink); color: var(--paper);
  font: 500 10px var(--mono); letter-spacing: .16em; text-transform: uppercase;
  transition: background .25s; }
.mast-cta:hover { background: var(--forest); }
.mast-menu { display: none; }

/* Condensed after the first scroll - the folio strip retires, the mark shrinks. */
.masthead.is-stuck .mast-strip { max-height: 0; opacity: 0; }
.masthead.is-stuck .mast-inner { height: 56px; }
.masthead.is-stuck .wordmark { font-size: 21px; }
/* ==================== 01 / FRONT PAGE ==================== */
.front { padding: clamp(46px, 7vh, 88px) 0 clamp(44px, 6vh, 76px); }
.front-grid { display: grid; grid-template-columns: minmax(0, 1.42fr) minmax(268px, .92fr);
  grid-template-areas: "lead plate" "contents plate";
  align-items: start; gap: clamp(30px, 4vw, 64px) clamp(30px, 4.5vw, 68px); }
.front-lead { grid-area: lead; }
.front-plate { grid-area: plate; }
.contents { grid-area: contents; }

.front-lead h1 { margin-top: 16px; }
/* Scoped, because site.css owns .cta-row for the interior pages. */
.front-lead .cta-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 32px; }

.front-plate .plate-frame { aspect-ratio: 4 / 5; }

/* ---- contents list, with dotted leaders ---- */
.contents { border-top: 1px solid var(--ink); padding-top: 14px; max-width: 560px; }
.contents-head { color: var(--forest); }
.contents ol { list-style: none; margin: 12px 0 0; padding: 0; }
.contents li + li { border-top: 1px solid var(--rule); }
.contents a { display: grid; grid-template-columns: 26px auto 1fr; align-items: baseline; gap: 11px;
  padding: 9px 0; transition: color .2s; }
.contents a::after { content: ""; border-bottom: 1px dotted var(--rule-2); transform: translateY(-4px); }
.contents b { font: 500 10.5px var(--mono); letter-spacing: .1em; color: var(--ink-2); }
.contents span { font-size: 14.5px; color: var(--ink-2); }
.contents a:hover span { color: var(--ink); box-shadow: inset 0 -8px 0 var(--acid); }

/* ==================== STANDING FIGURES ====================
   Nearly opaque, because the standing figures are labelled in --ink-3 and the
   plate runs live behind them. */
.figures { border-top: 1px solid var(--ink); border-bottom: 1px solid var(--ink);
  background: rgba(255, 253, 248, .92); }
/* margin-block, not margin: this dl also carries .shell, and a shorthand `margin:
   0` here is later in the file than .shell's `margin-inline: auto`, so it won the
   cascade and left the whole row of figures flush against the frame edge instead
   of centred on the measure. Only the dl's default vertical margin is unwanted. */
.figures-inner { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); margin-block: 0; }
.figures-inner > div { padding: 15px 18px 16px 0; border-right: 1px solid var(--rule); }
.figures-inner > div + div { padding-left: 18px; }
.figures-inner > div:last-child { border-right: 0; }
.figures dt { font: 500 9.5px var(--mono); letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink-3); }
.figures dd { margin: 7px 0 0; font-family: var(--display); font-variation-settings: var(--display-vs);
  font-size: clamp(17px, 1.6vw, 23px); letter-spacing: -.01em; line-height: 1.05;
  font-variant-numeric: tabular-nums; }
.figures dd span { font: 500 11px var(--mono); letter-spacing: .04em; color: var(--forest); }
/* A ticker set inside the label instead of the figure. The envelope figure is
   the widest in the row, and a dd that outgrows its minmax(0, 1fr) track spills
   over the next cell's rule, so the unit moves up into the dt. */
.figures dt span { color: var(--forest); }
.figures dd.is-soon { color: var(--ink-2); font-style: var(--em-style); }

/* ==================== BANDS ==================== */
.band { position: relative; padding: var(--band-y) 0; border-top: 1px solid var(--rule); }
.band-head { max-width: 780px; }
.band-head .kicker { margin-bottom: 15px; }
.band-head .rule { margin-top: 26px; }
.band-head-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 44px;
  max-width: none; }
.band-head-row .band-note { margin: 0 0 5px; }

/* ==================== 02 / DISPATCHES ==================== */
.deck { display: grid; grid-template-columns: minmax(0, 1fr) minmax(250px, 340px);
  gap: clamp(22px, 3vw, 42px); margin-top: 46px; align-items: start; }
.deck-stage .plate-frame { aspect-ratio: 16 / 9; }
.deck-stage video { transition: opacity .3s var(--ease); }
.deck-stage.is-swapping video { opacity: 0; }

/* The channel list is set as a running order: numbered, ruled, right-aligned label. */
.running-order { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--ink); }
.running-order li + li { border-top: 1px solid var(--rule); }
.running-order button { display: grid; grid-template-columns: 26px auto 1fr; align-items: baseline;
  gap: 12px; width: 100%; padding: 15px 4px; cursor: pointer; border: 0; background: transparent;
  text-align: left; color: inherit; transition: background .22s, padding-left .25s var(--ease); }
.running-order b { font: 500 10.5px var(--mono); letter-spacing: .1em; color: var(--ink-2); }
.running-order span { font-family: var(--display); font-variation-settings: var(--display-vs);
  font-size: 21px; letter-spacing: -.01em; }
.running-order em { justify-self: end; font: 500 9.5px var(--mono); letter-spacing: .15em;
  text-transform: uppercase; font-style: normal; color: var(--ink-2); }
.running-order button:hover { background: rgba(255, 253, 248, .8); padding-left: 10px; }
.running-order button.is-active { background: var(--acid); }
.running-order button.is-active b, .running-order button.is-active em { color: var(--ink); }
/* ==================== 03 / CONTACT SHEET ==================== */
.sheet-head { display: flex; justify-content: space-between; gap: 20px; margin-top: 44px;
  padding-top: 10px; border-top: 1px solid var(--ink); color: var(--ink-2); }

.sheet { margin-top: 18px; padding-bottom: 22px; overflow-x: auto; overscroll-behavior-inline: contain;
  scroll-snap-type: x proximity; scrollbar-width: none; cursor: grab; }
.sheet::-webkit-scrollbar { display: none; }
.sheet.is-dragging { cursor: grabbing; scroll-snap-type: none; }
.sheet-track { display: flex; gap: 20px; width: max-content;
  padding-inline: max(var(--gutter), calc((100vw - var(--shell)) / 2)); }

.frame { position: relative; flex: none; width: min(310px, 72vw); margin: 0; scroll-snap-align: center;
  opacity: .74; filter: saturate(.5) contrast(.96);
  transition: opacity .5s var(--ease), filter .5s var(--ease), transform .5s var(--ease); }
.frame .plate-frame { aspect-ratio: 4 / 5; border-color: var(--rule); box-shadow: none;
  transition: border-color .5s, box-shadow .5s; }
.frame figcaption b { font-family: var(--display); font-variation-settings: var(--display-vs);
  font-size: 20px; letter-spacing: -.01em; text-transform: none; color: var(--ink); }
.frame figcaption span { font: 500 9.5px var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-2); font-style: normal; margin-left: auto; }

/* The plate nearest the centre of the viewport is the one being read. */
.frame.is-focus { opacity: 1; filter: none; }
.frame.is-focus .plate-frame { border-color: var(--ink); box-shadow: var(--shadow); }
.frame.is-focus::before { content: ""; position: absolute; left: -7px; top: -7px; width: 18px; height: 18px;
  border-left: 1px solid var(--amber); border-top: 1px solid var(--amber); }

.sheet-foot { display: flex; align-items: center; justify-content: space-between; gap: 24px;
  flex-wrap: wrap; }
.hint { color: var(--ink-2); }

/* ==================== 04 / NOTES ==================== */
.notes-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(210px, 268px);
  gap: clamp(28px, 4vw, 60px); margin-top: 48px; align-items: start; }

/* Body copy in this band is set in the serif, in real columns, with rules. */
.columns { columns: 2; column-gap: 38px; column-rule: 1px solid var(--rule);
  font-family: var(--serif); font-variation-settings: "opsz" 14, "wght" 400, "SOFT" 30, "WONK" 0;
  font-size: 16.5px; line-height: 1.62; color: var(--ink-2); hyphens: auto; }
.columns p { margin: 0 0 1.1em; }
.columns h3 { break-after: avoid; margin: 1.4em 0 .5em; color: var(--forest);
  font-family: var(--mono); font-variation-settings: normal; font-weight: 500; font-size: 10.5px;
  letter-spacing: .19em; text-transform: uppercase; }
.notes-list { break-inside: avoid; margin: 0 0 1.2em; padding-left: 1.1em; }
.notes-list li { margin-bottom: .5em; }
.notes-list b { color: var(--ink); font-weight: 600; }

.lead-para::first-letter { float: left; font-family: var(--serif);
  font-variation-settings: "opsz" 144, "wght" 700, "SOFT" 0, "WONK" 1;
  font-size: 4.2em; line-height: .78; padding: .06em .1em 0 0; color: var(--forest); }

.margin-note { position: sticky; top: 120px; padding: 20px; border: 1px solid var(--rule-2);
  background: rgba(255, 253, 248, .86); }
.note-head { color: var(--forest); margin-bottom: 12px; }
.margin-note p { margin: 0 0 12px; font-size: 13.5px; line-height: 1.55; color: var(--ink-2); }
.margin-note p:last-child { margin-bottom: 0; }
.note-meta { padding-top: 12px; border-top: 1px solid var(--rule); color: var(--ink-3) !important;
  font-size: 12.5px !important; font-style: italic; }

/* ==================== PULL QUOTE ==================== */
.pull { padding: clamp(54px, 7vw, 96px) 0; background: var(--paper-3);
  border-top: 2px solid var(--ink); border-bottom: 2px solid var(--ink); }
.pull blockquote { position: relative; margin: 0; max-width: 22ch;
  font-size: clamp(38px, 5.4vw, 84px); }
.pull blockquote::before { content: "\201C"; position: absolute; left: -.62em; top: -.08em;
  color: var(--amber); opacity: .5; }
.pull-attr { margin: 26px 0 0; padding-top: 14px; border-top: 1px solid var(--rule-2);
  max-width: 44ch; font: 500 10.5px var(--mono); letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-3); }
/* ==================== 05 / PRODUCT STUDY (two-page spread) ==================== */
.spread { position: relative; margin-top: 46px; padding: clamp(30px, 4vw, 58px) clamp(24px, 3.4vw, 52px);
  background: var(--paper-2); border: 1px solid var(--rule-2); box-shadow: var(--shadow-2);
  display: grid; grid-template-columns: minmax(0, 1.62fr) minmax(0, 1fr);
  gap: clamp(28px, 4vw, 62px); align-items: end;
  transform: perspective(1500px) rotateY(var(--tx, 0deg)) rotateX(var(--ty, 0deg));
  transition: transform .55s var(--ease); }

.spread-meta { position: absolute; inset: 14px 18px auto; display: flex; justify-content: space-between;
  color: var(--ink-3); }

/* The centre gutter: a hairline with the shadow a bound spread would cast. */
.spread-gutter { position: absolute; top: 8%; bottom: 8%; left: calc(50% + 8px); width: 1px;
  background: var(--rule-2); }
.spread-gutter::before, .spread-gutter::after { content: ""; position: absolute; top: 0; bottom: 0;
  width: 26px; }
.spread-gutter::before { right: 0; background: linear-gradient(90deg, transparent, rgba(16, 16, 16, .06)); }
.spread-gutter::after { left: 0; background: linear-gradient(90deg, rgba(16, 16, 16, .06), transparent); }

.spread figure { margin: 0; }
.spread-recto { margin-top: 26px; }
.spread-verso { max-width: 236px; justify-self: center; }
.spread figcaption { border-top-color: var(--rule-2); }
.spread figcaption b { font: 500 10px var(--mono); letter-spacing: .16em; text-transform: uppercase;
  color: var(--forest); }
.spread figcaption span { font-size: 12.5px; color: var(--ink-3); font-style: italic; }

/* Editor's marks: circled letter, hairline label. */
.mark { position: absolute; z-index: 4; display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 11px 7px 8px; background: var(--paper); border: 1px solid var(--rule-2);
  font: 500 9.5px var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--ink-2); }
.mark i { display: grid; place-items: center; width: 17px; height: 17px; border-radius: 50%;
  border: 1px solid var(--amber); font-style: normal; color: var(--ink); }
.mark-a { top: 20%; right: 4%; transform: rotate(1.6deg); }
.mark-b { left: 5%; bottom: 7%; transform: rotate(-1.4deg); }
/* ==================== 06 / LEDGER ==================== */
.ledger-band { background: linear-gradient(180deg, var(--paper) 0%, var(--paper-3) 100%); }

/* The gating notice reads as a stamped editor's warning, not a marketing box. */
.notice { max-width: 74ch; margin: 40px 0 0; padding: 20px 24px; background: var(--paper-2);
  border: 1px solid var(--rule); border-left: 3px solid var(--ink);
  color: var(--ink-2); font-size: 14.5px; line-height: 1.62; }
.notice b { color: var(--ink); font-weight: 600;
  box-shadow: inset 0 -.62em 0 var(--acid); }         /* highlighter pass, ink stays on top */

.table-wrap { margin-top: 34px; overflow-x: auto; background: var(--paper-2);
  border: 1px solid var(--rule-2); box-shadow: var(--shadow); }
.ledger-table { width: 100%; min-width: 720px; border-collapse: collapse; text-align: left;
  font-variant-numeric: tabular-nums; }
.ledger-table caption { padding: 20px 24px 16px; text-align: left; max-width: 74ch;
  font: 500 10.5px var(--mono); letter-spacing: .13em; text-transform: uppercase;
  color: var(--ink-3); line-height: 1.7; }
.ledger-table th, .ledger-table td { padding: 15px 24px; border-top: 1px solid var(--rule);
  vertical-align: baseline; }
.ledger-table thead th { border-top: 1px solid var(--ink); border-bottom: 2px solid var(--ink);
  font: 500 10px var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--ink); }
.ledger-table tbody th { font-family: var(--body); font-weight: 600; font-size: 15px; color: var(--ink);
  white-space: nowrap; }
.ledger-table td { color: var(--ink-2); font-size: 14px; }
.ledger-table .num { text-align: right; white-space: nowrap; color: var(--ink);
  font-family: var(--mono); font-size: 13.5px; }
.ledger-table thead .num { text-align: right; }
.ledger-table tbody tr:hover { background: var(--paper); }
.ledger-table td:last-child { color: var(--ink-3); font-size: 13px; line-height: 1.6; }
.ledger-table .total th, .ledger-table .total td { border-top: 3px double var(--ink);
  padding-top: 17px; padding-bottom: 22px; color: var(--ink); }
.ledger-table .total .num { font-weight: 500; }
.ledger-table .total td:last-child { color: var(--ink-2); }

/* ==================== 07 / ROUTE ==================== */
.route-grid { display: grid; grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr);
  gap: clamp(34px, 5vw, 86px); align-items: start; }
.route-intro { position: sticky; top: 148px; }

.route-list { position: relative; margin: 0; padding: 0; list-style: none; counter-reset: none; }
/* A single rule runs the length of the route; the ink fill tracks scroll. */
.route-list::before, .route-list::after { content: ""; position: absolute; left: 54px;
  top: 14px; bottom: 14px; width: 1px; }
.route-list::before { background: var(--rule-2); }
.route-list::after { background: var(--ink); transform: scaleY(var(--route-progress, 0));
  transform-origin: top center; transition: transform .25s linear; }

.route-list li { position: relative; display: grid; grid-template-columns: 54px minmax(0, 1fr);
  gap: 0 36px; padding: 30px 0; border-top: 1px solid var(--rule); }
.route-list li:first-child { border-top: 0; padding-top: 4px; }
.route-list li::after { content: ""; position: absolute; left: 49px; top: 40px; z-index: 2;
  width: 9px; height: 9px; border-radius: 50%; background: var(--paper);
  border: 1px solid var(--ink); transition: background .4s var(--ease); }
.route-list li:first-child::after { top: 14px; }
.route-list li.is-in::after { background: var(--acid); }

.route-no { padding-top: 9px; color: var(--ink-2); }
.route-body { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline;
  gap: 10px 20px; }
.route-body b { font-family: var(--display); font-variation-settings: var(--display-vs);
  letter-spacing: var(--display-ls); font-weight: 400; font-size: clamp(25px, 3vw, 40px);
  line-height: 1.02; color: var(--ink); }
.route-body > span { grid-column: 1 / -1; max-width: 52ch; margin-top: 2px;
  color: var(--ink-2); font-size: 14.5px; line-height: 1.6; }

.route-body em { justify-self: end; padding: 5px 10px 4px; font-style: normal;
  font: 500 9.5px var(--mono); letter-spacing: .15em; text-transform: uppercase; white-space: nowrap; }
.route-body em[data-status="live"] { background: var(--acid); color: var(--ink); }
.route-body em[data-status="next"] { border: 1px solid var(--ink); color: var(--ink); }
.route-body em[data-status="planned"] { border: 1px solid var(--rule-2); color: var(--ink-2); }
.route-body em[data-status="exploring"] { border: 1px dashed var(--rule-2); color: var(--ink-2); }
/* ==================== 08 / GOODS ==================== */
.goods-band { border-top: 1px solid var(--rule); }
.goods-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(18px, 2.4vw, 34px); margin-top: 46px; }
.good { margin: 0; }
.good .plate-frame { aspect-ratio: 4 / 5; transition: transform .5s var(--ease); }
.good:hover .plate-frame { transform: translateY(-6px); }
.good img { transition: transform 1.1s var(--ease); }
.good:hover img { transform: scale(1.04); }

/* Rubber stamp - amber rule, ink text, sitting off-square like a real one. */
.stamp { position: absolute; top: 14px; right: 12px; z-index: 3; padding: 6px 12px 5px;
  background: rgba(244, 240, 232, .9); border: 1px solid var(--amber); color: var(--ink);
  transform: rotate(-7deg); }

/* ==================== COLOPHON ==================== */
.colophon { position: relative; z-index: 1; overflow: hidden; padding: clamp(64px, 8vw, 108px) 0 42px;
  background: var(--paper-3); border-top: 2px solid var(--ink); }
.colophon .ghost { position: absolute; left: 50%; bottom: -.22em; transform: translateX(-50%);
  font-size: clamp(120px, 22vw, 340px); line-height: .8; white-space: nowrap;
  color: var(--ink); opacity: .05; pointer-events: none; }

.notes-apparatus { padding-bottom: 40px; border-bottom: 1px solid var(--rule-2); }
.notes-head { color: var(--ink-3); }
.fn-list { margin: 20px 0 0; padding: 0; list-style: none;
  columns: 2; column-gap: 54px; column-rule: 1px solid var(--rule); }
.fn-list li { break-inside: avoid; margin: 0 0 14px; padding-left: 24px; text-indent: -24px;
  max-width: 62ch; color: var(--ink-3); font-size: 12.5px; line-height: 1.62; }
.fn-list b { color: var(--ink-2); font-weight: 500; font-family: var(--mono); font-size: 11.5px;
  padding-right: 5px; }
.fn-list a { color: var(--forest); text-decoration: none; padding-left: 3px; }
.fn-list a:hover { box-shadow: inset 0 -6px 0 var(--acid); }
/* Following a footnote marker marks the note, the way a finger would. */
.fn-list li:target { color: var(--ink-2); }
.fn-list li:target b { box-shadow: inset 0 -7px 0 var(--acid); }

.colophon-grid { display: grid; grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, .8fr));
  gap: clamp(28px, 4vw, 64px); padding: 44px 0; }
.colophon-brand p { margin: 12px 0 0; max-width: 34ch; color: var(--ink-2); font-size: 14.5px; }
.imprint { color: var(--ink-3) !important; font-size: 12.5px !important; font-style: italic;
  line-height: 1.65; }
.colophon-label { color: var(--forest); margin-bottom: 16px; }
.colophon-label-2 { margin-top: 26px; }
.colophon-grid a { display: block; margin-bottom: 9px; color: var(--ink-2); text-decoration: none;
  font-size: 14.5px; width: fit-content; }
.colophon-grid a:hover { color: var(--ink); box-shadow: inset 0 -8px 0 var(--acid); }
/* site.css:12 also styles .socials for the old dark footer - grey rule, acid
   hover. These come later, so the paper version wins on source order. */
.socials { display: flex; flex-wrap: wrap; gap: 8px; }
.socials a { margin: 0; padding: 7px 14px; border: 1px solid var(--rule-2);
  font: 500 10px var(--mono); letter-spacing: .16em; text-transform: uppercase; }
.socials a:hover { border-color: var(--ink); box-shadow: none; background: var(--acid); color: var(--ink); }

.copyright { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 14px; margin: 0;
  padding-top: 22px; border-top: 1px solid var(--rule-2);
  font: 500 10px var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-3); }

/* ==================== REVEAL ====================
   Everything arrives the way ink meets paper: a short rise, no bounce. */
[data-reveal] { opacity: 0; transform: translateY(22px);
  transition: opacity .85s var(--ease), transform .85s var(--ease); }
[data-reveal].is-in { opacity: 1; transform: none; }
[data-reveal-delay="1"] { transition-delay: .08s; }
[data-reveal-delay="2"] { transition-delay: .16s; }
[data-reveal-delay="3"] { transition-delay: .24s; }
[data-reveal-delay="4"] { transition-delay: .32s; }
/* ==================== RESPONSIVE ==================== */
/* The folio needs real margin, not nearly enough of it. Its number box runs from
   35px (rail at 20 plus 15 of padding) to about 54px once the 3px hover shift is
   counted, and the shell's left edge is 44px flat until the viewport passes
   1388px, after which it opens at (100vw - 1300) / 2. So the paper only clears
   the rail from 1408px up, and it was being drawn from 1241px: at 1280px the
   numbers sat on the lede, and because each one is a link, the top of the lede
   was covered by eight anchors. Same reasoning as the section names above, one
   step further out - names want 1560px, numbers want 1410px, and below that the
   rail is not a margin mark, it is an overlay. */
@media (max-width: 1410px) {
  .folio { display: none; }
}

@media (max-width: 1100px) {
  .front-grid { grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "lead" "plate" "contents"; }
  .front-plate { max-width: 620px; }
  .contents { max-width: 620px; }

  .figures-inner { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .figures-inner > div { border-bottom: 1px solid var(--rule); }
  .figures-inner > div:nth-child(3n) { border-right: 0; }
  .figures-inner > div:nth-child(3n + 1) { padding-left: 0; }

  .deck { grid-template-columns: minmax(0, 1fr); }
  .notes-grid { grid-template-columns: minmax(0, 1fr); }
  .margin-note { position: static; max-width: 640px; }

  .spread { grid-template-columns: minmax(0, 1fr); padding-top: 56px; }
  .spread-gutter, .mark { display: none; }
  .spread-recto { margin-top: 0; }
  .spread-verso { justify-self: start; }

  .route-grid { grid-template-columns: minmax(0, 1fr); }
  .route-intro { position: static; }
  .goods-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* The concept hid .mast-nav at this width, because a floating dock flew that
   page and the nav was decoration. On the shipped site the masthead is the only
   navigation above the colophon, so instead of hiding it the row wraps and the
   nav becomes what site.css:37 already made it at 900px - a scrolling strip with
   every destination still reachable. Hiding it would have stranded mobile
   visitors on whatever page they landed on. */
@media (max-width: 860px) {
  .mast-inner { flex-wrap: wrap; height: auto; min-height: 58px; gap: 10px 18px; }
  .masthead.is-stuck .mast-inner { height: auto; }
  .mast-cta { margin-left: auto; }
  .mast-nav { order: 3; flex: 1 0 100%; margin: 0; gap: 18px; padding: 3px 0 9px;
    border-top: 1px solid var(--rule); overflow-x: auto; scrollbar-width: none; }
  .mast-nav::-webkit-scrollbar { display: none; }
  .mast-nav a { flex: none; white-space: nowrap; }
  .strip-end { display: none; }

  .columns { columns: 1; column-rule: 0; }
  .figures-inner { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .figures-inner > div:nth-child(2n) { border-right: 0; }
  .figures-inner > div:nth-child(2n + 1) { padding-left: 0; }
  .fn-list { columns: 1; column-rule: 0; }
  .colophon-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 36px 0; }
  .colophon-brand { grid-column: 1 / -1; }
  .pull blockquote { max-width: none; }
  .band-head-row { flex-direction: column; align-items: flex-start; gap: 20px; }
  .band-head-row .band-note { margin: 0; }
}

@media (max-width: 620px) {
  :root { --band-y: 62px; }
  .strip-inner { gap: 14px; overflow-x: auto; scrollbar-width: none; }
  .strip-inner::-webkit-scrollbar { display: none; }
  /* No height here: the 860px block above put this row on two lines. */
  .mast-inner { gap: 8px 14px; }
  .wordmark { font-size: 25px; }

  .front-lead .cta-row .btn-ink,
  .front-lead .cta-row .btn-line { width: 100%; justify-content: center; }
  .figures-inner > div { padding-right: 12px; }
  /* A five-column ledger scrolls inside .table-wrap at this width, so the prose
     column is wrapping inside the 720px min-width while the short columns beside
     it stay one line - which put rows that are 40px tall on desktop past 200px
     here, most of it empty. Tighter cells hand that column back about 60px of
     measure and take the row height down with it. It is a mitigation, not a fix:
     these tables want a stacked layout on a phone. */
  .ledger-table th, .ledger-table td { padding: 11px 16px; }
  .ledger-table caption { padding: 16px 18px 13px; }
  .notice { padding: 17px 18px; }
  .sheet-foot { flex-direction: column; align-items: flex-start; gap: 16px; }
  .route-list li { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .route-list::before, .route-list::after, .route-list li::after { display: none; }
  .route-body { grid-template-columns: minmax(0, 1fr); }
  .route-body em { justify-self: start; }
  .copyright { flex-direction: column; gap: 8px; }
}

/* Mobile navigation is a compact disclosure: every destination remains present,
   but the header no longer spends a second row on a tiny scrolling link strip. */
@media (max-width: 700px) {
  .mast-strip { max-height: 27px; }
  .strip-inner { height: 26px; gap: 0; }
  .strip-inner span { display: none; }
  .strip-inner span:first-child { display: block; color: var(--ink-2); font-size: 9px; }
  .strip-inner span:first-child::after { content: " / Vol. 042"; color: var(--ink-3); }

  .mast-inner { min-height: 60px; gap: 12px; }
  .masthead.is-stuck .mast-inner { min-height: 56px; }
  .mast-cta { display: none; }
  .mast-menu { display: inline-flex; align-items: center; justify-content: center; gap: 9px;
    min-height: 44px; margin-left: auto; padding: 10px 0 10px 14px; border: 0;
    background: transparent; color: var(--ink); cursor: pointer; font: 500 10px var(--mono);
    letter-spacing: .15em; text-transform: uppercase; }
  .mast-menu i, .mast-menu i::before, .mast-menu i::after { display: block; width: 18px; height: 1px;
    background: currentColor; transition: transform .22s var(--ease), opacity .22s var(--ease); }
  .mast-menu i { position: relative; }
  .mast-menu i::before, .mast-menu i::after { content: ""; position: absolute; left: 0; }
  .mast-menu i::before { top: -6px; }
  .mast-menu i::after { top: 6px; }
  .mast-menu[aria-expanded="true"] i { background: transparent; }
  .mast-menu[aria-expanded="true"] i::before { transform: translateY(6px) rotate(45deg); }
  .mast-menu[aria-expanded="true"] i::after { transform: translateY(-6px) rotate(-45deg); }
  .mast-nav { display: none; order: 3; flex-basis: 100%; margin: 0; padding: 0 0 10px;
    border-top: 1px solid var(--rule); overflow: visible; }
  .mast-nav.is-open { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mast-nav a { min-height: 44px; display: flex; align-items: center; padding: 12px 0;
    border-bottom: 1px solid var(--rule); font-size: 10px; }
  .mast-nav a:nth-child(odd) { padding-right: 12px; }
  .mast-nav a:nth-child(even) { padding-left: 12px; border-left: 1px solid var(--rule); }
}

/* ==================== REDUCED MOTION ====================
   The page still works as a page: everything visible, nothing moving. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  .rule { transform: scaleX(1) !important; }
  .spread { transform: none !important; }
  .frame { opacity: 1 !important; filter: none !important; }
}

/* ==================== LEAN HOME ====================
   The home page is an invitation, not the complete dispatch. CapyCity stays
   live behind it; opaque panels appear only where a reader needs to stop. */
body[data-page="home"] .colophon { padding-block: 38px 26px; border-top-width: 1px; }
body[data-page="home"] .notes-apparatus { display: none; }
body[data-page="home"] .colophon-grid { padding-block: 26px; }
body[data-page="home"] .colophon .ghost { font-size: clamp(90px, 16vw, 220px); }

.landing { position: relative; z-index: 1; }
.landing-hero { position: relative; min-height: min(760px, calc(100svh - 92px)); display: grid; align-items: center; padding: clamp(64px, 9vw, 132px) 0 74px; }
.landing-hero-grid { display: grid; grid-template-columns: minmax(0, 1.02fr) minmax(300px, .74fr); align-items: center; gap: clamp(36px, 8vw, 130px); }
.landing-copy { max-width: 640px; }
.landing-eyebrow { display: flex; align-items: center; gap: 9px; margin: 0; color: var(--ink-2); font: 500 10px/1.4 var(--mono); letter-spacing: .17em; text-transform: uppercase; }
.landing-eyebrow span { width: 7px; height: 7px; border-radius: 50%; background: var(--acid); box-shadow: 0 0 0 3px rgba(194,238,44,.22); }
.landing h1 { max-width: 8ch; margin-top: 18px; font-size: clamp(58px, 8.8vw, 138px); }
.landing-intro { max-width: 39ch; margin: 26px 0 0; color: var(--ink-2); font: 400 clamp(19px, 2vw, 27px)/1.35 var(--serif); }
.landing-meta { margin: 22px 0 0; color: var(--ink-2); font: 500 10px/1.5 var(--mono); letter-spacing: .15em; text-transform: uppercase; }
.landing-meta i { padding: 0 6px; color: var(--forest); font-style: normal; }
.hero-capy { position: relative; margin: 0; padding: 10px; background: rgba(255,253,248,.78); border: 1px solid var(--rule-2); box-shadow: var(--shadow-2); transform: rotate(2deg); }
.hero-capy img { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; filter: saturate(.92) contrast(.97); }
.hero-capy figcaption, .capy-card figcaption { display: flex; justify-content: space-between; gap: 12px; margin-top: 10px; color: var(--ink-2); font-size: 12px; font-style: italic; }
.hero-capy figcaption b, .capy-card figcaption b { color: var(--forest); font: 500 10px var(--mono); letter-spacing: .13em; text-transform: uppercase; }
.landing-scroll { position: absolute; bottom: 26px; left: 50%; transform: translateX(-50%); color: var(--ink-2); font: 500 9px var(--mono); letter-spacing: .15em; text-transform: uppercase; }
.landing-scroll span { display: inline-block; margin-left: 8px; color: var(--forest); animation: landing-bob 1.8s ease-in-out infinite; }

.landing-section { padding: clamp(74px, 11vw, 150px) 0; }
.landing-head { max-width: 680px; }
.landing-head h2, .world-card h2, .landing-close h2 { margin-top: 16px; }
.landing-head > p:last-child { max-width: 40ch; margin: 24px 0 0; color: var(--ink-2); font-size: 17px; }
.capy-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(14px, 2.5vw, 34px); margin-top: 44px; }
.capy-card { margin: 0; padding: 9px; background: rgba(255,253,248,.7); border: 1px solid var(--rule); transition: transform .25s var(--ease), background .25s; }
.capy-card:hover { background: var(--paper-2); transform: translateY(-5px); }
.capy-card img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; filter: saturate(.84); }
.text-link { display: inline-block; margin-top: 30px; color: var(--forest); border-bottom: 1px solid currentColor; font: 500 10px var(--mono); letter-spacing: .15em; text-transform: uppercase; }
.text-link:hover { color: var(--ink); }

.club { border-block: 1px solid var(--rule-2); background: rgba(244,240,232,.83); }
.club-layout, .faq-layout { display: grid; grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr); gap: clamp(42px, 9vw, 150px); align-items: start; }
.club-points { border-top: 1px solid var(--ink); }
.club-points article { display: grid; grid-template-columns: minmax(120px, .5fr) 1fr; gap: 20px; padding: 20px 0; border-bottom: 1px solid var(--rule-2); }
.club-points b { color: var(--forest); font: 500 10px var(--mono); letter-spacing: .16em; text-transform: uppercase; }
.club-points p { margin: 0; color: var(--ink-2); font-size: 16px; }

.world { padding-block: clamp(110px, 16vw, 230px); }
.world-card { max-width: 760px; margin-left: auto; padding: clamp(30px, 5vw, 64px); background: rgba(16,16,16,.91); color: var(--paper); border: 1px solid rgba(255,253,248,.2); box-shadow: var(--shadow-2); }
.world-card h2 { color: var(--paper); }
.world-card h2 em { color: var(--acid); }
.world-card p:not(.landing-eyebrow) { max-width: 42ch; margin: 24px 0 30px; color: rgba(244,240,232,.77); font-size: 17px; }
.world-card .landing-eyebrow { color: rgba(244,240,232,.72); }
.world-card .btn-line { border-color: var(--paper); color: var(--paper); }
.world-card .btn-line:hover { color: var(--ink); }

.ahead { padding-block: clamp(92px, 13vw, 174px); background: rgba(244,240,232,.9); border-block: 1px solid var(--rule-2); }
.ahead-panel { max-width: 880px; margin-inline: auto; text-align: center; }
.ahead-panel .landing-eyebrow { justify-content: center; }
.ahead-panel h2 { margin-top: 18px; }
.ahead-chips { display: flex; flex-wrap: wrap; justify-content: center; gap: 16px 20px; max-width: 720px; margin: clamp(40px, 6vw, 70px) auto 0; }
.ahead-chip { display: inline-flex; align-items: center; justify-content: center; min-height: 56px; padding: 13px 27px; border: 1px solid rgba(16,16,16,.12); border-radius: 999px; background: var(--paper-2); color: var(--ink); box-shadow: 0 8px 18px rgba(16,16,16,.05); font-size: clamp(18px, 2vw, 23px); animation: chip-bounce 3.1s var(--ease) infinite; animation-delay: var(--chip-delay); }
.ahead-note { margin: clamp(50px, 8vw, 90px) auto 0; max-width: 22ch; color: var(--ink-2); font-size: clamp(24px, 3vw, 39px); line-height: 1.15; }
.ahead-note::first-line { color: var(--ink-3); }

/* ==================== ROADMAP ====================
   A single route drawn through the existing city plate. It is deliberately a
   page section rather than a stack of cards: the line gives four phases a
   shared direction while the paper, type and city remain the visual lead. */
.roadmap-section { position: relative; overflow: hidden; padding-block: clamp(92px, 13vw, 176px); border-block: 1px solid var(--rule-2); background: rgba(244,240,232,.91); }
.roadmap-intro { max-width: 760px; }
.roadmap-intro h2 { margin-top: 16px; }
.roadmap-intro > p:last-child { max-width: 42ch; margin: 24px 0 0; color: var(--ink-2); font-size: 17px; }
.roadmap-route { margin-top: clamp(50px, 7vw, 96px); }
.roadmap-phases { position: relative; display: grid; gap: clamp(38px, 5vw, 76px); max-width: 1120px; margin: 0 auto; padding: 0; list-style: none; }
.roadmap-phases::before { content: ""; position: absolute; top: 52px; bottom: 52px; left: 50%; width: 1px; background: var(--ink); transform: translateX(-.5px); }
.roadmap-phase { position: relative; display: grid; grid-template-columns: 1fr 1fr; min-height: 250px; }
.roadmap-phase article { width: min(100%, 440px); padding: 0 24px; }
.roadmap-phase.is-left article { grid-column: 1; justify-self: end; text-align: right; }
.roadmap-phase.is-right article { grid-column: 2; justify-self: start; text-align: left; }
.roadmap-marker { position: absolute; z-index: 1; top: 76px; left: 50%; display: grid; width: 28px; height: 28px; place-items: center; border: 2px solid var(--ink); border-radius: 50%; background: var(--forest); transform: translateX(-50%); }
.roadmap-marker::after { content: ""; width: 10px; height: 10px; border-radius: 50%; background: var(--acid); }
.roadmap-marker i { position: absolute; top: 43px; width: 6px; height: 6px; border-radius: 50%; background: var(--acid); animation: route-bounce 2.3s var(--ease) infinite; }
.roadmap-label { margin: 0; color: var(--ink-2); font: 500 10px/1.5 var(--mono); letter-spacing: .16em; text-transform: uppercase; }
.roadmap-label i { padding: 0 5px; color: var(--forest); font-style: normal; }
.roadmap-status { display: inline-block; margin: 12px 0 14px; padding: 5px 9px; background: var(--acid); color: var(--ink); font: 500 10px/1.35 var(--mono); letter-spacing: .13em; text-transform: uppercase; }
.roadmap-phase h3 { font-size: clamp(34px, 4vw, 56px); line-height: .93; letter-spacing: -.055em; }
.roadmap-phase h3 + p { max-width: 34ch; margin: 17px 0 0; color: var(--ink-2); font-size: 16px; line-height: 1.55; }
.roadmap-phase.is-left h3 + p { margin-left: auto; }
.roadmap-phase ul { display: grid; gap: 7px; margin: 18px 0 0; padding: 0; list-style: none; color: var(--ink-2); font-size: 13px; line-height: 1.45; }
.roadmap-phase li::before { content: ""; display: inline-block; width: 6px; height: 6px; margin: 0 9px 2px 0; border-radius: 50%; background: var(--forest); }
.roadmap-principles { display: grid; grid-template-columns: minmax(210px,.72fr) minmax(0,1.6fr); gap: clamp(26px, 5vw, 74px); margin-top: clamp(62px, 9vw, 130px); padding: clamp(24px, 4vw, 42px); border: 1px solid var(--ink); background: rgba(255,253,248,.65); }
.roadmap-principles h3 { margin-top: 15px; font-size: clamp(34px, 4vw, 52px); letter-spacing: -.05em; }
.roadmap-principles ol { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; margin: 0; padding: 0; list-style: none; }
.roadmap-principles li { display: grid; gap: 10px; padding: 5px clamp(16px, 2vw, 26px); border-left: 1px solid var(--rule-2); }
.roadmap-principles li:first-child { border-left: 0; }
.roadmap-principles b { display: grid; width: 35px; height: 35px; place-items: center; border-radius: 50%; background: var(--acid); color: var(--ink); font: 500 10px var(--mono); }
.roadmap-principles strong { font-size: 18px; line-height: 1.25; }
.roadmap-principles span { color: var(--ink-2); font-size: 13px; line-height: 1.45; }
@keyframes route-bounce { 0%, 100% { transform: translateY(0); opacity: .55; } 45% { transform: translateY(-9px); opacity: 1; } 60% { transform: translateY(1px); } }

.store-preview { overflow: hidden; padding-bottom: clamp(84px, 11vw, 150px); }
.store-head { max-width: 620px; }
.store-head h2 { margin-top: 16px; }
.store-head > p:last-child { max-width: 39ch; margin: 22px 0 0; color: var(--ink-2); font-size: 17px; }
.store-viewport { margin-top: 44px; overflow: hidden; }
.store-track { display: flex; width: max-content; gap: clamp(16px, 2.2vw, 28px); padding: 4px clamp(16px, 2.2vw, 32px) 20px; animation: store-drift 30s linear infinite; }
.store-viewport:hover .store-track { animation-play-state: paused; }
.store-card { width: clamp(210px, 20vw, 310px); margin: 0; padding: 9px; background: rgba(255,253,248,.8); border: 1px solid var(--rule-2); box-shadow: 0 14px 30px rgba(16,16,16,.1); }
.store-card img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; filter: saturate(.83) contrast(.94); }
.store-card figcaption { display: flex; justify-content: space-between; gap: 10px; margin-top: 9px; color: var(--ink-2); font-size: 12px; font-style: italic; }
.store-card figcaption b { color: var(--forest); font: 500 9px var(--mono); letter-spacing: .13em; text-transform: uppercase; }
.store-card figcaption span { color: var(--ink-3); font: 500 9px var(--mono); letter-spacing: .12em; text-transform: uppercase; }

.faq { background: rgba(244,240,232,.92); border-top: 1px solid var(--rule-2); }
.faq-list { border-top: 1px solid var(--ink); }
.faq-list details { border-bottom: 1px solid var(--rule-2); }
.faq-list summary { display: flex; align-items: center; min-height: 64px; padding: 12px 34px 12px 0; cursor: pointer; list-style: none; color: var(--ink); font-size: clamp(17px, 2vw, 21px); }
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary::after { content: '+'; margin-left: auto; color: var(--forest); font: 400 28px/1 var(--serif); }
.faq-list details[open] summary::after { content: '−'; }
.faq-list details p { max-width: 52ch; margin: 0; padding: 0 22px 22px 0; color: var(--ink-2); font-size: 15px; }
.faq-list details > div { max-width: 62ch; padding: 0 22px 22px 0; color: var(--ink-2); font-size: 15px; }
.faq-list details ul { display: grid; gap: 11px; margin: 0; padding-left: 20px; }
.faq-list details li::marker { color: var(--forest); }
.faq-list details li b { color: var(--ink); }
.faq-list p a { color: var(--forest); text-decoration: underline; text-underline-offset: 3px; }

.landing-close { padding: clamp(90px, 13vw, 180px) 0; background: var(--paper-3); border-top: 1px solid var(--ink); }
.landing-close h2 { max-width: 10ch; }
@keyframes landing-bob { 50% { transform: translateY(4px); } }
@keyframes chip-bounce { 0%, 100% { transform: translateY(0); } 45% { transform: translateY(-7px); } 60% { transform: translateY(1px); } }
@keyframes store-drift { to { transform: translateX(calc(-50% - 14px)); } }

@media (max-width: 760px) {
  .landing-hero { min-height: auto; padding-block: 66px 92px; }
  .landing-hero-grid, .club-layout, .faq-layout { grid-template-columns: minmax(0, 1fr); }
  .landing-hero-grid { gap: 40px; }
  .landing h1 { font-size: clamp(54px, 15vw, 82px); }
  .landing-intro { font-size: 20px; }
  .hero-capy { width: min(100%, 440px); margin-inline: auto; transform: rotate(1deg); }
  .landing-scroll { bottom: 28px; }
  .capy-grid { grid-template-columns: repeat(3, minmax(170px, .8fr)); overflow-x: auto; margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter); scroll-snap-type: x mandatory; }
  .capy-card { scroll-snap-align: start; }
  .club-points article { grid-template-columns: 1fr; gap: 7px; }
  .world-card { margin: 0; }
  .roadmap-section { padding-block: 76px; }
  .roadmap-phases { gap: 50px; }
  .roadmap-phases::before { left: 14px; top: 35px; bottom: 35px; }
  .roadmap-phase { display: block; min-height: 0; padding-left: 46px; }
  .roadmap-phase article, .roadmap-phase.is-left article, .roadmap-phase.is-right article { width: 100%; padding: 0; text-align: left; }
  .roadmap-marker { top: 28px; left: 14px; }
  .roadmap-phase.is-left h3 + p { margin-left: 0; }
  .roadmap-principles { grid-template-columns: 1fr; gap: 28px; }
  .roadmap-principles ol { grid-template-columns: 1fr; }
  .roadmap-principles li, .roadmap-principles li:first-child { grid-template-columns: 38px 1fr; align-items: start; padding: 18px 0; border-left: 0; border-top: 1px solid var(--rule-2); }
  .roadmap-principles li strong { align-self: end; }
  .roadmap-principles li span { grid-column: 2; }
  .ahead-chips { gap: 12px; }
  .ahead-chip { min-height: 50px; padding: 11px 21px; font-size: 18px; }
  .store-viewport { overflow-x: auto; scrollbar-width: none; }
  .store-viewport::-webkit-scrollbar { display: none; }
  .store-track { animation-duration: 24s; }
  .landing-close .cta-row .btn-ink, .landing-close .cta-row .btn-line { width: 100%; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) { .landing-scroll span, .ahead-chip, .roadmap-marker i { animation: none; } .store-viewport { overflow-x: auto; } .store-track { width: max-content; animation: none; transform: none; } }

/* The compact navigation opens as a real menu panel: a single vertical list
   that reads in order and does not squeeze destination names into a grid. */
@media (max-width: 700px) {
  .mast-main { position: relative; }
  .mast-nav.is-open { position: absolute; z-index: 35; top: 100%; left: 0; display: flex; flex-direction: column; width: 100%; padding: 8px var(--gutter) 14px; border: 1px solid var(--rule-2); border-inline: 0; background: var(--paper-2); box-shadow: 0 18px 34px rgba(16,16,16,.14); }
  .mast-nav.is-open a { width: 100%; min-height: 50px; padding: 15px 0; border-left: 0; border-bottom: 1px solid var(--rule); }
  .mast-nav.is-open a:last-child { border-bottom: 0; }
}
