/* The Voyage Sheet — every voyage (Phase B for the 13, Phase D for the last 6).
 *
 * Every rule is scoped under #vs-. The one other scope still on this site is
 * disjoint from it: #ns-root (Next Stops). Nothing here may leak into it. The
 * parchment gallery scope and the .page-voyage plate are both gone — Phase D
 * emptied the six shells that used the first and deleted its stylesheet with
 * them; Phase B deleted the second.
 *
 * COLOUR. No new hex values are introduced. Every colour below already exists
 * in an approved export on disk:
 *   #EDE3D2 paper, #DCCBB2 paper dots  — next-stops-shell.css:44-45
 *   #F6ECD8 chart ground               — next-stops-chart.css:30
 *   #e8d9b6 land, #c2a97c land stroke  — next-stops-chart.css:65-66
 *   #3A2E22 ink, #B8431F rust,
 *   #FCF6EC cream, #E4B93B gold        — next-stops-shell.css, throughout
 *
 * ⚠ RUST IS #B8431F HERE, NOT var(--rust). styles.css defines --rust as
 * #e8623f, which is a different colour that no approved export uses, and the
 * 3.34:1 rust-on-cream contrast lock was measured on #B8431F. Logged as a
 * separate design-system ticket; deliberately not reconciled in this file.
 *
 * CONTRAST LOCK. Rust measures 3.34:1 on cream — WCAG AA for LARGE TEXT ONLY.
 * It is used below on the ghosted year, the course line, and the back link
 * (19px/700, which clears the large-text threshold). It is never used for body
 * copy, captions, the metadata line or the chart's stop labels; those take ink.
 */

#vs-root {
  background-color: #EDE3D2;
  background-image: radial-gradient(#DCCBB2 1px, transparent 1px);
  background-size: 26px 26px;
  color: #3A2E22;
  font-family: 'Nunito Sans', system-ui, sans-serif;
}

/* ------------------------------------------------------------------
   THE STAGE
   Full-bleed under the sticky header, the same footprint /next-stops/
   gives its chart, so the two pages read as one continuous object.
   The aspect-ratio is what stops the 756 KB coastline causing a layout
   shift: the well is at its final height before the fetch resolves.
   ------------------------------------------------------------------ */
#vs-root .vs-stage {
  position: relative;
  /* width MUST be definite. With width:auto the aspect-ratio resolves against
     whichever axis is constrained — so between roughly 700px and 1060px, where
     the ratio's natural height falls under min-height, the floor drove the
     WIDTH back up through the ratio (460 x 1240/540 = 1056px) and the page
     scrolled sideways at 768 and 1024 while passing at 375, 1440 and 1920.
     Pinning the width makes height the derived axis, so min/max-height clamp
     it without touching the width. */
  width: 100%;
  height: auto;
  aspect-ratio: 1240 / 540;
  min-height: 460px;
  max-height: 660px;
  overflow: hidden;
}

#vs-root .vs-chart {
  position: absolute;
  inset: 0;
  /* Chart-table ground and grain, identical to next-stops-chart.css:30-36 —
     a 19px dot screen with a gold wash top-left and a rust wash bottom-right,
     so the sea reads as printed paper rather than a flat fill. */
  background-color: #F6ECD8;
  background-image:
    radial-gradient(rgba(58, 46, 34, .055) 1px, transparent 1px),
    radial-gradient(circle at 22% 18%, rgba(200, 168, 116, .22), transparent 62%),
    radial-gradient(circle at 82% 84%, rgba(184, 67, 31, .07), transparent 58%);
  background-size: 19px 19px, auto, auto;
  background-repeat: repeat;
  overflow: hidden;
}

#vs-root .vs-chart-svg {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

#vs-root .vs-chart-land {
  fill: #e8d9b6;
  stroke: #c2a97c;
  /* 1.3 is the measured export value. The r2 revision sanctions dropping to
     1.1 — and only that, never a colour change — if 50m's finer vertices make
     it read heavy. Left at the measured value. */
  stroke-width: 1.3;
  stroke-linejoin: round;
}

#vs-root .vs-chart-label {
  fill: #3A2E22;              /* ink, never rust: these are small labels */
  font-family: 'Oswald', sans-serif;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  paint-order: stroke fill;
  stroke: #F6ECD8;
  stroke-width: 3;            /* paper halo, so a label stays legible over land */
  stroke-linejoin: round;
}

/* The chart's loading / failure line. Centred in the well it will fill. */
#vs-root .vs-chart-status {
  position: absolute;
  inset: auto 0 0 0;
  top: 50%;
  transform: translateY(-50%);
  margin: 0;
  text-align: center;
  font-family: 'Oswald', sans-serif;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  font-size: 13px;
  color: rgba(58, 46, 34, .62);
}
#vs-root .vs-chart-status--error { color: #3A2E22; }

@keyframes vs-chart-draw {
  from { stroke-dashoffset: 1; }
  to   { stroke-dashoffset: 0; }
}
@keyframes vs-chart-pop {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ------------------------------------------------------------------
   MASTHEAD
   Sits LEFT, overlapping the bottom-left of the stage — the asymmetry
   is the fix for the old page being "too centered". Nothing is inside
   a card; it is on the paper.
   ------------------------------------------------------------------ */
#vs-root .vs-masthead {
  position: absolute;
  left: clamp(16px, 3vw, 40px);
  bottom: clamp(18px, 3vw, 42px);
  z-index: 2;
  max-width: min(680px, calc(100% - 2 * clamp(16px, 3vw, 40px)));
}

/* A soft paper scrim, not a card.
   The masthead overlaps the bottom-left of the chart on purpose — that
   asymmetry is the fix for the old page being "too centered". But on a voyage
   whose course runs through that corner the title landed on top of the line.
   Labels are routed around the masthead in JS; the course itself cannot move,
   so the paper lifts under the type instead. No border, no radius, no shadow:
   it reads as the chart fading into the sheet, which is what a chart table
   does anyway. */
#vs-root .vs-masthead::before {
  content: '';
  position: absolute;
  z-index: -2;
  left: calc(-1 * clamp(16px, 3vw, 40px));
  bottom: calc(-1 * clamp(18px, 3vw, 42px));
  width: calc(100% + clamp(32px, 7vw, 120px));
  height: calc(100% + clamp(32px, 5vw, 84px));
  /* Falls off fast on purpose. A broad, even wash protected the type but also
     erased the end of the course — woodbridge-studland-2013 finishes at
     Studland Bay, in this exact corner, and its last two landfalls vanished
     under it. Strong only where the small stencilled metaline actually sits,
     clear again by roughly two-thirds out. */
  background: radial-gradient(
    105% 105% at 0% 100%,
    rgba(246, 236, 216, .94) 0%,
    rgba(246, 236, 216, .78) 30%,
    rgba(246, 236, 216, .32) 58%,
    rgba(246, 236, 216, 0) 78%
  );
  pointer-events: none;
}

/* Type as texture: the one piece of type doing pure graphic work. Ghosted,
   bleeding off the masthead's edge like an Admiralty sheet number. */
#vs-root .vs-year {
  position: absolute;
  left: -.06em;
  bottom: .06em;
  z-index: -1;
  display: block;
  font-family: 'Oswald', sans-serif;
  font-weight: 700;
  font-size: clamp(80px, 14vw, 200px);
  line-height: .78;
  color: #B8431F;
  opacity: .13;
  pointer-events: none;
  white-space: nowrap;
}

#vs-root .vs-sheet {
  display: block;
  font-family: 'Oswald', sans-serif;
  font-weight: 500;
  font-size: 12px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: rgba(58, 46, 34, .58);
  margin-bottom: 6px;
}

#vs-root .vs-title {
  margin: 0;
  font-family: 'Caveat', cursive;
  font-weight: 700;
  font-size: clamp(40px, 6.4vw, 82px);
  line-height: 1.02;
  color: #3A2E22;
  transform: rotate(-1.4deg);
  transform-origin: left bottom;
}

#vs-root .vs-metaline {
  margin: 12px 0 0;
  font-family: 'Oswald', sans-serif;
  font-weight: 500;
  font-size: clamp(11px, 1.05vw, 13px);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: #3A2E22;
}

/* ------------------------------------------------------------------
   BODY — the spine in the margin, one generous column beside it.
   ------------------------------------------------------------------ */
#vs-root .vs-body {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: clamp(20px, 3vw, 44px);
  max-width: 1240px;
  margin: 0 auto;
  padding: clamp(36px, 5vw, 72px) clamp(16px, 3vw, 40px) clamp(56px, 7vw, 104px);
}

/* THE SPINE. The course redrawn vertically. Sticky and fixed-height rather
   than stretched to the column: a variable-height viewBox would need
   preserveAspectRatio="none", which distorts the very lobe the spine exists to
   show. Server-rendered, so it is correct with JS off — only the position
   marker is scripted. */
#vs-root .vs-spine {
  position: sticky;
  top: 120px;
  align-self: start;
  height: 300px;
}
#vs-root .vs-spine-svg { display: block; overflow: visible; }
#vs-root .vs-spine-rule {
  stroke: rgba(58, 46, 34, .22);
  stroke-width: 1;
}
#vs-root .vs-spine-course {
  fill: none;
  stroke: #B8431F;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .78;
}
#vs-root .vs-spine-marker {
  fill: #B8431F;
  stroke: #FCF6EC;
  stroke-width: 1.6;
  transition: cx .35s ease, cy .35s ease;
}

#vs-root .vs-content { min-width: 0; }

/* The log is someone's writing: 62-68 characters, and the only centred thing
   on the page is the words themselves. */
#vs-root .vs-lede {
  margin: 0 0 28px;
  max-width: 34em;
  font-size: clamp(19px, 1.6vw, 22px);
  line-height: 1.62;
  color: #3A2E22;
  text-wrap: pretty;
}

#vs-root .vs-route {
  margin: 0 0 36px;
  max-width: 46em;
  font-size: 16px;
  line-height: 1.6;
  color: rgba(58, 46, 34, .78);
  text-wrap: pretty;
}

#vs-root .vs-h2 {
  margin: 0 0 18px;
  font-family: 'Oswald', sans-serif;
  font-weight: 600;
  font-size: 13px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(58, 46, 34, .66);
}

#vs-root .vs-log {
  max-width: 34em;
  margin: 0 0 44px;
}
#vs-root .vs-log p {
  margin: 0 0 1.05em;
  font-size: clamp(17px, 1.35vw, 19px);
  line-height: 1.7;
  text-wrap: pretty;
}

/* The landfall list — the chart's text alternative, and the scroll target the
   spine marker tracks. Real markup, never an aria-label. */
#vs-root .vs-stops { margin: 0 0 8px; }
#vs-root .vs-stoplist {
  margin: 0;
  padding: 0;
  list-style: none;
  max-width: 40em;
}
#vs-root .vs-stop {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 9px 0;
  border-bottom: 1px solid rgba(58, 46, 34, .12);
}
#vs-root .vs-stop-n {
  flex: 0 0 auto;
  font-family: 'Oswald', sans-serif;
  font-weight: 500;
  font-size: 12px;
  letter-spacing: .1em;
  color: rgba(58, 46, 34, .48);
  font-variant-numeric: tabular-nums;
}
#vs-root .vs-stop-label {
  font-size: 17px;
  line-height: 1.4;
}
/* The stop you are currently level with, paired with the spine marker. */
#vs-root .vs-stop.is-level .vs-stop-label { font-weight: 700; }
#vs-root .vs-stop.is-level .vs-stop-n { color: #B8431F; }

#vs-root .vs-note {
  margin: 16px 0 0;
  font-size: 15px;
  color: rgba(58, 46, 34, .68);
  font-style: italic;
}

/* ------------------------------------------------------------------
   THE PRINTS
   Live since the Media Library became the photo source: 118 prints across the
   six photographed voyages, 12 to 23 each, cover first. The rhythm is DERIVED
   from position and group size rather than a per-photo table — the round-1 mock
   hand-tuned h/flex/max/wide per photo, which cannot generalise to real
   voyages carrying 12 to 23 prints with no such data.
   The rule: a 5-step repeating cycle. Every 5th print runs full width; the
   rest alternate wide/narrow. A group of 1 gets its own centred treatment so
   it does not read as a mistake.
   THIS FILE OWNS THE RHYTHM. single-voyage.php deliberately does not compute a
   per-print sizes attribute from it — it leads with sizes=auto and lets the
   browser measure, so 5n does not have to be spelled out in two places.
   ------------------------------------------------------------------ */
#vs-root .vs-photos { margin: 48px 0 0; }
#vs-root .vs-group { margin: 0 0 clamp(36px, 5vw, 64px); }
#vs-root .vs-group-label {
  margin: 0 0 16px;
  font-family: 'Oswald', sans-serif;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(58, 46, 34, .66);
}
#vs-root .vs-prints {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(16px, 2.4vw, 30px);
  align-items: flex-start;
}
#vs-root .vs-print {
  margin: 0;
  flex: 1 1 clamp(200px, 30%, 320px);
  background: #FCF6EC;
  padding: 10px 10px 0;
  box-shadow: 0 6px 14px -8px rgba(58, 46, 34, .5);
  transition: transform .3s cubic-bezier(.34, 1.1, .5, 1), box-shadow .3s;
}

/* The pinned-up tilt: -1.1 / 0 / +1.1 repeating, so no two neighbours sit at
   the same angle and none of it reads as deliberate.
   ⚠ This was written as rotate(calc((var(--vs-i) % 3 - 1) * 1.1deg)) against a
   --vs-i the template printed per print. THAT NEVER APPLIED. % is not modulo in
   CSS calc() — it tokenises as a percentage, the expression is invalid, and the
   whole declaration is dropped. Nothing caught it because no .vs-print had ever
   rendered. nth-child computes the same three angles with no arithmetic, so
   --vs-i has no reader left and the template no longer emits it.
   These must stay ABOVE the hover rule: same (1,2,0) specificity, so source
   order is the only thing letting hover straighten a print. */
#vs-root .vs-print:nth-child(3n+1) { transform: rotate(-1.1deg); }
#vs-root .vs-print:nth-child(3n+2) { transform: rotate(0deg); }
#vs-root .vs-print:nth-child(3n)   { transform: rotate(1.1deg); }

/* Full-width break on a rhythm, not a cluster. */
#vs-root .vs-print:nth-child(5n) { flex-basis: 100%; }
/* ...except a portrait, which opts out. Every source is capped at 1280 on the
   LONG edge, so a portrait is at most ~960 wide and srcset has no candidate big
   enough for a 1072px column — it takes the largest it has and upscales. A
   portrait at column width never does. 17 of the 118 are portrait. */
#vs-root .vs-print[data-vs-orient="portrait"]:nth-child(5n) { flex-basis: clamp(200px, 30%, 320px); }
#vs-root .vs-print:nth-child(3n+2) { flex-grow: 1.6; }
#vs-root .vs-group[data-vs-count="1"] .vs-print { flex: 0 1 min(560px, 100%); margin: 0 auto; }
#vs-root .vs-print img { display: block; width: 100%; height: auto; }
#vs-root .vs-print figcaption {
  font-family: 'Caveat', cursive;
  font-size: 19px;
  line-height: 1.35;
  color: #3A2E22;
  padding: 8px 2px 12px;
}
/* A print lifts and straightens — it does not zoom. */
#vs-root .vs-print:hover,
#vs-root .vs-print:focus-within {
  transform: rotate(0deg) translateY(-4px);
  box-shadow: 0 12px 22px -10px rgba(58, 46, 34, .55);
}

/* ------------------------------------------------------------------
   ONWARD
   Adjacent-voyage navigation is deliberately not built in Phase B; there is no
   get_adjacent_post anywhere in the theme yet. Only the way back.
   ------------------------------------------------------------------ */
#vs-root .vs-back { margin: 44px 0 0; }
#vs-root .vs-backlink {
  font-family: 'Oswald', sans-serif;
  font-weight: 700;
  font-size: 19px;          /* large text: clears the rust contrast threshold */
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #B8431F;
  text-decoration: none;
  border-bottom: 2px solid rgba(184, 67, 31, .35);
  padding-bottom: 2px;
}
#vs-root .vs-backlink:hover { border-bottom-color: #B8431F; }

/* Focus rings are a gold outline, always visible, never suppressed. */
#vs-root a:focus-visible {
  outline: 3px solid #E4B93B;
  outline-offset: 3px;
}

/* ------------------------------------------------------------------
   RESPONSIVE
   375 / 768 / 1024 / 1440 / 1920, no horizontal scroll at any width.
   Below 720 the masthead stops overlapping the chart: at that width an
   overlaid masthead covers the course it describes, and the course is the
   point. The stage becomes a stacked block instead, and the chart keeps a
   generous share of the viewport rather than being shrunk.
   ------------------------------------------------------------------ */
@media (max-width: 720px) {
  #vs-root .vs-stage {
    aspect-ratio: auto;
    min-height: 0;
    max-height: none;
    display: flex;
    flex-direction: column;
  }
  #vs-root .vs-chart {
    position: relative;
    inset: auto;
    height: 68vw;
    min-height: 300px;
    max-height: 460px;
  }
  #vs-root .vs-masthead {
    position: static;
    max-width: none;
    padding: 26px clamp(16px, 5vw, 24px) 4px;
  }
  #vs-root .vs-year {
    left: auto;
    right: clamp(16px, 5vw, 24px);
    bottom: auto;
    top: -.1em;
    font-size: clamp(72px, 22vw, 130px);
  }
  /* The spine's own column is dropped rather than squeezed — at this width a
     44px gutter beside a 300px-tall sticky rule costs more than it gives. */
  #vs-root .vs-body { grid-template-columns: minmax(0, 1fr); }
  #vs-root .vs-spine { display: none; }
}

/* ------------------------------------------------------------------
   REDUCED MOTION
   The course renders already drawn, the prints already in place, and the
   spine marker still tracks. The page is complete and correct with every
   animation switched off.
   ------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  #vs-root .vs-chart-course,
  #vs-root .vs-chart-dot,
  #vs-root .vs-chart-label {
    animation: none !important;
    opacity: 1 !important;
    stroke-dashoffset: 0 !important;
  }
  #vs-root .vs-spine-marker { transition: none; }
  #vs-root .vs-print { transition: none; }
}
