/* ═══════════════════════════════════════════════════════════════════════
   DRIFT — HOMEPAGE
   Sections 01–09 per DRIFT-Kinetic-Immersive-Design-Spec.md, Part B.
   Shared tokens, type, buttons, nav and footer live in site.css.
   ═══════════════════════════════════════════════════════════════════════ */

/* ═══ 01 · HERO ══════════════════════════════════════════════════════════ */
/* 200vh, so the pinned range is one screen of scroll rather than 1.6. The
   crossfade windows in home.js §04 are fractions of that range, so the two
   numbers move together — see the note there before changing either. */
.hero{position:relative;height:200vh}
/* NB: a sticky element taller than the viewport does not stick. Never give
   .pin a min-height — it must always equal the viewport exactly. */
.hero .pin{position:sticky;top:0;height:100svh;overflow:hidden}
/* Top-down aerial: already deep, rich blue — the opposite problem to the
   flat overcast clip this replaced. It needs a light touch, not rescuing.
   Heavy saturation/brightness lifts would only crush the water texture.
   Origin sits on the vessel (bottom centre) so the push-in reads as the
   camera closing on the boat while the ocean opens out around it. */
.hero video,.hero .heroimg{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;
  transform-origin:50% 88%;will-change:transform;
  filter:saturate(1.12) contrast(1.06) brightness(1.02);
}
/* ── THE HANDOVER ──────────────────────────────────────────────────────
   .is-held is set by home.js §01b when the pass has played out.

   This was a straight 2.2s cross-fade from the video to the still, and it
   read as a jarring cut with a soft edge. The reason is the two pictures,
   not the timing: the last frame is a top-down of near-black water with two
   bright vertical wakes and no horizon, and the still is an eye-level
   golden-hour shot that is half sky. They share no shape, no horizon line
   and no colour temperature, so dissolving one through the other just ghosts
   two unrelated images together. Lengthening it makes it worse.

   So they never share the screen. The picture dips through the section's own
   ground colour and the swap happens underneath, which is what an editor
   does with two shots that will not cut together. The dip clears to reveal
   the still already in place.

   Timings interlock and must stay that way. Over 2.4s the dip is fully
   opaque from 40% to 55% — 960ms to 1320ms — and the still is brought up
   inside that window, starting at 1000ms and finishing at 1200ms. That
   leaves 40ms of cover before the swap starts and 120ms after it ends.
   Shorten the hold, delay the swap, or lengthen it, and the video peeks
   through the instant the dip begins to clear.

   The swap's own 200ms is cosmetic — it happens under an opaque layer. The
   duration that matters is that it FINISHES before 1320ms.

   The dip sits above both scrims but below the copy, so the headline holds
   while the shot changes behind it. */
.hero .heroimg{opacity:0;z-index:0;transition:opacity .2s linear 1s}
.hero.is-held .heroimg{opacity:1}
.hero .dip{position:absolute;inset:0;z-index:3;background:var(--abyss);
  opacity:0;pointer-events:none;will-change:opacity}
.hero.is-held .dip{animation:heroDip 2.4s var(--ease-inout) forwards}
@keyframes heroDip{0%{opacity:0}40%{opacity:1}55%{opacity:1}100%{opacity:0}}
/* barely-there wash — the footage is already on-palette, so this only
   unifies it with the section below rather than recolouring it */
.hero .tint{position:absolute;inset:0;z-index:1;mix-blend-mode:soft-light;
  background:linear-gradient(180deg,#6FBDF5 0%,#2A7FCB 55%,#0E3E64 100%);opacity:.24}
/* Three stacked scrims. The footage is bright daylight, so a single radial
   is not enough: the radial seats the centre, the vertical protects the nav
   and the scroll cue, and the flat tint holds overall contrast for the type. */
/* Much lighter than the version tuned for bright overcast footage: this
   clip is already dark, so a heavy centre ellipse would flatten the water
   to black. The type is carried by its shadow instead. */
.hero .scrim{position:absolute;inset:0;z-index:2;
  background:
    linear-gradient(180deg,rgba(var(--abyss-rgb),.72) 0%,rgba(var(--abyss-rgb),.06) 24%,
                    rgba(var(--abyss-rgb),.06) 72%,rgba(var(--abyss-rgb),.78) 100%),
    radial-gradient(70% 56% at 50% 44%,rgba(var(--abyss-rgb),.60),rgba(var(--abyss-rgb),0) 80%)}

/* The footage moves, so no fixed scrim can guarantee contrast on every
   frame. A soft shadow on the hero type does, and is invisible when the
   frame behind is already dark. */
.hero h1,.hero h2.d2{text-shadow:0 2px 40px rgba(var(--abyss-rgb),.85),0 1px 8px rgba(var(--abyss-rgb),.5)}
/* ── A SHORT WINDOW ────────────────────────────────────────────────────
   Every size in this hero was a vw term, so the type had no idea the window
   was short — and phase B is the tallest block on the site: a four-line
   headline, two sub-lines and a button.

   On a laptop that block did not fit the pin. At 1440x700 it measured 634px
   against 623px of room, so it was clamped hard to the top: "Investment
   open" sat wholly behind the fixed nav and the headline's first line butted
   into it. By 1280x600 the button was below the fold — and the pin holds for
   the whole 200vh range, so there was no scrolling to it.

   Fixed with a height ceiling on each headline rather than a breakpoint,
   because a breakpoint would drop the type a whole step in one pixel of
   resize. 9vh and 21vh are both set just under where each headline tops out
   on a tall window: at 900px the vw term is still the smaller of the two and
   nothing changes, and below that the type comes down in step with the room
   it has. The margins between the four parts do the same, further down. */
.hero .layer.b h2.d2{font-size:min(clamp(2.2rem,5.8vw,4.9rem),9vh)}
.hero .layer.a h1.d1{font-size:min(clamp(2.9rem,10.5vw,9.5rem),21vh)}
.hero .sub{text-shadow:0 1px 18px rgba(var(--abyss-rgb),.95),0 1px 4px rgba(var(--abyss-rgb),.7)}
.hero .sub{color:#fff}
.hero .dark{position:absolute;inset:0;z-index:3;background:var(--abyss);opacity:0;will-change:opacity}
/* padding-bottom lifts the centred copy off the vessel, which sits bottom
   centre in this shot — otherwise the sub-line lands across its sails.
   padding-top is the nav: the header is fixed over the top of the pin, so
   without it the copy centres in a box whose top quarter the reader cannot
   see. See A SHORT WINDOW above for what that costs on a laptop. */
.hero .layer{position:absolute;inset:0;z-index:4;display:grid;place-items:center;
  text-align:center;
  padding:clamp(62px,8vh,76px) clamp(20px,5vw,40px) clamp(60px,11vh,130px);
  will-change:transform,opacity,filter}
.hero .layer .box{max-width:min(1120px,92vw)}
.hero .layer.b{opacity:0}
.hero .layer.b .box{max-width:min(1060px,92vw)}
/* Phase B's sub-line is a good deal longer than phase A's, and at the shared
   40ch measure it stacked five centred lines under an already four-line
   headline. Wider measure, same type. */
.hero .layer.b .sub{max-width:54ch}
/* The quoted line is a second sub under the first, so it takes a tighter
   margin than the headline-to-sub step above it. */
.hero .sub.quoted{margin-top:clamp(10px,1.7vh,16px);font-style:italic;color:#fff}
.hero .sub{margin:clamp(20px,3.4vh,30px) auto 0;max-width:40ch;color:var(--mist)}
.hero .heroctas{margin-top:clamp(24px,4.3vh,38px);display:flex;gap:14px;justify-content:center;flex-wrap:wrap}
.pulse-dot{width:7px;height:7px;border-radius:50%;background:var(--charge);flex:none;
  animation:pulse 2.4s var(--ease-out) infinite}
@keyframes pulse{0%,100%{opacity:1;box-shadow:0 0 0 0 rgba(78,240,196,.5)}
  50%{opacity:.55;box-shadow:0 0 0 7px rgba(78,240,196,0)}}
.scrollcue{position:absolute;left:50%;bottom:26px;transform:translateX(-50%);z-index:5;
  font-family:var(--sans);font-weight:600;font-size:.62rem;letter-spacing:.26em;text-transform:uppercase;
  opacity:.7;display:flex;flex-direction:column;align-items:center;gap:10px}
.scrollcue i{width:1px;height:42px;background:linear-gradient(#fff,transparent);
  animation:drop 2.2s var(--ease-out) infinite}
@keyframes drop{0%{transform:scaleY(0);transform-origin:top}
  45%{transform:scaleY(1);transform-origin:top}
  55%{transform:scaleY(1);transform-origin:bottom}
  100%{transform:scaleY(0);transform-origin:bottom}}

/* ═══ 02 · VALIDATION RAIL ═══════════════════════════════════════════════
   This band is the first proof point after the hero, so it has to carry.
   v1.3 undersold it: 22px logos at 40% opacity and body copy tracked out
   to .1em, which read as a technical footnote rather than a claim. */
.rail{position:relative;border-bottom:1px solid var(--line);padding:0;
  background:linear-gradient(180deg,var(--deck) 0%,var(--hull) 62%,var(--hull) 100%)}
/* accent hairline — the band announces itself instead of blending in */
.rail::before{content:"";position:absolute;inset:0 0 auto 0;height:2px;
  background:linear-gradient(90deg,transparent,var(--current) 22%,
             var(--charge) 50%,var(--current) 78%,transparent);opacity:.85}

.rail .wrap{display:grid;grid-template-columns:auto 1fr;gap:clamp(28px,4vw,64px);
  align-items:center;padding:clamp(26px,3.4vw,38px) 0}

/* the RINA claim, as a badge rather than a sentence */
.rail .claim{display:flex;align-items:center;gap:22px;padding:22px 26px;
  border:1px solid var(--line-signal);border-radius:var(--r-md);
  background:linear-gradient(105deg,rgba(59,123,255,.16),rgba(59,123,255,.03))}
.rail .claim img{height:54px;width:auto;flex:none}
.rail .claim .t{font-size:1.06rem;font-weight:500;letter-spacing:-.022em;line-height:1.32;
  color:var(--white);max-width:20ch}
.rail .claim .t b{display:block;font-size:.64rem;font-weight:600;letter-spacing:.2em;
  text-transform:uppercase;color:var(--charge);margin-bottom:8px}

/* Two labelled rows. Vertical labels were unreadable and gimmicky; a fixed
   label column lets both rows align and scan in one pass. */
.rail .groups{display:flex;flex-direction:column;gap:26px}
.rail .grp{display:flex;align-items:center;gap:clamp(18px,2.2vw,34px);flex-wrap:wrap}
/* Both rows span the same measure and justify to both edges, so the three
   investors line up with the first and last of the five below them rather
   than bunching left against a row half again as wide. */
.rail .grp .lgs{flex:1;display:flex;align-items:center;justify-content:space-between;
  gap:clamp(18px,2.2vw,34px);flex-wrap:wrap}
/* 128px keeps "RECOGNISED BY" on one line at .18em tracking */
.rail .grp .lab{font-size:.6rem;font-weight:600;letter-spacing:.18em;text-transform:uppercase;
  color:var(--fog);width:128px;flex:none;line-height:1.4}
.rail .grp img{width:auto;transition:transform var(--t-fast)}
.rail .grp.inv img{height:30px}
.rail .grp.rec img{height:34px}
.rail .grp img:hover{transform:translateY(-2px)}

@media(max-width:1180px){
  .rail .wrap{grid-template-columns:1fr;gap:28px}
  .rail .claim{align-self:start;max-width:480px}   /* don't stretch full width */
}
@media(max-width:640px){
  .rail .grp{gap:16px}
  .rail .grp .lab{width:100%}
  /* one column: space-between would strand the last wrapped row */
  .rail .grp .lgs{gap:16px;justify-content:flex-start}
  .rail .grp.inv img{height:24px}
  .rail .grp.rec img{height:27px}
}

/* ═══ 04 · THE VISION ════════════════════════════════════════════════════ */
/* ── §04 CHAPTER OPENER ────────────────────────────────────────────────
   Three lines of type opening the three movements. It was a single stacked
   column in a full-width wrap, which on a wide screen left ~700px of empty
   column beside the standfirst and spent 264px of a 596px section on
   padding alone — so it read as a stranded paragraph rather than a title.

   Two columns now, headline against standfirst, bottom-aligned so the last
   line of the small type sits on the baseline of the big — an editorial
   spread instead of a stack. Padding roughly halved, because the space was
   doing nothing that the two-column split does not now do better. */
/* Padding roughly doubled again, and the headline given its own size above
   .d2. At the old scale this chapter title was shorter than the movement
   section under it was padded, so the two ran together and read as one
   badly-spaced module rather than as an opener and the first movement. A
   chapter title has to be able to hold the screen on its own. */
/* Top padding halved from 15vh — see the note on .hiw's bottom edge, which
   is the other half of this gap. The opener still holds the screen: what it
   needs for that is the room BELOW its standfirst before the first movement
   starts, and that is set by .macro-open + .movement further down, not by
   how far the eyebrow sits from the section that ended above it. */
.macro-open{position:relative;overflow:hidden;
  padding:clamp(56px,8.5vh,100px) 0 clamp(30px,4vh,54px)}
.macro-open h2{font-size:clamp(2.5rem,6.6vw,5.9rem);letter-spacing:-.04em}
.macro-open .wrap{position:relative;z-index:1;display:grid;
  grid-template-columns:1.3fr .7fr;column-gap:clamp(36px,4.5vw,80px);
  align-items:end}
.macro-open .lede{color:var(--mist);max-width:42ch;margin-top:0}
@media(max-width:900px){
  .macro-open .wrap{grid-template-columns:1fr}
  .macro-open .lede{margin-top:26px;max-width:52ch}
}

/* ═══ 04 · THE MOVEMENTS ═════════════════════════════════════════════════
   Formerly one pinned screen scrubbed sideways (.hscroll/.htrack). Ordinary
   sections now: each can be linked to, scrolled back into, and read at the
   reader's own pace, and the globe no longer has to share a viewport with
   anything else. There were three; the third — "No cable. No seabed." —
   was cut as a restatement of the hero and of §06. */
.movement{position:relative;min-height:clamp(560px,86vh,900px);display:flex;align-items:center;
  overflow:hidden;padding:clamp(80px,12vh,140px) 0}
/* The first movement is the continuation of the chapter opener above it, not
   a new arrival: no gap between them, and its own top padding does the
   spacing that two sets of section padding used to do twice over. */
.macro-open + .movement{margin-top:0;padding-top:clamp(40px,7vh,96px)}
.movement>img{position:absolute;left:0;top:-8%;width:100%;height:116%;object-fit:cover;z-index:0;
  will-change:transform}
/* The top of this gradient used to open at .60, so the photograph was
   already half-visible at the section's first pixel and met the flat ground
   above it on a hard horizontal line — which is what made a chapter opener
   and its first movement read as two unrelated modules. It starts fully
   opaque now and clears by a fifth of the way down: the image emerges out of
   the same colour the section above ends on, and there is no seam to see. */
.movement .g{position:absolute;inset:0;z-index:1;
  background:
    linear-gradient(90deg,rgba(var(--abyss-rgb),.90) 0%,rgba(var(--abyss-rgb),.64) 46%,rgba(var(--abyss-rgb),.14) 100%),
    linear-gradient(180deg,
      rgba(var(--abyss-rgb),1) 0%,
      rgba(var(--abyss-rgb),.86) 7%,
      rgba(var(--abyss-rgb),.34) 20%,
      rgba(var(--abyss-rgb),.08) 40%,
      rgba(var(--abyss-rgb),.82) 100%)}
.movement .c{position:relative;z-index:2;max-width:680px}
.movement h2{margin-bottom:22px}
.movement p{color:var(--mist)}

/* Fleet financing. A rule above and an eyebrow, which is how the rest of
   this section separates things — it was a bordered, backdrop-blurred card, the
   only piece of chrome on a full-bleed image with no boxes anywhere else in
   it, and it read as an advert dropped into the page. */
/* 620 rather than the 680 text column: it lines up with the roadmap directly
   above it, so the rule, the rail and the statement share one right edge. */
.fundnote{margin-top:clamp(28px,4vh,44px);padding-top:clamp(18px,2.4vh,26px);
  border-top:1px solid var(--line-strong);max-width:620px}
.fundnote .fn-head{display:flex;align-items:center;justify-content:space-between;
  gap:20px;flex-wrap:wrap;margin-bottom:12px}
.fundnote .eyebrow{margin-bottom:0}
/* brightness(0) flattens the mark to black whatever it arrives as, invert
   takes it to white — so a black-on-transparent or a white-on-transparent
   file both come out correct on this background. */
.fundnote .fn-logo{height:clamp(26px,3vw,34px);width:auto;flex:none;
  filter:brightness(0) invert(1);opacity:.88}
/* Subordinate to the lede above it, not a rival to it. At white and
   clamp(1rem,1.3vw,1.1rem) this was within a hair of the section's own
   standfirst, so the column read as two headline statements stacked — and
   the note is an annotation to the roadmap, not a second argument. */
.fundnote .fn-say{color:var(--mist);max-width:none;
  font-size:clamp(.94rem,1.05vw,1.01rem);line-height:1.5}
/* Coloured, not dimmed: this is the correction to the announcement, and the
   one line on the block a reader must not skim past. */
.fundnote .fn-when{margin-top:11px;max-width:none;color:var(--current-lift);
  font-size:.93rem;line-height:1.45}
.fundnote .fn-links{display:flex;flex-wrap:wrap;gap:9px 26px;margin-top:15px}
.fundnote .tlink{font-size:.89rem}

/* An ordered roadmap, not a progress meter. The four bars this replaces were
   filled from scroll position, which made a scroll animation look like a
   status claim — see the note in index.njk §04a. Nothing here is driven by
   scroll and nothing reports a percentage; the connectors fade along the
   sequence so it still reads as a direction of travel.

   The track is drawn per stop rather than as one line across the container,
   so it always ends ON the last node. A single container line has to guess
   where that node is, which holds only while every stop is the same size —
   and it stops being true the moment the rail goes vertical. */
.phaserail{position:relative;margin-top:clamp(30px,4.4vh,44px);max-width:620px;
  list-style:none;display:grid;grid-template-columns:repeat(3,1fr)}
.phaserail .stop{position:relative;padding:22px 18px 0 0}
.phaserail .stop::before{content:"";position:absolute;left:0;top:0;width:11px;height:11px;
  border-radius:50%;box-sizing:border-box;
  border:1px solid var(--current-lift);background:var(--abyss)}
.phaserail .stop::after{content:"";position:absolute;left:12px;right:-5px;top:5px;height:1px;
  background:linear-gradient(90deg,var(--current-lift),rgba(255,255,255,.30))}
.phaserail .stop:nth-child(2)::after{
  background:linear-gradient(90deg,rgba(255,255,255,.30),rgba(255,255,255,.13))}
.phaserail .stop:last-child::after{display:none}
.phaserail .pn{display:block;font-family:var(--instrument);font-size:.56rem;font-weight:400;
  letter-spacing:.2em;color:var(--current-lift);margin-bottom:7px}
.phaserail .lab{display:block;font-size:.98rem;line-height:1.3;color:var(--mist);max-width:16ch}
@media(max-width:620px){
  .phaserail{grid-template-columns:1fr;max-width:none}
  .phaserail .stop{padding:0 0 22px 26px}
  .phaserail .stop:last-child{padding-bottom:0}
  .phaserail .stop::after{left:5px;right:auto;top:12px;bottom:-1px;width:1px;height:auto;
    background:linear-gradient(180deg,var(--current-lift),rgba(255,255,255,.30))}
  .phaserail .stop:nth-child(2)::after{
    background:linear-gradient(180deg,rgba(255,255,255,.30),rgba(255,255,255,.13))}
  .phaserail .lab{max-width:none}
}

/* ── MISSION CONTROL — one panel ───────────────────────────────────────
   This was a pinned sequence: five beats of copy scrolled past a sticky
   globe and each beat directed it — the camera settled on a target, the
   emphasis moved from the wind field to the control links to a single hull
   running for a quay, and the row of the readout that beat was talking
   about lit up. The scene was ONE grid cell with two children stacked in
   it, so the stage could have the full width of the section while a narrow
   column of copy floated over the empty ocean beside it.

   It is a two-column panel again: copy left, globe right, nothing pinned
   and nothing driven by scroll position. Everything the old layout was
   working around went with the sequence — the sticky stage, the overlap,
   the pointer-events dance that kept the copy selectable through the
   stage, and the height budget that sized the disc against a readout that
   no longer exists. The disc is now sized by its column, which is one
   number instead of four.

   Camera: home.js § 04b. */
.mission{position:relative;background:var(--schematic);isolation:isolate;
  padding-block:clamp(96px,16vh,190px)}
.mission::before{content:"";position:absolute;inset:0;z-index:0;
  background:var(--grid-schematic)}
/* the light the scene is lit by — a cold sun behind the globe, and enough
   fall-off at the top and bottom edges that the panel arrives out of the
   section above it rather than starting on a hard seam */
.mission::after{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(90% 62% at 72% 44%,rgba(96,178,255,.22),transparent 62%),
    linear-gradient(180deg,var(--abyss),transparent 12% 88%,var(--abyss))}

/* The copy takes the narrower column: it is one block of prose at ~46ch and
   giving it half the section would run the measure past readable, while the
   globe is a disc and every pixel of its column becomes diameter. */
.scene{position:relative;z-index:1;display:grid;
  grid-template-columns:minmax(0,.82fr) minmax(0,1fr);
  gap:clamp(36px,6vw,96px);align-items:center;
  width:min(1400px,92vw);margin-inline:auto}

/* ── THE COPY ──────────────────────────────────────────────────────────
   No .beat dimming, no [data-story] fail-safe and no chapter rail: there
   is one block, it is always the one being read, and it fills off the
   shared reveal like every other block of copy on the page. */
.brief h2{margin-bottom:22px}
.brief p{color:var(--mist);max-width:46ch}
.brief .lede{margin-bottom:18px}
/* ── THE STAGE ─────────────────────────────────────────────────────────
   A plain column now. The disc is square and sized by the column it is in,
   with a viewport ceiling so a wide window cannot push it taller than the
   screen. */
.stage{position:relative;display:grid;justify-items:center;gap:18px}
.stage-inner{width:min(100%,78svh,700px);aspect-ratio:1;position:relative}

/* ── THE GLOBE ─────────────────────────────────────────────────────────
   A live flotilla on canvas: the wind field, the hulls riding it, and the
   deliveries running into port are all simulated, not drawn. It reads as an
   instrument, and it carries the argument the copy beside it is making.
   See home.js § 04b. */
.globe-stage{position:relative;width:100%;height:100%}
.globe-stage canvas{width:100%;height:100%;display:block;cursor:grab;
  /* A vertical swipe stays the PAGE's — the canvas is full width on a phone
     and a globe that swallows it leaves the reader unable to scroll past the
     section at all. Horizontal is the globe's, and zoom is on the buttons. */
  touch-action:pan-y;border-radius:50%}
.globe-stage canvas:focus-visible{outline:2px solid var(--current-lift);
  outline-offset:6px;border-radius:50%}

/* ── THE CONTROLS ──────────────────────────────────────────────────────
   Zoom in, zoom out, fly to the next flotilla, and hand the camera back to
   the sequence. Real buttons, so the globe is fully drivable from the
   keyboard — the drag and the wheel are the shortcut, not the interface. */
.gctl{position:absolute;top:2%;right:0;z-index:4;display:grid;gap:7px;
  pointer-events:auto}
.gctl button{width:34px;height:34px;display:grid;place-items:center;cursor:pointer;
  border:1px solid var(--line-signal);border-radius:10px;
  background:rgba(var(--abyss-rgb),.66);backdrop-filter:blur(8px);
  color:var(--sky);transition:background var(--t-fast),color var(--t-fast),
                              border-color var(--t-fast),transform var(--t-fast)}
.gctl button:hover{background:rgba(62,140,255,.26);color:#fff;transform:translateY(-1px)}
.gctl button:focus-visible{outline:2px solid var(--current-lift);outline-offset:2px}
.gctl svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.5;
  stroke-linecap:round;stroke-linejoin:round}
/* once the reader has the camera, Reset is the way back — say so */
.globe-stage.manual .gctl [data-g="reset"]{border-color:var(--current-lift);
  color:var(--current-lift);background:rgba(62,140,255,.2)}

.ghint{position:absolute;left:50%;bottom:-22px;translate:-50% 0;z-index:4;
  max-width:min(94%,44ch);text-align:center;pointer-events:none;
  font-family:var(--instrument);font-size:.5rem;letter-spacing:.13em;
  text-transform:uppercase;color:rgba(182,220,251,.6);line-height:1.5;
  transition:opacity var(--t-base)}
.globe-stage.manual .ghint{opacity:0}
/* On a narrow screen the globe is ~255px and the hint wraps to two lines
   that land on the disc itself. Taken out of the picture and left to the
   screen reader (the canvas still points at it with aria-describedby): a
   touch reader discovers the drag by dragging, and zoom is on the buttons
   either way. */
@media(max-width:820px){
  .ghint{position:absolute;width:1px;height:1px;overflow:hidden;
    clip:rect(0 0 0 0);white-space:nowrap;bottom:auto;left:0;translate:none}
  .gctl{gap:6px}
  .gctl button{width:30px;height:30px;border-radius:9px}
  .gctl svg{width:13px;height:13px}
}

/* instrument framing — corner ticks + crosshair.
   A fixed inset, not -6%: as a percentage the brackets grew with the globe
   and ate the gap below it. */
.gframe{position:absolute;inset:-18px;pointer-events:none}
.gframe span{position:absolute;width:16px;height:16px;border:1px solid rgba(156,201,245,.42)}
.gframe span:nth-child(1){top:0;left:0;border-right:0;border-bottom:0}
.gframe span:nth-child(2){top:0;right:0;border-left:0;border-bottom:0}
.gframe span:nth-child(3){bottom:0;left:0;border-right:0;border-top:0}
.gframe span:nth-child(4){bottom:0;right:0;border-left:0;border-top:0}
.gframe .tick{position:absolute;left:50%;translate:-50% 0;font-family:var(--instrument);
  font-size:.52rem;letter-spacing:.2em;color:rgba(156,201,245,.55);width:auto;height:auto;border:0;
  white-space:nowrap}
.gframe .tick.t{top:-15px}

/* ── THE LEGEND ────────────────────────────────────────────────────────
   Four things are drawn on the disc in four colours. This used to be the
   last row of the readout panel; with the readout gone it is its own strip
   under the globe, because nothing else on the page says which is which. */
.glegend{display:flex;flex-wrap:wrap;justify-content:center;gap:8px 26px;
  font-family:var(--instrument);font-size:.52rem;letter-spacing:.11em;
  color:var(--fog);text-transform:uppercase}
.glegend span{display:flex;align-items:center;gap:7px}
.glegend i{display:inline-block;width:7px;height:7px;border-radius:50%;flex:none}
.glegend .g1 i{background:var(--charge)}
/* amber, keyed to the port pins and to the delivery arcs that run into them */
.glegend .g2 i{background:var(--warn)}
/* the wind is drawn as streaks, not points, so the swatch is a streak;
   the control link is a dashed run, so its swatch is a dashed rule */
.glegend .g3 i{width:16px;height:2px;border-radius:1px;background:rgba(190,225,255,.85)}
.glegend .g4 i{width:16px;height:0;border-radius:0;border-top:1px dashed var(--charge)}

/* The disc is a simulation, not a plot of where the fleet actually is. It
   sits under the legend rather than in it, quieter than the four swatches
   so it reads as a caveat on the whole picture and not a fifth thing drawn
   on it.

   Quieter, though — not unreadable. Set at the legend's .52rem and 42%
   this was 2.7:1 on the schematic panel, well under AA at a size no
   reader would squint at anyway, and it is the one line stopping the
   globe from being taken for a live fleet tracker. At .64rem and 70% it
   measures 4.7:1, which clears AA and still sits just under the legend's
   own 5.05:1 — so the hierarchy the paragraph above describes survives.
   Do not take the contrast back down without also taking the claim off
   the disc. */
.gnote{margin-top:14px;text-align:center;font-family:var(--instrument);
  font-size:.64rem;letter-spacing:.11em;text-transform:uppercase;
  color:rgba(156,201,245,.7)}

.pullstat .n{font-family:var(--mono);font-size:clamp(2.6rem,5.4vw,4.2rem);font-weight:500;
  line-height:1;letter-spacing:-.045em;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.pullstat .n .chip{font-size:.5rem}
.pullstat .l{color:var(--mist);font-size:.85rem;margin-top:12px;max-width:34ch}

/* ── STACKED ───────────────────────────────────────────────────────────
   Under 960px the copy takes the top and the globe runs underneath it.

   This block used to be considerably longer, and every extra line of it was
   arithmetic for two things that are gone. The stage pinned, so it needed
   an opaque full-bleed backdrop to stop the copy scrolling visibly under
   the disc, and a clip to stop that bleed widening the page; and the disc
   was sized out of a height BUDGET — `min(100svh, max(430px, 60svh))` less
   232px of readout — so that the instrument below it always had room.

   Nothing pins and there is no readout, so the disc is simply as wide as
   its column allows, capped so it cannot outgrow a short screen. */
@media(max-width:960px){
  .scene{grid-template-columns:minmax(0,1fr);gap:clamp(30px,5vh,52px)}
  .brief p{max-width:none}
  .stage-inner{width:min(100%,72svh)}
  .gframe{inset:-12px}
}
@media(max-width:600px){
  /* The corner brackets sit 12px outside the disc and the tick above them;
     at this width the disc is the full column, so pull them in or they
     print on the section's own gutter. */
  .gframe{inset:-9px}
  .glegend{gap:6px 16px;font-size:.48rem}
}

/* ── A SHORT WINDOW ────────────────────────────────────────────────────
   Wide but short — 2000x570 is an ordinary maximised laptop with the dock
   showing — is the case the width terms get wrong on their own: they offer
   the disc its full 700px while the window has nowhere to put it.

   The 78svh ceiling in .stage-inner already handles the sizing. What is
   left is the hint, which sits 22px under the disc and is the first thing
   to collide with the fold; it goes to the screen reader, exactly as it
   already does on a narrow screen and for the same reason. */
@media(min-width:961px) and (max-height:780px){
  .ghint{position:absolute;width:1px;height:1px;overflow:hidden;
    clip:rect(0 0 0 0);white-space:nowrap;bottom:auto;left:0;translate:none}
}


/* ═══ 05 · HOW IT WORKS ══════════════════════════════════════════════════ */
/* The padding is asymmetric and both halves are smaller than the 16vh they
   were, because neither edge of this section pays for its own gap alone.

   TOP: the film above it ends on 9vh of its own padding, so 16vh here made
   a 272px trench between "Read the full technology breakdown" and this
   section's eyebrow (measured at 1512x950). The two paddings are one gap —
   9vh + 9vh reads as the deliberate beat between two chapters, 9 + 16 reads
   as the page having lost its place.

   BOTTOM: same doubling at the other end, and worse — the closing line
   already floats in 15vh of .hiw-close padding above it, and then this and
   §04's opener stacked another 294px under it. 10vh here against 8.5vh
   there brings that back to about 176px, level with the top gap, so the two
   chapter breaks on this page are the same size. Both flagged in review:
   "reduce gap", then "same here". */
.hiw{background:var(--schematic);position:relative;
  padding:clamp(60px,9vh,110px) 0 clamp(64px,10vh,120px)}
.hiw::before{content:"";position:absolute;inset:0;background:var(--grid-schematic);
  z-index:0;pointer-events:none}
.hiw .wrap{position:relative;z-index:1}
.hiw-head{display:flex;justify-content:space-between;align-items:flex-end;gap:30px;
  margin-bottom:48px;flex-wrap:wrap}

/* ═══ 03c · THE SHIP, ANNOTATED ══════════════════════════════════════════
   Overview diagram at the top of How it works: the render on the left, four
   keys on the right, and numbered markers on the hull tying the two together.
   Marker positions are percentages of the image box, so they track it at
   every width — the image is object-fit:contain inside a fixed aspect box,
   which is what makes that true. */
.shipmap{position:relative;display:grid;grid-template-columns:1.15fr .85fr;
  gap:clamp(24px,4vw,60px);align-items:center;
  margin:clamp(30px,4.6vh,52px) 0 clamp(38px,5.6vh,66px)}
/* THE BOX MUST BE THE PICTURE. This was width:100% + max-height, which at
   most viewports produced a box WIDER than the render's 1240/1336 — 633x560
   against an image that paints 520x560 inside it. object-fit:contain then
   letterboxed the vessel with ~57px of empty space each side, and since the
   markers below are positioned as a percentage of the BOX, every one of them
   sat off the part of the hull it names. Worse, that letterbox is a function
   of the column width, so the markers drifted as the window resized.

   Driving the width from the height instead makes the box exactly the
   painted image at every width, which is what lets the marker percentages be
   read straight off the render. max-width keeps it inside a narrow column;
   aspect-ratio then trades height back so the two never disagree. */
.shipmap .ship{position:relative;aspect-ratio:1240/1336;
  height:min(58vh,560px);width:auto;max-width:100%;margin-inline:auto}
.shipmap img{width:100%;height:100%;object-fit:contain;display:block}

/* The markers. Coordinates are read off the render: the forward wing-sail,
   the water turbine under the counter, the hull amidships, and the after
   deck. */
.shipmap .mk{position:absolute;translate:-50% -50%;width:30px;height:30px;
  border-radius:50%;border:1px solid var(--current-lift);
  background:rgba(var(--abyss-rgb),.42);backdrop-filter:blur(2px);
  display:grid;place-items:center}
.shipmap .mk i{font-family:var(--instrument);font-style:normal;font-size:.56rem;
  letter-spacing:.08em;color:var(--current-lift)}
/* Marker positions, as percentages of the render. These are ANATOMICAL —
   each one has to land on the part of the vessel its key names, so they were
   set against the alpha silhouette of mvy-profile-alpha.webp rather than by
   eye. In that file: the forward sail spans x 32–53%, the aft sail x 75–98%,
   the hull band y 77–86%, the main foil x 42–48% descending to y 100%, and
   the stern rudder-and-turbine x 74–79% at y 88–92%.

   Matching the original diagram: Capture is on the AFT sail (it was on the
   forward one), Store is mid-hull by the ③, and Scale is forward at the bow
   — Store and Scale had been the other way round. Move one and check it
   still sits on its own subject; 02 in particular was at top:92%, which is
   just past the tip of the turbine and left it floating in open water. */
.shipmap .m1{left:86%;top:30%}    /* Capture — aft sail, mid-height        */
.shipmap .m2{left:76.5%;top:89.5%}/* Convert — stern rudder/turbine        */
.shipmap .m3{left:54%;top:81.5%}  /* Store   — mid-hull, just aft of the ③ */
.shipmap .m4{left:20%;top:81.5%}  /* Scale   — hull, forward               */
/* One pulse ring per marker, so the eye is taken to the hull rather than
   left to find four small circles on a large render. */
.shipmap .mk::after{content:"";position:absolute;inset:-1px;border-radius:50%;
  border:1px solid var(--current-lift);animation:mkpulse 3.4s var(--ease-out) infinite}
.shipmap .m2::after{animation-delay:.4s}
.shipmap .m3::after{animation-delay:.8s}
.shipmap .m4::after{animation-delay:1.2s}
@keyframes mkpulse{0%{opacity:.55;scale:1}70%,100%{opacity:0;scale:1.85}}

.shipkeys{display:grid;gap:clamp(16px,2.4vh,26px)}
.shipkeys .key{display:grid;grid-template-columns:auto 1fr;column-gap:12px;
  align-items:baseline}
.shipkeys .n{font-family:var(--instrument);font-size:.56rem;letter-spacing:.2em;
  color:var(--current-lift)}
.shipkeys b{font-size:clamp(1.15rem,1.7vw,1.42rem);font-weight:500;letter-spacing:-.02em;
  color:var(--white)}
.shipkeys p{grid-column:2;margin-top:5px;max-width:34ch;color:var(--mist);
  font-size:.97rem;line-height:1.45}

/* Connector arrows. Geometry comes from home.js §05c; everything about how
   they look is here. They draw themselves on as their step arrives, which is
   what makes the sequence read as four deliberate steps rather than four
   things fading up in the same place. */
.shiplines{position:absolute;inset:0;width:100%;height:100%;
  pointer-events:none;overflow:visible;color:var(--current-lift);z-index:2}
.shiplines .sl{fill:none;stroke:var(--current-lift);stroke-width:1;
  marker-end:url(#shiparrow);stroke-dashoffset:var(--len);
  transition:stroke-dashoffset 620ms var(--ease-out);opacity:.85}
.shiplines .sl.on{stroke-dashoffset:0}

/* Sequenced arrival, 01 → 04, driven by the figure's travel up the viewport
   (home.js §05c). .seq is added by that script and is the only thing that
   hides anything — no JS, no .seq, and every marker and key is visible.

   The steps are deliberately staged rather than simultaneous: the marker
   lands first with a snap, the arrow draws toward it, and the key rises in
   behind. Reading the delays as one gesture is the point — a step you can
   see happen, not a crossfade. */
.shipmap.seq .mk{opacity:0;scale:.4;
  transition:opacity 300ms var(--ease-out),scale 480ms var(--ease-snap)}
.shipmap.seq .mk.on{opacity:1;scale:1}
/* The pulse would otherwise run on markers that have not arrived yet. */
.shipmap.seq .mk::after{animation:none}
.shipmap.seq .mk.on::after{animation:mkpulse 3.4s var(--ease-out) infinite}
/* A hard ring flash on arrival, so a step registers even in peripheral
   vision. */
.shipmap.seq .mk.on{animation:mkland 620ms var(--ease-out) both}
@keyframes mkland{
  0%{box-shadow:0 0 0 0 rgba(147,198,255,.65)}
  100%{box-shadow:0 0 0 16px rgba(147,198,255,0)}}
.shipmap.seq .key{opacity:0;translate:0 18px;
  transition:opacity 520ms var(--ease-out) 260ms,translate 620ms var(--ease-snap) 260ms}
.shipmap.seq .key.on{opacity:1;translate:0 0}
/* The numeral leads its own key in, so the eye is at the number the arrow is
   pointing at before the sentence arrives. */
.shipmap.seq .key .n{opacity:0;transition:opacity 300ms var(--ease-out) 120ms}
.shipmap.seq .key.on .n{opacity:1}

@media(max-width:900px){
  .shipmap{grid-template-columns:1fr;gap:clamp(20px,3vh,30px)}
  .shipmap .ship{max-height:44vh}
  /* The markers stay. They are not targets — nothing here is tappable — they
     are the other half of the numeral, and without them the keys below name
     four parts of a ship the reader has no way of finding. The box is still
     exactly the painted render at this width (height-driven, object-fit
     contain), so the percentages in §01 above land on the same anatomy they
     do on the desktop figure.

     Scaled to suit the smaller render: a 30px disc on a half-size ship
     covers the part it is naming. The arrows do go — a leader needs a column
     of copy to leave from, and the keys are underneath the ship from here. */
  .shipmap .mk{width:22px;height:22px}
  .shipmap .mk i{font-size:.5rem}
  .shiplines{display:none}
  .shipkeys{grid-template-columns:1fr 1fr;gap:22px 26px}
  .shipkeys p{max-width:none}
}
@media(max-width:560px){.shipkeys{grid-template-columns:1fr}}
@media(prefers-reduced-motion:reduce){
  .shipmap .mk::after{animation:none;opacity:.4}
  .shipmap .mk.on{animation:none}
  .shiplines .sl{stroke-dashoffset:0;transition:none}}

/* The frame, its play ring, in-place playback AND the chapter strip are all
   in site.css now — the technology page's Cape Horn reel plays in its frame
   the same way and has a strip of its own, so every rule that used to sit
   here moved there with it (including `contain` rather than the shared
   `cover`: a 16/9 frame squared off on a narrow screen must letterbox rather
   than crop the subtitles away). Nothing about the film is homepage-only. */

/* ═══ 03b · THE FILM ═════════════════════════════════════════════════════
   Its own section since the film was promoted out of §05. Same head layout
   the stage teardown used to share with it. */
.film{position:relative;padding:clamp(72px,11vh,132px) 0 clamp(64px,9vh,110px)}
/* No longer space-between: the runtime badge that used to sit opposite the
   headline was removed (it said what the caption under the film says, and at
   flex-end against a two-line headline it read as an orphan). */
.film-head{margin-bottom:clamp(30px,4.6vh,50px)}
.film-head .lede{margin-top:20px;color:var(--mist);max-width:54ch}
/* §05 keeps a head of its own now, with a lede under it rather than a runtime
   badge beside it, so it must not inherit the film head's space-between */
.stages-head{display:block}
/* 52ch dropped "platform." onto a line of its own. Wider measure, plus
   balance so no width can orphan the last word again. */
.stages-head .lede{margin-top:18px;color:var(--mist);max-width:64ch;text-wrap:balance}

/* One child since the runtime line came out, so space-between would park the
   link on the left. It belongs under the right-hand end of the frame. */
.vcap{display:flex;justify-content:flex-end;align-items:center;gap:24px;
  margin-top:22px;flex-wrap:wrap}

/* Proof row. Four numbers, one per stage of the mechanism, carried over when
   the stage cards went to /technology/ — they are what makes the four
   callouts above believable, so they sit directly under them. */
.proofrow{list-style:none;display:grid;grid-template-columns:repeat(4,1fr);
  gap:1px;background:var(--line);border-block:1px solid var(--line);
  margin-top:clamp(8px,1.6vh,20px)}
.proofrow li{background:var(--schematic);padding:clamp(20px,3vh,30px) clamp(16px,2vw,26px)}
.proofrow b{display:block;font-family:var(--instrument);font-weight:400;
  font-size:clamp(1.5rem,2.8vw,2.3rem);letter-spacing:-.02em;color:var(--white);
  line-height:1;margin-bottom:11px}
.proofrow span{display:block;font-size:.92rem;line-height:1.4;color:var(--mist);
  max-width:26ch}
@media(max-width:860px){.proofrow{grid-template-columns:1fr 1fr}}
@media(max-width:520px){.proofrow{grid-template-columns:1fr}}

.hiwlink{margin-top:clamp(22px,3vh,32px);display:flex;justify-content:flex-end}

/* 11.5vh, down from the 15 it was. The isolation above the closing line is
   the point — it is the section's last word and it should arrive after a
   pause — but 15vh put 142px between it and the technology link at
   1512x950, which on top of the two chapter gaps either side of it made
   this stretch of the page read as mostly air. Flagged in the same review
   pass as those two. */
.hiw-close{text-align:center;padding:clamp(72px,11.5vh,140px) 0 0}
.hiw-close p{margin-inline:auto;max-width:26ch}

/* ═══ 07 · MARKETS ═══════════════════════════════════════════════════════ */
.markets{padding-bottom:clamp(80px,12vh,140px)}
.markets .lead{padding:clamp(90px,15vh,170px) 0 46px}
.cards{position:relative}
/* Each card is now half image, half copy. The v1.1 cards were flat colour
   fields with a lot of dead space; the imagery names the market faster
   than the headline does.

   min-height was 60vh, which is one full screen of scroll per card and
   nearly three for the section. The sticky stack is worth keeping — it is
   the best interaction on the page after the globe — so the cards are
   shorter rather than fewer. Copy still clears the fold at 48vh. */
.scard{position:sticky;margin:0 auto 26px;width:min(1120px,92vw);min-height:48vh;
  border-radius:var(--r-lg);display:grid;grid-template-columns:1fr 1fr;
  border:1px solid var(--line);overflow:hidden;box-shadow:0 -20px 70px rgba(2,14,26,.55)}
.scard .copy{padding:clamp(30px,4.4vw,58px);display:flex;flex-direction:column;
  justify-content:space-between;position:relative;z-index:1}
.scard .shot{position:relative;overflow:hidden;min-height:280px}
.scard .shot img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform 1.2s var(--ease-out);filter:saturate(1.1)}
.scard:hover .shot img{transform:scale(1.05)}
/* feather the image into the card so it reads as one object, not a pasted photo */
.scard .shot::after{content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,var(--card-bg) 0%,rgba(0,0,0,0) 42%)}
.scard:nth-child(1){--card-bg:#0E3252;--card-rgb:14,50,82;background:#0E3252;top:11vh}
.scard:nth-child(2){--card-bg:#124068;--card-rgb:18,64,104;background:#124068;top:13vh}
.scard:nth-child(3){--card-bg:#18537F;--card-rgb:24,83,127;background:#18537F;top:15vh}
/* The compute galleon carried a drawn SVG, which needed the saturate() lift
   and the hover zoom suppressed — a diagram enlarging under the cursor reads
   as a bug, not a zoom. It is a render now, so it behaves like the other
   three and those two exceptions have gone with the drawing. */
.scard:nth-child(4){--card-bg:#1E6597;--card-rgb:30,101,151;background:#1E6597;top:17vh}
/* EVERY CARD'S PICTURE RUNS THE FULL WIDTH OF ITS CARD (James, 31 Aug 2026),
   rather than sitting in the right-hand half of the grid. The shot leaves the
   grid and covers the card; the copy stays in the left column on top of it,
   and the feather that fades the picture into the card's colour carries much
   further across so the type keeps a solid ground under it. Each card mixes
   that feather from its own --card-rgb, so the four keep their colour steps.

   Side-by-side widths only. Below 820px the cards stack the picture above the
   copy as a full-width band, which is already the full width of the card —
   overlaying the type there would put the tag and the headline across the
   brightest part of each frame. */
@media(min-width:821px){
  .scard .shot{position:absolute;inset:0;min-height:0}
  .scard .copy{position:relative;z-index:2}
  /* The scrim is as light as the copy will take, so the picture reads across
     the whole card rather than fading behind a wash of card colour. What buys
     the extra transparency is the text-shadow below: at .82 the island card's
     turquoise came through hard enough to eat body copy set in --mist, and a
     shadow on the type fixes that where more opacity would only hide the
     photograph. Same trade the hero makes over moving footage. */
  .scard .shot::after{background:linear-gradient(90deg,
    rgba(var(--card-rgb),.94) 0%,rgba(var(--card-rgb),.82) 34%,
    rgba(var(--card-rgb),.42) 58%,rgba(0,0,0,0) 78%)}
  .scard .copy{text-shadow:0 1px 16px rgba(2,14,26,.72),0 1px 4px rgba(2,14,26,.5)}
}
@media(max-width:820px){
  .scard{grid-template-columns:1fr;min-height:0}
  .scard .shot{min-height:210px;order:-1}
  .scard .shot::after{background:linear-gradient(180deg,rgba(0,0,0,0) 40%,var(--card-bg) 100%)}
}
.scard .tag{font-family:var(--mono);font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--current-lift);font-weight:600}
.scard h3{margin-top:auto;max-width:16ch}
.scard .foot{margin-top:20px;display:flex;justify-content:space-between;align-items:flex-end;
  gap:24px;flex-wrap:wrap}
.scard p{color:var(--mist);max-width:48ch}

/* ═══ 08 · MILESTONES ════════════════════════════════════════════════════ */
.milestones{padding:clamp(64px,9vh,112px) 0}
/* One column, not two — for the CLAIM and the QUOTES. The feature and the
   quotes were a 7fr/5fr split, which ran the quotes down a rail level with
   the headline: they read as furniture beside the claim rather than as
   support for it. The quotes therefore sit in line beneath it.

   The claim itself does pair with something on the right, but not with type —
   with the photograph of the handover. That is not a second column of
   argument competing with the first; it is the evidence for the sentence
   next to it, so it may sit level with it. The copy keeps its reading
   measure inside .fcopy. */
.milestones .feature{display:grid;align-items:stretch;
  grid-template-columns:minmax(0,1.08fr) minmax(0,.92fr);
  gap:clamp(30px,4vw,62px)}
.milestones .fcopy{max-width:min(880px,100%);align-self:center}

/* ── THE HANDOVER PHOTOGRAPH ───────────────────────────────────────────
   A bright convention-centre snapshot on a navy page will read as a pasted
   rectangle unless it is made to belong. Three things do that, and they are
   deliberately split between the file and the CSS:

   In the FILE (src/assets/img/rina-aip-handover.webp, cropped and graded
   from the newsroom original): the colour is calmed and the shadows are
   pushed toward --abyss, so the darks in the picture are the same navy as
   the section behind it. Highlights are left alone — the faces and the
   certificate still read as a photograph, not as a duotone.

   Here: the frame borrows the RINA plate's border and radius so the two
   objects read as one family, and ::after feathers every edge back into the
   page with an inset wash rather than stopping at a hard line.

   The frame STRETCHES to the copy beside it and the image covers it, so the
   two columns always bottom out together whatever the headline wraps to.
   object-position holds the picture high — heads, certificate and the DRIFT
   mark on the banner — and lets the empty stand floor fall under the
   caption, which is where the caption's scrim wants dead space anyway. */
.rina-shot{position:relative;margin:0;overflow:hidden;
  min-height:clamp(340px,44vw,560px);
  border:1px solid var(--line-signal);border-radius:var(--r-lg);
  background:var(--schematic);box-shadow:0 26px 68px rgba(2,14,26,.5)}
.rina-shot img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:50% 26%}
.rina-shot::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,
    rgba(var(--abyss-rgb),.34) 0%,rgba(var(--abyss-rgb),0) 24%,
    rgba(var(--abyss-rgb),0) 46%,rgba(var(--abyss-rgb),.84) 84%,
    rgba(var(--abyss-rgb),.96) 100%);
  box-shadow:inset 0 0 52px 10px rgba(var(--abyss-rgb),.52)}
/* Same type as .rina-plate .t, one tier down — the plate states the approval,
   the caption only says who is in the picture. */
.rina-shot figcaption{position:absolute;left:0;right:0;bottom:0;z-index:2;
  padding:clamp(20px,2.4vw,26px);font-size:.76rem;line-height:1.55;color:var(--mist)}
.rina-shot figcaption b{display:block;color:var(--white);font-weight:500;
  font-size:.88rem;margin-bottom:4px}
/* Below ~900px the picture goes under the claim rather than beside it, and
   stops stretching — nothing is left to match its height to. */
@media(max-width:900px){
  .milestones .feature{grid-template-columns:1fr}
  .rina-shot{aspect-ratio:4/3;min-height:0}
  .rina-shot img{object-position:50% 22%}
}
@media(max-width:560px){.rina-shot{aspect-ratio:5/4}}
.feature .tag{font-family:var(--mono);font-size:.66rem;letter-spacing:.2em;color:var(--charge);
  text-transform:uppercase;margin-bottom:20px}
.feature h3{margin-bottom:20px}
.feature p{color:var(--mist);margin-bottom:28px;max-width:58ch}
/* the lede hands straight down to the claim, so it does not carry the gap */
.feature p.lede{margin-bottom:12px}
/* The sentence that used to be the back half of the lede. It is the point of
   the approval — an outside body now stands behind the design — so it is set
   at pull-quote weight and in white. Deliberately NOT a blockquote: nobody is
   being quoted, and a left rule plus quotation marks would imply RINA said
   it. */
.feature .pullclaim{font-size:clamp(1.06rem,1.7vw,1.34rem);font-weight:300;
  line-height:1.46;color:var(--white);max-width:36ch;margin-bottom:30px}
/* ── THE QUOTES, IN LINE ───────────────────────────────────────────────
   Side by side under the claim and across the full content width. Below
   ~660px of tile width they drop to one per row on their own — auto-fit,
   no breakpoint. */
.voices{margin-top:clamp(36px,5vh,58px);padding-top:clamp(26px,4vh,40px);
  border-top:1px solid var(--line);
  display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));
  gap:clamp(24px,4vw,56px)}
/* ── RECOGNITION LOGOS ─────────────────────────────────────────────────
   Light tiles carrying the marks at full colour.

   They used to be white knock-outs at 72% opacity on a near-black tile,
   which turned eleven different organisations into one flat grey wall. The
   fix is not "un-dim them": of the ten marks here only RINA, SailGP and
   Robb Report have any real colour in them — CNN, COP28, the IMO, the WEF,
   The Economist and the Sunday Times are all BLACK artwork drawn for light
   backgrounds. Full colour therefore requires a light tile; on the navy,
   black artwork has nowhere to go but white.

   Two columns rather than three: several of these marks are very wide
   (the IMO lockup is 5:1, the Sunday Times masthead 5.5:1) and in a 110px
   tile they were width-constrained down to about 20px tall while the square
   ones sat at 32px. Wider tiles let the whole set share one cap height. */
/* ── THE CREDIBILITY BAND ──────────────────────────────────────────────
   The strips run the full width of the section rather than down the side
   column. In a 448px column eleven tiles wrapped 2–3 across and stood five
   rows deep; across the page they are two rows, which is ~220px of height
   back and gives every wide lockup room to sit at the same cap height as
   the square ones. */
/* .creds and .mstones are direct children of the section, deliberately
   OUTSIDE the two-column .wrap so they can run the full content width. But
   "outside the columns" was implemented as outside every container, so both
   ran full-bleed to the viewport edge: the headings sat hard against x=0
   while the feature above them was inset, and the last tile in each logo row
   was clipped off the right. They need the page gutter, not the column. */
.creds{margin-top:clamp(44px,6vh,72px);width:min(1240px,90vw);margin-inline:auto}
.creds h4{margin-bottom:16px}
.creds h4:not(:first-child){margin-top:22px}
/* ONE rule for both strips, at every width.

   This was a ladder of fixed column counts — 6 and 5 on desktop, 3 at
   1080px, 2 at 620px, 2 again at 520px — plus a base of 2 and a later
   flex block for .press that never applied because `.creds .reclogos.press`
   outranked it. Two generations of layout arguing: at a 966px wrap the
   1080px rung won and produced three 315px-wide tiles, so each logo sat in
   the middle of a mostly-empty white box a third of the page across.

   auto-fit + minmax sizes the tiles to the logos instead of to the
   container, and reflows 6 → 5 → 4 → 3 → 2 on its own. No breakpoints. */
.creds .reclogos{display:grid;gap:10px;margin-bottom:0;
  grid-template-columns:repeat(auto-fit,minmax(132px,1fr))}
/* mastheads are wider than roundels — the Sunday Times needs ~170px at cap */
.creds .reclogos.press{display:grid;gap:10px;margin-bottom:0;
  grid-template-columns:repeat(auto-fit,minmax(158px,1fr))}
.creds .reclogos.press span{min-height:58px}
/* 26px rather than 23: The Economist's mark is the boxed lockup, nearly
   square, so at the smaller cap it sat 45px wide against the Sunday Times
   masthead's 127px and read as an afterthought. At 26px the widest masthead
   is still 143px inside a 204px tile. */
.creds .reclogos.press img{max-height:26px}
.reclogos a,.reclogos span{display:grid;place-items:center;padding:14px 22px;min-height:64px;
  border:1px solid rgba(255,255,255,.12);border-radius:var(--r-md);background:#fff;
  transition:border-color var(--t-fast),box-shadow var(--t-fast),transform var(--t-fast)}
.reclogos a:hover,.reclogos span:hover{border-color:var(--current-lift);
  box-shadow:0 8px 26px rgba(2,14,26,.45);transform:translateY(-1px)}
/* max-height AND max-width, so a wide lockup shrinks to fit rather than
   overflowing and a square one is not blown up past its cap height */
.reclogos img{max-height:30px;max-width:100%;width:auto;height:auto;object-fit:contain}
/* "As seen in" reuses the tile grid but must not read as loudly as the
   recognition row above it — a masthead is coverage, not endorsement — so
   the tiles are quieter and the wordmarks are set rather than shouted. */
/* The flex version of this ("flex:1 1 150px") lived here and never applied —
   `.creds .reclogos.press` above outranks a bare `.reclogos.press` on
   specificity, so display:grid always won. auto-fit does the job it was
   reaching for, so only the cap height survives. */
.reclogos.press img{max-height:23px}
/* the one masthead with no artwork available */
.reclogos.press b{font-weight:600;font-size:.9rem;letter-spacing:.02em;
  color:var(--hull);text-align:center;line-height:1.2}
/* ── THE TIMELINE ──────────────────────────────────────────────────────
   Full width, outside the two columns, one entry per row laid ACROSS the
   page: date / headline / detail.

   Stacked inside the 380px feature column it ran to 848px — 59% of the whole
   section — because on a measure that narrow every entry spent three or four
   lines on what is really one sentence. Turned through ninety degrees the
   same eight entries are two lines at most, and it reads as a record you can
   scan down rather than a wall you have to climb.

   No rules between rows: the rail and its nodes carry the structure, and
   ruled rows made the unequal heights the loudest thing about it. */
.mstones{list-style:none;margin:clamp(48px,7vh,84px) auto 0;padding:16px 0 0;
  width:min(1240px,90vw);border-top:1px solid var(--line)}
.mstones li{position:relative;display:grid;
  grid-template-columns:96px minmax(0,.92fr) minmax(0,1.5fr);
  gap:clamp(16px,2.2vw,34px);align-items:baseline;
  padding:12px 0 12px 28px}
/* the rail runs node to node and stops at the last */
.mstones li::before{content:"";position:absolute;left:0;top:4px;bottom:0;width:1px;
  background:var(--line-signal)}
.mstones li:last-child::before{content:none}
.mstones li::after{content:"";position:absolute;left:-3.5px;top:4px;
  width:8px;height:8px;border-radius:50%;background:var(--current-lift);
  box-shadow:0 0 0 4px var(--abyss)}
.mstones .when{font-family:var(--mono);font-size:.68rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--sky);white-space:nowrap}
.mstones b{color:var(--white);font-weight:500;font-size:.95rem;line-height:1.42}
.mstones .det{font-size:.875rem;line-height:1.6;color:var(--fog)}
.mstones .chip{white-space:nowrap;vertical-align:1px}
/* the one that just happened */
.mstones li.now::after{background:var(--charge);
  box-shadow:0 0 0 4px var(--abyss),0 0 16px rgba(78,240,196,.8)}
.mstones li.now .when{color:var(--charge)}
/* the ones still ahead */
.mstones li.ahead::after{background:transparent;border:1.5px solid var(--ghost);
  left:-4.5px;box-shadow:0 0 0 4px var(--abyss)}
.mstones li.ahead::before{background:repeating-linear-gradient(180deg,
  var(--line) 0 5px,transparent 5px 11px)}
.mstones li.ahead .when{color:var(--ghost)}
.mstones li.ahead b{color:var(--mist)}
/* Below ~900px there is no room for three across: date on its own line,
   then headline, then detail. */
@media(max-width:900px){
  .mstones li{grid-template-columns:1fr;gap:5px;padding-left:24px}
}

/* RINA gets its own plate — it is a classification approval, not a mention */
.rina-plate{display:flex;align-items:center;gap:22px;padding:22px 26px;margin-bottom:30px;
  border:1px solid var(--line-signal);border-radius:var(--r-md);
  background:linear-gradient(100deg,rgba(59,123,255,.14),rgba(59,123,255,.03))}
.rina-plate img{height:44px;width:auto;flex:none}
.rina-plate .t{font-size:.8rem;color:var(--mist);line-height:1.55}
.rina-plate .t b{display:block;color:var(--white);font-weight:500;font-size:.92rem;margin-bottom:3px}
blockquote{border-left:2px solid var(--current);padding-left:22px;font-size:1.05rem;
  font-weight:200;line-height:1.5;color:var(--white)}
blockquote cite{display:block;margin-top:14px;font-style:normal;font-family:var(--mono);
  font-size:.68rem;letter-spacing:.12em;color:var(--fog);text-transform:uppercase}

/* ═══ 09 · THE ASK ═══════════════════════════════════════════════════════ */
.ask{position:relative;overflow:hidden;padding:clamp(120px,22vh,240px) 0;text-align:center;
  background:var(--abyss)}
/* Oversized and offset so a parallax shift can never expose an edge. */
.ask>img{position:absolute;left:0;top:-12%;width:100%;height:124%;object-fit:cover;z-index:0;
  will-change:transform;filter:saturate(1.2) contrast(1.05)}
.ask .sc{position:absolute;inset:0;z-index:1;
  background:
    linear-gradient(180deg,rgba(var(--abyss-rgb),.92) 0%,rgba(var(--abyss-rgb),.44) 42%,
                    rgba(var(--abyss-rgb),.44) 58%,rgba(var(--abyss-rgb),.92) 100%),
    radial-gradient(80% 62% at 50% 50%,rgba(var(--abyss-rgb),.26),rgba(var(--abyss-rgb),.84))}
/* The wash over these photographs was lightened so the picture reads as a
   picture. Type that used to be carried by that wash is carried by its own
   shadow instead — the same trade the hero already makes, and it protects
   the words specifically rather than dimming the whole frame to reach them.
   It also holds while the parallax moves brighter water up behind them. */
.ask .wrap{position:relative;z-index:2}
.ask h2,.ask .eyebrow{text-shadow:0 2px 30px rgba(var(--abyss-rgb),.9),0 1px 6px rgba(var(--abyss-rgb),.6)}
.ask p.body{text-shadow:0 1px 18px rgba(var(--abyss-rgb),.95),0 1px 4px rgba(var(--abyss-rgb),.7)}
.ask p.body{margin:30px auto 0;color:var(--mist);max-width:52ch}
/* The page's most important action — scaled up accordingly. */
.ask .ctas{margin-top:46px;display:flex;gap:16px;justify-content:center;flex-wrap:wrap}
.ask .ctas .btn{padding:22px 48px;font-size:1.1rem}
.ask .direct{margin-top:60px;padding-top:34px;border-top:1px solid var(--line);
  max-width:560px;margin-inline:auto;font-size:.95rem;color:var(--mist);line-height:1.95}
.ask .direct .lab{display:block;font-size:.7rem;font-weight:600;letter-spacing:.26em;
  text-transform:uppercase;color:var(--fog);margin-bottom:14px}
.ask .direct b{color:var(--white);font-weight:500}
.ask .direct a{color:var(--current-lift);font-weight:400}
.ask .direct a:hover{text-decoration:underline}


/* ═══ REDUCED MOTION — homepage unwinds ══════════════════════════════════
   site.css kills durations globally. These additionally unwind the
   scroll-driven layout that would otherwise leave content stranded — the
   pinned hero. Mandatory, spec A4. */
@media(prefers-reduced-motion:reduce){
  .hero{height:auto}
  .hero .pin{position:relative;height:100svh}
  .hero .layer.a{display:none}
  .hero .layer.b{opacity:1}
  /* The horizontal journey is gone; the movements are ordinary sections
     and need no unwinding. Their background images still parallax, so
     those are pinned instead. */
  .movement>img{transform:none!important;top:0;height:100%}
  /* Mission Control needs almost nothing here now. It was a pinned
     sequence that had to be unwound into a stack; it is an ordinary
     two-column panel, so all it gives up is the side-by-side. The globe
     still runs — home.js draws one frame and stops — so the instrument is
     there to read, it just never moves on its own. */
  .mission .scene{grid-template-columns:minmax(0,1fr)}
  .mission .stage-inner{width:min(100%,520px)}
  .scard{position:relative;top:auto!important}
}

/* ── PHONE RHYTHM ─────────────────────────────────────────────────────────
   The same note as body .sec in site.css (James, 28 Aug 2026 — "spacing
   between the modules", too much on mobile). The homepage does not use
   .sec; every band here carries its own vh-based clamp, and on an 812px
   phone those resolve enormous: #numbers 162px top AND bottom, #ask 179,
   #mission 130. Between #mission and #numbers that was 292px of empty
   screen — a third of the phone — for one section change.

   Values, not clamps, because the whole problem is that a viewport unit on
   a phone is not the same instrument it is on a laptop. Roughly halved,
   and the asymmetries that were doing something are kept: the chapter
   opener still runs into the movement below it, and .ask keeps more air
   than the rest because it is the closing panel, not another band. */
@media(max-width:620px){
  .film{padding-block:56px 48px}
  .hiw{padding-block:56px}
  .macro-open{padding-block:52px 28px}
  .movement{padding-block:56px}
  .mission{padding-block:64px}
  .markets{padding-bottom:56px}
  .markets .lead{padding-top:64px}
  .milestones{padding-block:56px}
  .ask{padding-block:80px}
}
