/* ═══════════════════════════════════════════════════════════════
   STEAMER POINT — holding page
   Built to Steamer Point brand guidelines:
     p.13  Twelve letters, twelve hours — S at 12 o'clock, gold at high noon
     p.15  The Toolkit — Sailcloth / Night Watch / Solar Noon
     p.16  Typography — Newsreader (primary), JetBrains Mono (fact only)
     p.24  Homepage reference layout
   ═══════════════════════════════════════════════════════════════ */

/* ─── Tokens ─────────────────────────────────────────────────── */
:root {
  /* Palette — p.15. Restraint, with one exception. */
  --sailcloth:  #FFFDF4;
  --night:      #1F1D1A;
  --noon:       #BC853B;   /* used sparingly, only where the sun is at its peak */
  --surface-dim: #F6F3E9;  /* Sailcloth, a touch dimmer — banded surfaces like the register card. Binary fallback; the @supports block below makes it track the theme in both directions. */

  --rule:       rgb(31 29 26 / 0.18);
  --rule-soft:  rgb(31 29 26 / 0.10);
  --ink-muted:  rgb(31 29 26 / 0.62);

  --rule-inv:      rgb(255 253 244 / 0.20);
  --ink-muted-inv: rgb(255 253 244 / 0.62);

  /* Type */
  --serif: 'Newsreader', 'Times New Roman', times, serif;
  --mono:  'JetBrains Mono', ui-monospace, 'SF Mono', menlo, monospace;

  /* Fluid scale */
  --step-hero: clamp(2rem, 5.2vw, 7rem);
  --step-h2:   clamp(2rem, 4.6vw, 3.75rem);
  --step-h3:   clamp(1.25rem, 1.8vw, 1.625rem);
  --step-lede: clamp(1.125rem, 1.9vw, 1.5rem);
  --step-body: clamp(1rem, 1.15vw, 1.0625rem);
  --step-data: 0.6875rem;

  /* Rhythm */
  --gutter: clamp(1.25rem, 4vw, 4rem);
  --bleed:  clamp(1.25rem, 2.5vw, 2.5rem);   /* cream margin around the hero frame, p.24 */
  --section-y: clamp(5rem, 11vw, 11rem);

  /* Two measures, because they do different jobs.
     --maxw caps reading content: sections, grids, fact lists.
     --maxw-wide is for the furniture that should track the screen —
     the masthead and the banner, which on p.24 run edge to edge with
     only the cream bleed outside them. */
  --maxw: 120rem;
  --maxw-wide: 160rem;

  /* Fixed masthead height, so the hero can fill exactly the rest of the
     first screen — the banner sits above the fold, as on p.24. */
  --masthead-h: 5.5rem;

  /* How dark the masthead is: 0 daylight, 1 night. JS slides it so dusk
     arrives as a fade, and holds dark past sunrise / ahead of sunset.
     Mirrors solace.mov. */
  --night-mix: 0;
  /* Banner saturation, driven by how high the sun is (JS). */
  --banner-sat: 1;
  /* How far the banner is dimmed at full night. */
  --banner-scrim: 0.55;
  /* Ink steps rather than blends, so it never meets the background in the
     mid-grey; the masthead's colour transition smooths the swap. */
  --ink-mix: 0;

  /* Binary fallback for browsers without color-mix(); the smooth version
     overrides these in the @supports block below. */
  --sky-bg:    var(--sailcloth);
  --sky-ink:   var(--night);
  --sky-muted: rgb(31 29 26 / 0.62);
  --sky-rule:  rgb(31 29 26 / 0.10);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

:root[data-daypart="night"] {
  --sky-bg:    var(--night);
  --sky-ink:   var(--sailcloth);
  --sky-muted: rgb(255 253 244 / 0.62);
  --sky-rule:  rgb(255 253 244 / 0.14);
  --surface-dim: #2B2823;   /* Night, a touch lighter — the dark-mode fallback for the card */
}

/* The actual crossfade. Everything in the masthead reads these, including
   the day arc's strokes via currentColor, so the whole thing fades as one. */
@supports (color: color-mix(in srgb, white, black)) {
  :root, :root[data-daypart="night"] {
    --sky-bg:  color-mix(in srgb,
                      var(--night) calc(var(--night-mix) * 100%), var(--sailcloth));
    --sky-ink: color-mix(in srgb,
                      var(--sailcloth) calc(var(--ink-mix) * 100%), var(--night));
    --sky-muted: color-mix(in srgb, var(--sky-ink) 62%, transparent);
    --sky-rule:  color-mix(in srgb, var(--sky-ink) 13%, transparent);
    /* A small step of ink into the sky colour, either direction — dims
       Sailcloth for the card in daylight, lifts Night for it after dark. */
    --surface-dim: color-mix(in srgb, var(--sky-ink) 6%, var(--sky-bg));
  }
}

/* ─── Reset ──────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--sailcloth);
  color: var(--night);
  font-family: var(--serif);
  font-optical-sizing: auto;
  font-size: var(--step-body);
  font-weight: 400;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ─── Grain ────────────────────────────────────────────────────
   Every surface in the guidelines (p.17, p.24) carries a faint grain
   rather than a flat fill — book cover, hero photo, cream header strip
   alike. One fixed, blended layer over the whole viewport does that
   without re-deriving it per background colour: overlay blend darkens
   it slightly into Sailcloth and lightens it slightly into Night
   Watch, so the same texture reads correctly on both. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 999;
  pointer-events: none;
  opacity: 0.045;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}

h1, h2, h3, p, dl, dd, figure { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
img, svg { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
button, input, select { font: inherit; color: inherit; }

/* ─── Utilities ──────────────────────────────────────────────── */
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

.skip-link {
  position: absolute; top: 0; left: 50%; z-index: 200;
  transform: translate(-50%, -110%);
  padding: 0.6rem 1.25rem;
  background: var(--night); color: var(--sailcloth);
  font-family: var(--mono); font-size: var(--step-data);
  letter-spacing: 0.14em; text-transform: uppercase; text-decoration: none;
}
.skip-link:focus-visible { transform: translate(-50%, 0); }

:where(a, button, input, select, [tabindex]):focus-visible {
  outline: 2px solid var(--noon);
  outline-offset: 3px;
}

/* Mono carries only fact: coordinates, tide times, plot numbers — p.16 */
.eyebrow,
.datastrip,
.factlist,
.card__meta,
.nav-toggle__label,
.footer__coords {
  font-family: var(--mono);
  font-size: var(--step-data);
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1.5;
}

.eyebrow { display: flex; align-items: center; gap: 0.75em; color: var(--ink-muted); }
.index { color: var(--noon); }

.link-underline {
  display: inline-block;
  text-decoration: none;
  padding-bottom: 2px;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 1px;
  transition: background-size 0.45s var(--ease), opacity 0.3s var(--ease);
}
.link-underline:hover { background-size: 0 1px; opacity: 0.7; }

/* ═══ HEADER ═════════════════════════════════════════════════ */
.masthead {
  position: sticky; top: 0; z-index: 100;
  height: var(--masthead-h);
  padding-inline: var(--bleed);
  background: var(--sky-bg);
  color: var(--sky-ink);
  /* Scope the muted ink so the readout and rules follow the theme too */
  --ink-muted: var(--sky-muted);
  --rule: var(--sky-rule);
  --rule-soft: var(--sky-rule);
  transition: background-color 1.2s var(--ease), color 1.2s var(--ease),
              box-shadow 0.4s var(--ease);
}
.masthead[data-scrolled] { box-shadow: 0 1px 0 var(--sky-rule); }

@media (prefers-reduced-motion: reduce) {
  .masthead { transition: box-shadow 0.4s var(--ease); }
}

/* Fact left, wordmark centred, nav right — one slim row, p.24 */
.masthead__inner {
  position: relative;
  height: 100%;
  max-width: var(--maxw-wide);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1rem;
}

.datastrip { justify-self: start; }
.wordmark  { justify-self: center; }
.nav       { justify-self: end; }

/* Masthead entrance — a quick, quiet cascade left to right, settled
   before the hero underneath it has finished dissolving in. */
@media (prefers-reduced-motion: no-preference) {
  .datastrip { animation: hero-fade-in 0.9s var(--ease) both; }
  .wordmark  { animation: hero-fade-in 0.9s var(--ease) 0.15s both; }
  .nav       { animation: hero-fade-in 0.9s var(--ease) 0.3s both; }
}

/* One mark, not a crossfade to a second asset — themed via currentColor,
   so it rides the masthead's own color transition for the day/night swap
   for free. On scroll the sun fades out and the wordmark lifts and grows
   slightly to settle where the mark used to balance it. */
.wordmark { display: block; position: relative; }
.wordmark-mark {
  display: block;
  height: clamp(3.25rem, 7vw, 4rem);
  width: auto;
  overflow: visible;
  fill: currentColor;
}
.wordmark-mark__icon { transition: opacity 0.4s var(--ease); }
.wordmark-mark__text {
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 0.4s var(--ease);
}
.masthead[data-scrolled] .wordmark-mark__icon { opacity: 0; }
.masthead[data-scrolled] .wordmark-mark__text { transform: translateY(-52%) scale(1.8); }

@media (prefers-reduced-motion: reduce) {
  .wordmark-mark__icon, .wordmark-mark__text { transition: none; }
}

.nav__list {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 2.6vw, 2.5rem);
}
.nav__list a {
  text-decoration: none;
  font-size: 1.0625rem;
  transition: opacity 0.3s var(--ease);
}
.nav__list a:hover { opacity: 0.6; }
.nav__cta { text-decoration: underline !important; text-underline-offset: 4px; }

/* Mobile nav */
.nav-toggle {
  display: none;
  align-items: center; gap: 0.6rem;
  background: none; border: 0; padding: 0.4rem 0;
  cursor: pointer;
}
.nav-toggle__bars { display: grid; gap: 4px; width: 18px; }
.nav-toggle__bars span {
  height: 1px; background: currentColor;
  transition: transform 0.35s var(--ease), opacity 0.25s var(--ease);
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:first-child { transform: translateY(2.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:last-child  { transform: translateY(-2.5px) rotate(-45deg); }

@media (max-width: 60.99rem) {
  :root { --masthead-h: 5rem; }

  .nav-toggle { display: flex; }

  /* One balanced row — arc left, wordmark centre, menu right. Auto
     placement already gives that from the DOM order; .nav is absolute
     here so it doesn't claim a column. */
  .masthead__inner {
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 0.75rem;
  }
  .datastrip  { justify-self: start; }
  .wordmark   { justify-self: center; }
  .nav-toggle { justify-self: end; }

  .nav {
    position: absolute; top: 100%; left: 0; right: 0;
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.45s var(--ease);
  }
  .nav__list {
    overflow: hidden;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    border-top: 1px solid var(--sky-rule);
    background: var(--sky-bg);
  }
  .nav__list li { width: 100%; border-bottom: 1px solid var(--rule-soft); }
  .nav__list a { display: block; padding: 0.9rem 0; font-size: 1.25rem; }
  .nav[data-open] { grid-template-rows: 1fr; }
}

/* Noon graph + solar noon + coordinates, p.24 */
.datastrip {
  display: flex;
  align-items: center;
  gap: clamp(0.625rem, 1.2vw, 1rem);
}
/* solace.svg — the day arc. Strokes take currentColor so the whole mark
   inverts with the masthead; the gold is reserved for the sun at its peak.

   Stroke widths are in user units, deliberately heavier than the source
   asset (arc 8.99, horizon 4.49) because the mark renders about 14x
   smaller here than in solace.mov and a true-to-scale stroke would be
   sub-pixel. NOT non-scaling-stroke: Chrome then measures stroke-dasharray
   in device pixels, which collapses the horizon's dashes into one long
   solid line. Keeping user units preserves the dash rhythm at any size. */
.solace {
  width: clamp(3.5rem, 7vw, 7.5rem);
  height: auto;
  flex: 0 0 auto;
  overflow: visible;
}
.solace__horizon path {
  stroke: currentColor;
  stroke-width: 16;
  stroke-linecap: round;
  opacity: 0.32;
}
.solace__arc {
  fill: none;
  stroke: currentColor;
  stroke-width: 21;
  stroke-linecap: round;
}

/* The sun is moved along the arc by JS to wherever it actually is now */
.solace__sun {
  transition: transform 1.2s var(--ease), opacity 1.2s var(--ease);
}
.solace__orb {
  fill: currentColor;
  transition: fill 1.2s var(--ease);
}
.solace__rays {
  fill: none;
  stroke: var(--noon);
  stroke-width: 18;
  stroke-dasharray: 17.97 17.97;
  opacity: 0;
  transition: opacity 1.2s var(--ease);
}

/* Peak only — the single place Solar Noon is allowed to appear (p.15) */
.solace[data-phase="noon"] .solace__orb  { fill: var(--noon); }
.solace[data-phase="noon"] .solace__rays { opacity: 1; }

/* Below the horizon there is no sun to show */
.solace[data-phase="night"] .solace__sun { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  .solace__sun, .solace__orb, .solace__rays { transition: none; }
}
/* High noon above the coordinates, left-aligned stack — p.24 */
.datastrip__readout { display: grid; gap: 0; line-height: 1.45; }
.datastrip__pair { display: flex; gap: 0.6em; }
.datastrip__pair dt { color: var(--ink-muted); }
.datastrip__pair--coords dd { color: var(--ink-muted); }
.datastrip__pair dd { margin: 0; font-variant-numeric: tabular-nums; }

/* Small screens keep the arc alone — the readout is too much detail at
   that width and the coordinates are already in the footer. This has to
   come after the rules above to win on source order. */
@media (max-width: 60.99rem) {
  .datastrip__readout { display: none; }
}

/* ═══ HERO ═══════════════════════════════════════════════════ */
/* The banner fills whatever the masthead leaves of the first screen,
   keeping the whole hero above the fold — p.24. */
.hero {
  padding: 0 var(--bleed) var(--bleed);
  background: var(--sky-bg);
  color: var(--sky-ink);
  --ink-muted: var(--sky-muted);
  transition: background-color 1.2s var(--ease), color 1.2s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .hero { transition: none; }
}

.hero__frame {
  position: relative;
  max-width: var(--maxw-wide);
  margin-inline: auto;
  height: calc(100svh - var(--masthead-h) - var(--bleed));
  min-height: 24rem;
}
@media (max-width: 60.99rem) {
  .hero__frame { height: 50svh; }
}

/* Night scrim: keeps a daylight photograph from glaring out of an
   otherwise Night Watch page. Fades in with the theme, sits above the
   image and below the headline. */
.hero__frame::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--night);
  opacity: calc(var(--night-mix) * var(--banner-scrim));
  transition: opacity 1.2s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .hero__frame::after { transition: none; }
}

.hero__media {
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--night);
  /* Fully blue only when the sun is overhead; near-grey after dark */
  filter: saturate(var(--banner-sat));
  transition: filter 1.2s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .hero__media { transition: none; }
}

/* Entrance — video dissolves in first, headline rises in after it,
   the scroll cue settling in last. A quiet, deliberate sequence rather
   than everything landing on the page at once. */
@media (prefers-reduced-motion: no-preference) {
  .hero__media  { animation: hero-fade-in 1.8s var(--ease) both; }
  .hero__title  { animation: hero-fade-up-in 1.3s var(--ease) 0.5s both; }
  .hero__scroll { animation: hero-fade-in 1s var(--ease) 1.3s both; }
}
@keyframes hero-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes hero-fade-up-in {
  from { opacity: 0; transform: translateY(1rem); }
  to   { opacity: 1; transform: none; }
}


/* Headline sits over the banner, centred — p.24 */
.hero__title {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 0.06em;
  margin: 0;
  padding: 0 8%;
  font-size: var(--step-hero);
  font-weight: 300;
  line-height: 1.02;
  letter-spacing: -0.015em;
  text-align: center;
  pointer-events: none;
}
.hero__line--italic { font-style: italic; font-weight: 300; }

/* Small scroll cue, bottom centre of the frame — anchors down to #intro.
   Always sailcloth-white rather than theme-linked: it sits directly on
   the photograph, not the chrome around it, so it needs to read against
   whatever the video is doing regardless of day/night state. A soft
   shadow keeps it visible over pale sky too. */
.hero__scroll {
  position: absolute;
  left: 50%;
  bottom: clamp(1.25rem, 3vw, 2.25rem);
  z-index: 2;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  color: var(--sailcloth);
  opacity: 0.9;
  transform: translateX(-50%);
  filter: drop-shadow(0 1px 6px rgb(0 0 0 / 0.35));
  transition: opacity 0.3s var(--ease);
}
.hero__scroll:hover { opacity: 1; }
.hero__scroll svg { display: block; width: 1.625rem; height: 1.625rem; }

@media (prefers-reduced-motion: no-preference) {
  .hero__scroll svg { animation: hero-scroll-bob 2.4s ease-in-out infinite; }
}
@keyframes hero-scroll-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(0.3rem); }
}

/* ═══ INTRO ══════════════════════════════════════════════════
   Full-bleed and sky-themed like the hero and masthead above it, so
   the page doesn't hand off from a live Night Watch banner to a page
   that's stuck in daylight — the line, its lede and the register card
   all cross with the same fade. */
.intro {
  background: var(--sky-bg);
  color: var(--sky-ink);
  --ink-muted: var(--sky-muted);
  --rule: var(--sky-rule);
  --rule-soft: var(--sky-rule);
  transition: background-color 1.2s var(--ease), color 1.2s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .intro { transition: none; }
}

.intro__inner {
  /* The site's reading-content cap, so the statement and its copy can
     spread out; the register card below keeps its own narrower measure. */
  max-width: var(--maxw);
  margin-inline: auto;
  padding: clamp(3.5rem, 8vw, 7rem) var(--gutter);
  display: grid;
  gap: clamp(2rem, 3.5vw, 3rem);
}

/* Four pieces of text, auto-placed in reading order. One column on a
   phone. From 48rem the two detail paragraphs pair up beneath a
   full-width statement and lede. From 64rem it is a 2x2: statement and
   lede side by side on the first row, the details on the second, so the
   block is wide and low and no column is left empty. The statement gets
   the wider column so it holds to four lines at its full size, which
   comes out level with the lede beside it. */
.intro__grid {
  display: grid;
  gap: clamp(2rem, 3.5vw, 3.5rem) clamp(3rem, 6vw, 6rem);
  align-items: start;
}
.intro__title {
  font-size: var(--step-h2);
  font-weight: 300;
  line-height: 1.14;
  letter-spacing: -0.012em;
  text-wrap: balance;
}
.intro__title em { font-style: italic; }
.intro__body   { font-size: var(--step-lede); color: var(--ink-muted); max-inline-size: 60ch; }
.intro__detail { font-size: var(--step-body); color: var(--ink-muted); max-inline-size: 58ch; }

@media (min-width: 48rem) {
  .intro__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .intro__title, .intro__body { grid-column: 1 / -1; }
}
@media (min-width: 64rem) {
  .intro__grid { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
  .intro__title, .intro__body { grid-column: auto; }
}

/* ═══ REGISTER ═══════════════════════════════════════════════
   An inset card rather than a section of its own — same tint as
   before, sitting inside the intro's measure. Points out to the
   real enquiry form on the main site instead of re-implementing it. */
.register {
  /* Held to the width the intro used to have, and centred, so it stays
     the same size while the text above it runs wider. */
  justify-self: center;
  width: 100%;
  max-width: 78rem;
  margin-top: clamp(1rem, 3vw, 2.5rem);
  background: var(--surface-dim);
  padding: clamp(2rem, 4vw, 3.25rem) clamp(2.5rem, 6vw, 4rem);
  display: grid;
  justify-items: center;
  gap: 1rem;
  text-align: center;
}
.register__title { font-size: var(--step-h3); font-weight: 400; }
.register__body { font-size: clamp(1.0625rem, 1.3vw, 1.1875rem); color: var(--ink-muted); max-inline-size: 40ch; }
.register .button { margin-top: 0.5rem; }

.button {
  display: inline-block;
  padding: 0.85rem 2rem;
  background: var(--sky-ink);
  color: var(--sky-bg);
  border: 1px solid var(--sky-ink);
  font-family: var(--serif);
  font-size: 1.0625rem;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.35s var(--ease), color 0.35s var(--ease), border-color 0.35s var(--ease);
}
.button:hover { background: transparent; color: var(--sky-ink); }

/* ═══ Scroll reveal ══════════════════════════════════════════
   Slow and deliberate rather than snappy — a longer rise, held back
   briefly before it starts, reads as considered rather than triggered. */
@media (prefers-reduced-motion: no-preference) {
  [data-reveal] {
    opacity: 0;
    transform: translateY(1.75rem);
    transition: opacity 1.1s var(--ease), transform 1.1s var(--ease);
  }
  [data-reveal][data-revealed] { opacity: 1; transform: none; }
}

/* One link on the right rather than a nav, so there is no menu to open:
   undo the small-screen dropdown and keep it inline at every width. */
@media (max-width: 60.99rem) {
  .nav { position: static; display: block; }
  .nav__list {
    overflow: visible;
    flex-direction: row;
    align-items: center;
    gap: 0;
    border-top: 0;
    background: none;
  }
  .nav__list li { width: auto; border-bottom: 0; }
  .nav__list a { display: inline-block; padding: 0; font-size: 1.0625rem; }
}
