/* ==========================================================================
   ROAMWITHADI — responsive.css
   "The Expedition Cut" · the four breakpoints and nothing else.
   --------------------------------------------------------------------------

   THE ONE RULE THIS FILE OBEYS
   Every declaration below lives inside an @media (min-width: …) block. There
   is not one top-level rule in this file and not one max-width query. The
   site is mobile-first: style.css ships the 360px layout, effects.css ships
   the motion, and this file only ever ADDS as the viewport grows. Anything
   that must be true at 360px belongs in style.css — if it cannot be written
   as a min-width rule, it is not this file's job.

   EXACTLY FOUR BREAKPOINTS
     §1  480px   --gutter: 1.5rem · the hero headline starts moving · the
                 card grids go two-up · the newsletter form gets onto one
                 line · the touch-target floor
     §2  768px   --gutter: 2rem · story / bio / contact / destination rows
                 split · the gear list gains its columns · the footer brand
                 sits beside the socials · the grain doubles
     §3  1024px  --gutter: 3rem · THE CHAPTER RAIL AND THE HERO COMPASS ARE
                 SWITCHED ON (style.css ships both display:none and names
                 this file as the place they come back) · the masthead
                 becomes a horizontal row and the toggle goes away · the
                 videos go three-up · the blog lead sits beside the cards ·
                 the footer goes four-up · .dest-pin opts into the pinned reel
     §4  1440px  --gutter: 4.5rem · the display type sits at its ceiling ·
                 the destination cards gain width

   CASCADE POSITION
   header.php loads style.css → effects.css → responsive.css and calls that
   order load-bearing. On equal specificity these rules therefore win without
   an !important, and there is not one in this file. Where the earlier sheets
   are MORE specific than a bare class — everything the masthead drawer does
   is written `html.is-js .nav-panel` at (0,2,0), in BOTH style.css and
   effects.css — the rules here carry the same prefix so they still win on
   load order. A bare `.nav-panel` at (0,1,0) never beats that, however late
   it loads, and the site would ship with no desktop navigation. Same story
   for `html.is-js .nav-list{gap}` and `html.is-js .nav-link{font-size}`:
   both are answered here at matching specificity, not below it.

   --------------------------------------------------------------------------
   THE RESET LOG — everything style.css or effects.css sets for the small
   screen that is EXPLICITLY overridden here rather than merely added to.
   This list exists because of a real defect in this repo's history: a
   grid-template-areas declared in style.css and never reset in
   responsive.css left a whole section stacked on desktop forever.

   §1 480
     grid-template-columns   .video-grid, .blog-cards  1fr → two-up
     gap                     .video-grid, .blog-cards  the single `gap` is
                             split into column-gap / row-gap
     flex-direction          .news-form  column → row
     width / height          .social-link  2.35rem boxes raised to a 44px
                             floor by min-* (a raise only, never a shrink)

   §2 768
     grid-template-columns   .story-grid 1fr → 2 · .bio-grid 1fr → 2 ·
                             .contact-grid 1fr → 2 · .gear-row 1fr → 2
     display                 .gear-item  (typography only in style.css) →
                             grid, so the mono role gets its own column
     grid-template-columns   .foot-top 1fr → content + socials
     gap                     .foot-top  var(--space-lg) on both axes → a
                             tight row-gap and a wide column-gap
     display                 .post-card--lead  flex column → grid
     opacity                 .grain  .045 → .09, the doubling effects.css
                             asks for in its own comment

   §3 1024
     display                 .chapter-rail  none → flex   (style.css §11
                             names this file and this value)
     display                 .hero-compass  none → block  (style.css names
                             this file and this value)
     flex                    .mast-inner > .nav / > .nav-panel  1 0 100% →
                             0 0 auto, so the NO-JS nav stops taking a whole
                             row of the masthead to itself
     flex-wrap               .mast-inner  wrap → nowrap
     width                   .nav  100% → auto
     margin-top              .nav-cta  var(--space-sm) → 0
     display / position / inset / width / padding / background / border /
     overflow / visibility / transform
                             html.is-js .nav-panel — the whole fixed-drawer
                             battery from style.css (position:fixed, inset,
                             width:min(86vw,21rem), 6rem padding, ink-deep
                             ground, left border, overflow-y:auto,
                             visibility:hidden, transform:translateX(100%))
     opacity / visibility / translate / pointer-events
                             html.is-js .nav-panel — and the second, softer
                             drawer battery effects.css lays on top of it
     flex-direction / gap    .nav-list  column + .1rem (.35rem under is-js)
                             → row + var(--space-md)
     font-size / letter-spacing
                             html.is-js .nav-link  the drawer's --text-lg /
                             .1em back to --text-sm / .16em
     overflow                .dest-rail  overflow-x:auto → visible, and ONLY
                             under html.is-js
     scroll-snap-type        .dest-rail  x mandatory → none, same scope
     flex-basis              .dest-card  0 0 78% → a definite 21rem, because
                             a percentage basis against a max-content rail
                             is indefinite and resolves to content size
     grid-column             .video-card / .post-card :nth-child(3) — the
                             full-row span §1 gave them is put back to auto
     grid-template-columns   .blog-cards  back to ONE column: it is the
                             narrow half of a split now, not the whole measure
     padding-inline-end      .container  reserves --rail beside the rail
     right                   .hero-compass  var(--gutter) → gutter + rail

   §4 1440
     padding-inline-end      .container  the rail reservation is handed back
     right                   .hero-compass  back to var(--gutter)
     max-width               .dest-card  21rem → 26rem. Without this reset
                             the wider flex-basis beside it would be capped
                             straight back and the cards would not grow.

   --------------------------------------------------------------------------
   HORIZONTAL OVERFLOW — audited at 360 / 480 / 768 / 1024 / 1440

     .seam · .hero-media · .hero-veil · .dest-bg · .blog-bg · .news-bg are
       every full-bleed layer on the site, and every one of them is
       position:absolute with inset:0 inside a section that is itself
       overflow:hidden. None can reach the document. Verified in style.css
       rather than guarded blindly here — a max-inline-size:100% on an
       inset:0 box is a no-op, and a no-op in a file this precise is noise.

     .dest-rail is the real one. Below 1024 it is a native overflow-x
       scroller and contains itself. At 1024, under html.is-js only, that
       overflow is turned OFF so animations.js can translate .dest-track
       instead — at which point five cards at max-content width WOULD run
       off the page. That is why .dest-pin is clipped on the inline axis in
       the same rule block. The two belong together and must never be
       separated.

     Every grid track written in this file uses minmax(0, …), never a bare
       1fr. A bare 1fr is minmax(auto, 1fr) and refuses to shrink below its
       content's min-content width — one long unbroken word in a card and
       the row overflows. That is the discipline here, not a special case.

     .nav-list wraps at §3, so seven items plus the CTA can never widen the
       masthead past the viewport.

   TOUCH TARGETS
     .btn-icon / .nav-toggle / .to-top are 2.75rem = 44px in style.css and
     .video-play / .collage-play are 3.5rem, so the floor in §1 is a no-op
     for all of them and exists to keep them that way. It does two real
     raises: .social-link (2.35rem = 37.6px) and .btn / .news-submit (~43px
     from .95rem padding on a line-height:1 box). .nav-link gets its padding
     opened at §3 for the same reason. Nothing in this file shrinks any
     control at any width. See hand-off note 1 — the 360–479 band cannot be
     reached from a min-width file and belongs to style.css.
   ========================================================================== */


/* ==========================================================================
   §1 · 480px — LARGE MOBILE
   The first width at which anything gets denser, so it is also where the
   touch-target floor is re-asserted.
   ========================================================================== */
@media (min-width: 480px) {

  :root {
    /* --gutter across all four steps: 1.25 → 1.5 → 2 → 3 → 4.5rem */
    --gutter: 1.5rem;

    /* The hero headline. The frozen token is clamp(3rem, 9.5vw, 8.5rem),
       which is pinned to its 3rem floor at every width below 505px — so the
       headline does not grow at all through this whole band. Raising the
       floor and the slope gets it moving from 480 up. The 8.5rem ceiling is
       untouched and is still the ceiling §4 sits at. */
    --text-hero: clamp(3.5rem, 10.5vw, 8.5rem);
  }

  /* ── touch-target floor ──────────────────────────────────────────────
     min-* only: this can raise a control, never shrink one. */
  .btn-icon,
  .nav-toggle,
  .video-play,
  .collage-play,
  .dest-prev,
  .dest-next,
  .to-top,
  .social-link {
    min-inline-size: 44px;
    min-block-size: 44px;
  }

  .btn,
  .news-submit,
  .news-input,
  .field-input,
  .field-textarea {
    min-block-size: 44px;
  }

  /* ── 06 · newsletter: the field and the button onto one line ─────────
     RESET: style.css has .news-form as a flex COLUMN with a single .75rem
     gap. The honeypot .hp is position:absolute and the two hidden inputs
     carry the UA's display:none, so none of the three becomes a flex item;
     the children that lay out are exactly .form-msg (only when the flash
     says so), .news-field, .news-submit and .news-note. The two full-width
     ones are pinned to their own rows so the field/button pair keeps a
     clean line to itself. */
  .news-form {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    column-gap: var(--space-sm);
    row-gap: var(--space-sm);
  }

  .news-form > .form-msg,
  .news-form > .news-note {
    flex: 1 0 100%;
    margin: 0;
  }

  .news-field {
    flex: 1 1 15rem;
    min-inline-size: 0;      /* a flex item's min-width is auto by default */
  }

  .news-input {
    inline-size: 100%;
  }

  .news-submit {
    flex: 0 0 auto;
    inline-size: auto;
  }

  /* ── the card grids go two-up ────────────────────────────────────────
     RESET: both are grid-template-columns:1fr in style.css.

     Home ships three .video-card and three .post-card; /videos ships two
     .video-card and /blog ships a lead plus two briefs. Two columns suit
     all four cases as long as the odd one out spans — which is what the
     nth-child(3) rule does. nth-child(3), not :last-child: on /videos the
     last card is the SECOND one, and spanning that would leave a
     half-width orphan sitting above a full-width card. */
  .video-grid,
  .blog-cards {
    display: grid;
    grid-template-areas: none;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--space-md);
    row-gap: var(--space-lg);
    align-items: start;
  }

  .video-grid > .video-card:nth-child(3),
  .blog-cards > .post-card:nth-child(3) {
    grid-column: 1 / -1;
  }

  /* /blog's index reverses that: there the FIRST card is the lead piece and
     it is the one that runs the full measure, so the third goes back into a
     normal track. */
  .blog-cards--list > .post-card:nth-child(3) {
    grid-column: auto;
  }

  .blog-cards--list > .post-card--lead {
    grid-column: 1 / -1;
  }

  /* ── footer: the legal line stops running together ───────────────────
     style.css gives .foot-legal type but no display, so its three <span>s
     are plain inline boxes with nothing between them. */
  .foot-legal {
    display: flex;
    flex-wrap: wrap;
    column-gap: var(--space-sm);
    row-gap: var(--space-xs);
  }
}


/* ==========================================================================
   §2 · 768px — TABLET
   The width at which two things can sit beside each other. Every split here
   is a two-column grid on a named contract wrapper, with grid-template-areas
   cleared and the children's placement returned to auto, so nothing declared
   for the stacked state can survive into a layout that no longer has it.
   ========================================================================== */
@media (min-width: 768px) {

  /* The masthead CTA comes back. style.css ships it display:none because at
     360px the wordmark + button + toggle overflowed the bar and carried the
     menu toggle off-screen with them. This is the width at which the bar
     genuinely fits all three. */
  .nav-cta {
    display: inline-flex;
    margin-top: 0;
  }

  :root {
    --gutter: 2rem;

    /* Film grain. Spec §9 asks for HALF the opacity below 768px — a
       max-width condition, which this file does not write. effects.css
       therefore ships the MOBILE value as its base (.045, and its own
       comment reads "≥768px doubles this in responsive.css"), and this is
       the doubling. Published as a token as well as a declaration so the
       two sheets can share one number instead of each holding a literal. */
    --grain-op: .09;
  }

  .grain {
    opacity: var(--grain-op);
  }

  /* ── 02 · story: the collage beside the copy ─────────────────────── */
  .story-grid {
    display: grid;
    grid-template-areas: none;
    grid-template-rows: auto;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    align-items: center;
  }

  .story-collage,
  .story-copy {
    grid-area: auto;
  }

  /* ── 03 · /destinations: each row splits, alternate rows flip ────────
     .dest-card--row wraps its own .container, so the split is made on that
     container. The flip is explicit placement rather than `direction` or
     `order`, so the reading order in the DOM is untouched. */
  .dest-card--row .container {
    display: grid;
    grid-template-areas: none;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    column-gap: var(--space-lg);
    row-gap: var(--space-md);
    align-items: center;
  }

  .dest-card--flip .container > .dest-card-media {
    grid-column: 2;
    grid-row: 1;
  }

  .dest-card--flip .container > .dest-card-body {
    grid-column: 1;
    grid-row: 1;
  }

  /* ── 05 · /blog: the lead piece becomes a media/text split ───────────
     RESET: .post-card is a flex column in style.css. .post-card--lead has
     exactly five children — .post-media, then .post-cat, .post-title,
     .post-date and .post-say — so the still takes column one across the
     four rows the rest of them occupy. */
  .blog-cards--list {
    column-gap: var(--space-lg);
  }

  .post-card--lead {
    display: grid;
    grid-template-areas: none;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: var(--space-md);
    align-items: center;
  }

  .post-card--lead > .post-media {
    grid-column: 1;
    grid-row: 1 / span 4;
  }

  /* ── /about: the bio splits, and flips on the alternate section ───── */
  .bio-grid {
    display: grid;
    grid-template-areas: none;
    grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
    column-gap: var(--space-lg);
    align-items: center;
  }

  .bio-media,
  .bio-copy {
    grid-area: auto;
  }

  .bio-grid--flip > .bio-media {
    grid-column: 2;
    grid-row: 1;
  }

  .bio-grid--flip > .bio-copy {
    grid-column: 1;
    grid-row: 1;
  }

  /* ── /gear: the list gains its columns ───────────────────────────────
     Two splits, one inside the other.

     .gear-row is a group — the slate heading, then the <ul> of items.
     RESET of grid-template-columns:1fr: the slate moves out to the left as
     a standing head and the items run down beside it.

     .gear-item is the <li>: a mono .gear-role, the item as an <h3>, and the
     .gear-note under it. style.css gives it type and no display at all, so
     this grid is new — the role becomes a slate-style stub in its own
     column with the item and its note stacked against it. */
  .gear-row {
    grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
    column-gap: var(--space-lg);
    align-items: start;
  }

  .gear-item {
    display: grid;
    grid-template-areas: none;
    grid-template-columns: minmax(4.5rem, 8ch) minmax(0, 1fr);
    column-gap: var(--space-md);
    align-items: start;
  }

  .gear-item > .gear-role {
    grid-column: 1;
    grid-row: 1 / span 2;
  }

  .gear-item > h3 {
    grid-column: 2;
    grid-row: 1;
  }

  .gear-item > .gear-note {
    grid-column: 2;
    grid-row: 2;
  }

  /* The two kit photographs sit between the groups as plates. At 1200px
     wide they take over the page from this width up; held to the measure of
     the text beside them they are illustrations again. */
  .gear-list > .frame {
    max-inline-size: 34rem;
    margin-inline: auto;
  }

  /* ── /contact: the form and the direct details split ─────────────── */
  .contact-grid {
    display: grid;
    grid-template-areas: none;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    column-gap: var(--space-lg);
    align-items: start;
  }

  .contact-form,
  .contact-aside {
    grid-area: auto;
  }

  /* ── footer: the brand block beside the socials ──────────────────────
     RESET: one column and a var(--space-lg) gap on both axes in style.css.
     The wordmark and the tagline belong together, so they keep column one
     across two tight rows and the socials take the whole of column two.
     .foot-cols already ships as a 2 x 2 at the base size and is left alone
     until §3 turns it into four. */
  .foot-top {
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--space-md);
    row-gap: var(--space-xs);
    align-items: center;
  }

  .foot-brand { grid-column: 1; grid-row: 1; }
  .foot-say   { grid-column: 1; grid-row: 2; }

  .foot-social {
    grid-column: 2;
    grid-row: 1 / span 2;
    justify-self: end;
    align-self: center;
  }
}


/* ==========================================================================
   §3 · 1024px — DESKTOP
   The biggest step on the site. Three things that do not exist below this
   width come into being here: the chapter rail and the hero compass, both of
   which style.css ships display:none and hands to this file by name, and the
   pinned destinations reel.
   ========================================================================== */
@media (min-width: 1024px) {

  :root {
    --gutter: 3rem;
  }

  /* ── THE CHAPTER RAIL ────────────────────────────────────────────────
     style.css §11: "Not displayed at the base size — responsive.css
     switches it on at 1024px+ (display:flex)." That is all this needs to
     be. The fixed position, the --rail width, the dark chip, the border,
     the vertical centring and the .9rem rhythm are all written there and
     are neither repeated nor second-guessed here.

     The one structural fix: header.php wraps the links in a <nav> for the
     landmark, so style.css's column lands on ONE child instead of six. The
     wrapper passes the three layout values straight through with `inherit`,
     which keeps style.css the single source of the rail's rhythm rather
     than copying .9rem into a second file where it can drift. */
  .chapter-rail {
    display: flex;
  }

  .chapter-rail > nav {
    display: flex;
    flex-direction: inherit;
    align-items: inherit;
    gap: inherit;
  }

  .chapter-link {
    min-inline-size: 44px;
    min-block-size: 44px;
  }

  /* Reserve the rail's width so no line of type can run underneath it. The
     rail is emitted by header.php on the HOMEPAGE ONLY — every href in it
     is an in-page anchor — which is why this is scoped with
     :has(.chapter-rail) instead of being paid for on all seven routes.
     The masthead is excluded: the rail's links are vertically centred, the
     masthead sits at the top, and pulling the CTA 52px inward on one page
     only would make the nav visibly disagree with itself between pages.
     §4 hands the reservation back. */
  body:has(.chapter-rail) .container:not(.mast-inner) {
    padding-inline-end: calc(var(--gutter) + var(--rail));
  }

  /* ── THE HERO COMPASS ────────────────────────────────────────────────
     style.css: "responsive.css switches it on at 1024px+ (display:block)."
     Its `right: var(--gutter)` would put it under the chapter rail at every
     width from here to 1439, so it is moved clear by the same amount the
     containers are. §4 puts it back. */
  .hero-compass {
    display: block;
    right: calc(var(--gutter) + var(--rail));
  }

  /* THE HERO FURNITURE — switched on here, exactly like .hero-compass above.
     (Hand-off note 2 is resolved: style.css no longer leaves these two in
     flow. They were a third and fourth flex item on .container's only line,
     which crushed the headline below ~900px; they are now pinned to the
     hero's edges and simply revealed at the width that has room for them.)

     .hero-scroll clears the chapter rail the same way the compass and the
     containers do; §4 hands that space back at 1440. */
  .hero-social {
    display: flex;
  }

  .hero-scroll {
    display: inline-flex;
    right: calc(var(--gutter) + var(--rail));
  }

  /* ── MASTHEAD: the drawer becomes a row ──────────────────────────────
     Everything that collapses the panel is written under `html.is-js` — in
     style.css (position:fixed, the 21rem width, the 6rem padding, the
     ink-deep ground, the left border, overflow-y, visibility:hidden and
     transform:translateX(100%)) and again in effects.css (opacity,
     visibility, translate, pointer-events). So everything that un-collapses
     it is written the same way: a bare .nav-panel would lose on specificity
     however late this file loads.

     The property list is deliberately a battery covering both sheets. If a
     single declaration survives to 1024 the desktop nav is either invisible
     or — worse — invisible and still focusable. */
  html.is-js .nav-toggle {
    display: none;
  }

  html.is-js .nav-panel,
  html.is-js .nav-panel.is-open {
    display: flex;
    flex-direction: row;
    align-items: center;
    position: static;
    inset: auto;
    inline-size: auto;
    min-inline-size: 0;
    max-inline-size: none;
    block-size: auto;
    min-block-size: 0;
    max-block-size: none;
    overflow: visible;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    clip-path: none;
    transform: none;
    translate: none;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
    backdrop-filter: none;
  }

  /* RESET, and this one matters with JavaScript OFF as much as on:
     style.css gives .nav and .nav-panel `flex: 1 0 100%`, so the no-JS menu
     takes a whole row of the masthead to itself under the wordmark. From
     here up it is a row item like any other. */
  .mast-inner {
    flex-wrap: nowrap;
    column-gap: var(--space-md);
  }

  .mast-inner > .nav,
  .mast-inner > .nav-panel {
    flex: 0 0 auto;
    inline-size: auto;
  }

  .nav {
    margin-inline-start: auto;    /* wordmark left, nav + CTA right */
  }

  .nav-cta {
    flex: 0 0 auto;
    margin-block-start: 0;        /* RESET: var(--space-sm) for the drawer */
  }

  /* Written twice so the html.is-js copy matches the (0,2,0) of
     `html.is-js .nav-list{gap:.35rem}` in style.css. That shorthand expands
     to both longhands at that specificity, and a bare .nav-list here would
     lose to it on the gap alone. */
  .nav-list,
  html.is-js .nav-list {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;              /* seven items can never widen the page */
    align-items: center;
    column-gap: var(--space-md);
    row-gap: 0;
  }

  /* Same reason: style.css blows the links up to --text-lg for the drawer.
     The opened padding keeps the target box over 44px without moving the
     is-current underline off the bottom of the text box. */
  .nav-link,
  html.is-js .nav-link {
    font-size: var(--text-sm);
    letter-spacing: .16em;
    padding-block: .85rem;
  }

  /* ── 03 · DESTINATIONS: opting into the pinned reel ───────────────────
     FIRST-TIMER #2, and the one place in this file where a default is taken
     AWAY rather than added to.

     Below this width — and at ANY width with JavaScript off, which is why
     every rule here is scoped to html.is-js — .dest-rail stays exactly what
     style.css made it: an overflow-x:auto, scroll-snap flex row. That is
     the behaviour that must survive, and it does: with JS off a 1920px
     desktop still gets a real, swipeable, keyboard-reachable scroller.

     Under html.is-js at 1024 the native scroller is switched off so
     animations.js can translate .dest-track instead. The rail is sized to
     max-content so the five cards lay out at their true width, and
     .dest-pin clips the inline axis so that width cannot reach the document
     and start the page rocking sideways. The block axis stays visible —
     `clip` beside `visible` is the one mixed pair CSS keeps as written — so
     the card hover lift and its gold key-line are not sheared off. */
  html.is-js .dest-pin {
    overflow-x: clip;
    overflow-y: visible;
    max-inline-size: 100%;
  }

  html.is-js .dest-rail {
    overflow: visible;
    scroll-snap-type: none;
    inline-size: max-content;
    max-inline-size: none;
  }

  html.is-js .dest-card {
    scroll-snap-align: none;
  }

  /* RESET, and it is load-bearing for the rule above: style.css sizes the
     cards `flex: 0 0 78%`. A percentage basis resolves against the flex
     container's inner main size, and a max-content rail has no definite one
     — the basis would fall back to content size and the five cards would
     come out at five unrelated widths. 78% of a phone is about 21rem, so
     this is the same card, stated as a length instead of a ratio. */
  .dest-card {
    flex-basis: 21rem;
  }

  /* ── 04 · videos: three-up ───────────────────────────────────────────
     auto-fit, because two pages share this grid: home has three cards and
     /videos has two. A fixed repeat(3, …) would leave /videos with a hole
     where a third card is not. RESET: the nth-child(3) full-row span §1
     gave the odd card while the grid was two-up. */
  .video-grid {
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    column-gap: var(--space-md);
  }

  .video-grid > .video-card:nth-child(3) {
    grid-column: auto;
  }

  /* /videos' lead film: the still beside its note. Six children — the
     eyebrow, the .video-media figure, the title, the say, the meta and the
     note — so the figure holds column one across the five rows the others
     take between them. */
  .videos--lead .container {
    display: grid;
    grid-template-areas: none;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    column-gap: var(--space-lg);
    align-items: center;
  }

  .videos--lead .container > * {
    grid-column: 2;
  }

  .videos--lead .container > .video-media {
    grid-column: 1;
    grid-row: 1 / span 5;
  }

  /* ── 05 · blog: the lead beside the cards ─────────────────────────────
     .blog-lead and .blog-cards are siblings inside .container, so the split
     is made on the container. It is matched with :has() rather than by page
     so that it applies to the homepage's blog block and skips /blog's
     .blog-cards--list, which is a full-width index and wants the whole
     measure. RESET: .blog-cards drops back to ONE column here — it is the
     narrow half of a split now, so §1's two-up and its nth-child(3) span
     would both be wrong inside it. */
  .blog .container:has(> .blog-cards:not(.blog-cards--list)) {
    display: grid;
    grid-template-areas: none;
    grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
    column-gap: var(--space-lg);
    row-gap: var(--space-lg);
    align-items: start;
  }

  .blog .container:has(> .blog-cards:not(.blog-cards--list)) > .blog-lead {
    max-inline-size: none;        /* the column is the measure now */
    margin-block-end: 0;
  }

  .blog-cards:not(.blog-cards--list) {
    grid-template-columns: minmax(0, 1fr);
  }

  .blog-cards:not(.blog-cards--list) > .post-card:nth-child(3) {
    grid-column: auto;
  }

  /* ── 06 · newsletter: the copy beside the form ────────────────────────
     Matched on :has(> .news-form) so /blog's .news--invite panel, which has
     no form in it, keeps its single measure instead of splitting into a
     column of orphans. */
  .news-inner:has(> .news-form) {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: var(--space-lg);
    align-items: center;
  }

  /* ── /about: all four numbers on one line ────────────────────────── */
  .stat-row {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  /* ── footer: four columns ────────────────────────────────────────── */
  .foot-cols {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}


/* ==========================================================================
   §4 · 1440px — LARGE DESKTOP
   Nothing new appears here. The gutter reaches its widest, the display type
   sits at the ceiling the frozen tokens already define, and the destination
   cards take the extra room.
   ========================================================================== */
@media (min-width: 1440px) {

  :root {
    --gutter: 4.5rem;

    /* THE CEILING. Every one of these clamps has already reached its own
       maximum before 1440 — 2.125rem at 1133px, 3.25rem at 1156, 4.5rem at
       1200, and 8.5rem at 1349 with §1's slope. Pinning them changes no
       rendered value; it states the top of the type scale in one place, as
       a fact rather than as the outcome of four clamp() sums. */
    --text-xl:   2.125rem;
    --text-2xl:  3.25rem;
    --text-3xl:  4.5rem;
    --text-hero: 8.5rem;
  }

  /* RESET of §3: the containers stop reserving room for the chapter rail.
     From here up the viewport margin outside --container (1280px) is at
     least 80px a side, wider than --rail's 52px on its own, so the rail
     already clears the content and the reservation would only push the page
     off its centre. The compass comes back to the gutter for the same
     reason. */
  body:has(.chapter-rail) .container:not(.mast-inner) {
    padding-inline-end: var(--gutter);
  }

  .hero-compass,
  .hero-scroll {
    right: var(--gutter);
  }

  /* The reel's cards gain width. flex-basis is what decides the size of a
     flex item, and the max-width RESET beside it is not optional: style.css
     caps .dest-card at 21rem, so without this line the wider basis would be
     clamped straight back and the cards would not grow at all. */
  .dest-card {
    flex-basis: 26rem;
    max-inline-size: 26rem;
  }

  /* The film stills get the extra room too, rather than the grid quietly
     adding a fourth track to a shelf that only ever holds three. */
  .video-grid {
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  }
}


/* ==========================================================================
   HAND-OFF NOTES — things this file cannot reach, for style.css (A11) and
   effects.css (A12). A min-width file has no way to say "below 480px", so
   every one of these is a base-size fix.

   1 · TOUCH TARGETS AT 360–479. Two controls are under 44px in style.css
       and are only raised from §1 up:
         .social-link   width/height 2.35rem = 37.6px
         .btn           .95rem padding on a line-height:1 box ≈ 43.4px
       Raising them at the base size would let §1's floor become the no-op
       it already is for .btn-icon and .to-top.

   2 · THE HERO'S BOTTOM ROW, at 360–1023. ⚠ The one real defect this file
       found and cannot fix.
       .hero is `display:flex; align-items:flex-end` with no wrap, and its
       in-flow children are .container, .hero-social and .hero-scroll —
       three items on ONE line. .hero-social is three flex:none 2.35rem
       links (~132px) and .hero-scroll is a tracked uppercase mono string
       plus a 2.75rem rule (~230px). At 360px those two take most of the
       line and .container — which carries the entire hero headline — is
       shrunk into what is left. .hero{overflow:hidden} keeps it off the
       document, so the page does not rock sideways; the headline is simply
       crushed and clipped. The row only genuinely fits from about 900px.
       Either fix works, and both are base-size, not breakpoint:
         (a) .hero{ flex-wrap: wrap; } + .hero > .container{ flex: 1 0 100%; },
             with padding-inline: var(--gutter) on .hero-social and
             .hero-scroll, since neither sits inside a .container; or
         (b) position .hero-social and .hero-scroll absolutely against .hero
             (which is already isolate + overflow:hidden), clear of the
             120px .seam along the bottom.
       §3 already sets flex-wrap:nowrap and a column-gap on .hero, so
       whichever is chosen the desktop composition — copy left, socials then
       the scroll cue bottom-right — comes back at 1024 unchanged. If (b) is
       chosen and either element is anchored to the INLINE-END edge, it
       needs calc(var(--gutter) + var(--rail)) from 1024 to 1439, exactly
       like .hero-compass in §3.

   3 · --grain-op is published as a token in §2 at .09, the doubling of
       effects.css's .045 that its own comment asks for. effects.css can
       read it — `.grain{ opacity: var(--grain-op, .045); }` — so the two
       sheets share one number instead of each holding a literal.

   4 · .dest-head, .dest-controls, .dest-foot and .hero-inner each carry
       max-width:var(--container) + margin-inline:auto + padding-inline:
       var(--gutter) of their own AND sit inside a .container on the
       homepage, so their gutter is applied twice there. Harmless at every
       width and left alone — but it is the reason §3's rail reservation is
       put on .container rather than on each of them.
   ========================================================================== */
