/* The scroll composition layer for `/`.
 *
 * LOADS AFTER `landing.css` AND DOES NOT REPLACE IT. `landing.css` still owns the brand tokens, the
 * nav, the cards, the pricing table and the FAQ, and `lib/landing-parity.test.ts` reads it to prove
 * the palette is still `lib/brand.ts`'s palette. This file adds the acts, the grounds and the peak;
 * it is additive on purpose so that gate keeps testing what it was written to test.
 *
 * THE ENGINE IS THE MECHANISM. `scrollcraft.css` positions the stages and publishes `--sc-p`;
 * nothing here restyles a `[data-sc-*]` selector. Theming is the six tokens below and two faces.
 *
 * THE GROUNDS ARE PAINTED PER SECTION, NOT DRIFTED. scrollcraft's `drift` interpolates the page
 * ground between acts, which is right for a page that is one continuous place. This one is not: the
 * founder chose distinct scenes, and the whole argument turns on a HARD CUT from ink to paper at
 * the peak. Interpolating that cut would turn the one moment the page exists for into a slow fade,
 * which is precisely the softness a chaptered page refuses. devices.md says so in as many words.
 */

/* ── the six tokens, mapped from lib/brand.ts ──────────────────────────────────────────────────
   Not new colours. `--sc-canvas` is the dark page, `--sc-surface` the dark card, `--sc-ink` the
   dark theme's text (deliberately not #FFFFFF: it haloes on the OLED screen a driver is holding),
   `--sc-accent` the amber that is constant across both themes. Changing a brand colour is still one
   edit in `lib/brand.ts`; these are the same values arriving under the names the engine expects. */
:root {
  --sc-canvas: #0f1216;
  --sc-surface: #171a1f;
  --sc-ink: #e8ebee;
  --sc-ink-soft: #9aa3ae;
  --sc-accent: #ffb400;
  --sc-accent-ink: #171a1f;
  --sc-font-display: "Barlow Condensed", system-ui, sans-serif;
  --sc-font-text: "Public Sans", system-ui, sans-serif;

  /* The two grounds the page cuts between, and the ink each one carries. Light values are
     lib/brand.ts's LIGHT.page / LIGHT.textPrimary / LIGHT.textSecondary. */
  --ground-ink: #0f1216;
  --ground-ink-deep: #0b0e11;
  --ground-paper: #f4f6f8;
  --on-ink: #e8ebee;
  --on-ink-soft: #9aa3ae;
  --on-paper: #171a1f;
  --on-paper-soft: #5a6472;

  /* 4px base. More space above a heading than below it, which is the rule that makes a page read as
     set rather than stacked. */
  --step-1: 4px;
  --step-2: 8px;
  --step-3: 16px;
  --step-4: 28px;
  --step-5: 48px;
  --step-6: 80px;
}

/* ── acts and grounds ───────────────────────────────────────────────────────────────────────── */

.act {
  position: relative;
  /* Opaque, always. A transparent act would show the body ground through it and the cut would
     depend on what the theme happened to be. */
  background: var(--ground-ink);
  color: var(--on-ink);
}

.act--deep {
  background: var(--ground-ink-deep);
}

.act--paper {
  background: var(--ground-paper);
  color: var(--on-paper);
}

/* The cut itself. A hairline in amber at the boundary, so the change of ground reads as an edit
   rather than as a rendering artefact. It is 1px and it is the only decoration on the page. */
.act--cut {
  border-top: 1px solid var(--sc-accent);
}

.act__stage {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100vh;
  min-height: 100svh;
  padding: var(--step-6) 0;
}

.act__hold {
  width: min(1100px, 100% - 2 * var(--step-4));
  margin-inline: auto;
}

/* ── the typographic floor ──────────────────────────────────────────────────────────────────────
   Typographic poster lifts taste.md's ~6rem display cap, because the whole page is one continuous
   hero moment. What it does NOT lift is tracking and measure: at this size default tracking is a
   visible defect. Tracking tightens as size grows, which is why every step below carries its own.

   `clamp()` rather than a raw `vw`, and the lower bound is what keeps 320px honest: `qa.guard.ts`
   measures `documentElement.scrollWidth` at a 320px viewport and a single unbreakable word set at
   14vw overflows it silently. */

.sc-line {
  font-family: var(--sc-font-display);
  font-weight: 700;
  line-height: 0.94;
  letter-spacing: -0.02em;
  text-wrap: balance;
  margin: 0;
}

.sc-line--xl {
  font-size: clamp(2.75rem, 11vw, 8.5rem);
  letter-spacing: -0.035em;
}

.sc-line--lg {
  font-size: clamp(2.25rem, 7.5vw, 5rem);
  letter-spacing: -0.028em;
}

.sc-line--md {
  font-size: clamp(1.75rem, 4.5vw, 3rem);
  letter-spacing: -0.02em;
}

.sc-say {
  font-family: var(--sc-font-text);
  font-size: clamp(1rem, 1.6vw, 1.1875rem);
  line-height: 1.55;
  /* 45–75ch, and line height falls as the measure narrows. */
  max-width: 62ch;
  color: var(--on-ink-soft);
  margin: var(--step-3) 0 0;
}

.act--paper .sc-say {
  color: var(--on-paper-soft);
}

/* An eyebrow at most once per three sections, per the refuse list. There are two on this page. */
.sc-kicker {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sc-accent);
  margin: 0 0 var(--step-4);
}

.act--paper .sc-kicker {
  /* Amber as TEXT on paper is #8A6100 in lib/brand.ts, because the fill is not readable as type.
     This is that value, not the fill. */
  color: #8a6100;
}

/* ── act 2, the tension: the number nobody set aside for ────────────────────────────────────── */

.dread {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-weight: 600;
  font-size: clamp(3.5rem, 16vw, 12rem);
  line-height: 1;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--on-ink);
  margin: 0;
  /* The wipe is on a wrapper and this box has room, because `clip-path` is relative to the border
     box and not to the ink: a reveal over type set tight shears the ascenders off and every figure
     renders as a plain bar. devices.md §4 names this as the usual casualty. */
  padding-block: 0.08em;
}

.dread__frame {
  display: block;
  overflow: hidden;
}

/* ── act 3, the turn: the week travels sideways ─────────────────────────────────────────────── */

.turn__rail {
  display: flex;
  gap: clamp(var(--step-5), 8vw, 120px);
  align-items: baseline;
  white-space: nowrap;
  font-family: var(--sc-font-display);
  font-size: clamp(2rem, 6vw, 4.5rem);
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--on-ink-soft);
}

.turn__rail b {
  color: var(--on-ink);
  font-weight: 700;
}

/* ── act 4, the peak: the week, and the figure that builds from it ──────────────────────────── */

.peak__figure {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--on-paper);
  /* NO TRANSITION, DELIBERATELY. This element's text changes every animation frame under the
     scroll; a transition on it would fight the scrub and, more to the point, money that eases into
     place reads as a number being decided rather than one being calculated. `dom.guard.ts` guard 10
     enforces exactly this rule inside the app. */
  transition: none;
}

.week {
  list-style: none;
  margin: var(--step-5) 0 0;
  padding: 0;
  /* A ledger, not cards. Typographic poster forbids cards of any kind, and a week of driving is a
     record, which is what a ruled list already is. */
  border-top: 1px solid rgba(23, 26, 31, 0.16);
  max-width: 640px;
}

.week__day {
  display: grid;
  grid-template-columns: 4.5rem 1fr auto;
  gap: var(--step-3);
  align-items: baseline;
  padding: var(--step-3) 0;
  border-bottom: 1px solid rgba(23, 26, 31, 0.12);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: clamp(0.8125rem, 1.6vw, 0.9375rem);
  font-variant-numeric: tabular-nums;
  /* The settled state IS the shipped state: a no-JS reader gets the whole week at full strength.
     The script only ever removes emphasis it has not yet earned. */
  color: var(--on-paper);
}

.week__name {
  font-family: var(--sc-font-display);
  font-size: 1.15em;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.week__miles,
.week__fare {
  color: var(--on-paper-soft);
}

.week__fare {
  text-align: right;
}

/* Only once the script is driving does a row start dimmed and arrive. Gated on the class the boot
   module sets, so the page without JavaScript never enters this state.

   THE DIM IS A READABLE COLOUR, NOT AN ALPHA. This was `rgba(23, 26, 31, 0.32)`, which is about
   2.4:1 on the paper ground — and `a11y.guard.ts` reads the page at rest, where no row has been
   counted yet, so every day of the week was failing contrast at the moment the act comes on screen.
   A row that has not been reached is still text a reader is entitled to read; the emphasis change
   has to come from the step between these two values, not from making the first one illegible.
   #5A6472 is `lib/brand.ts`'s LIGHT.textSecondary and clears 5.9:1. */
.js-week .week__day {
  color: #5a6472;
}

.js-week .week__day.is-counted {
  color: var(--on-paper);
}

.js-week .week__day.is-landing .week__name {
  color: #8a6100;
}

/* ── act 8, the close ───────────────────────────────────────────────────────────────────────── */

.close__inner {
  text-align: left;
}

.close__link {
  display: inline-block;
  margin-top: var(--step-4);
  font-family: var(--sc-font-text);
  font-size: 1.0625rem;
  color: var(--sc-accent);
  text-decoration: underline;
  text-underline-offset: 6px;
  /* 44px floor at 320px, which `qa.guard.ts` sweeps on every public page. Padding rather than a
     height so the underline still sits on the text. */
  padding: 12px 0;
  min-height: 44px;
}

/* The close is the last element on the page and the footer sits inside its stage, so there is no
   dead tail after the final line. */
.close__foot {
  margin-top: var(--step-6);
}

/* ── THE PALETTE FOLLOWS THE GROUND, NOT THE OS THEME ───────────────────────────────────────────
 *
 * This is the one structural consequence of painting grounds per act, and it caused every finding
 * `a11y.guard.ts` reported on the first run.
 *
 * `landing.css` drives the whole page off eleven tokens and flips them under
 * `@media (prefers-color-scheme: dark)`. That is exactly right for a document whose background IS
 * the theme's page colour. It is wrong here: the ink acts are dark in BOTH themes and the paper
 * acts are light in BOTH themes, so in light theme `--ink` stayed #171A1F and rendered the `h1`,
 * `.hero-sub`, `.hero-trust`, `.brand-word` and the nav links as dark type on a dark ground. Six
 * serious `color-contrast` findings, all of them `/ light/desktop`, and all one cause.
 *
 * So rebind the tokens by ground. Every `landing.css` rule then resolves correctly without any of
 * them being restated here, and the fix holds for markup this file has never heard of — which is
 * what makes it a fix rather than a list of six patches.
 *
 * BOTH DIRECTIONS, deliberately. The paper acts carry the features, the pricing and the FAQ, so in
 * DARK theme they would have had the mirror-image failure: light type on the light ground. Only the
 * light-theme half was reported, because that is the half that happened to be measured first.
 *
 * Values are `lib/brand.ts`'s LIGHT and DARK sets, copied from `landing.css`'s own two blocks.
 */
body,
.act:not(.act--paper) {
  --paper: #0f1216;
  --card: #171a1f;
  --ink: #e8ebee;
  --sub: #9aa3ae;
  --line: #2a3038;
  --panel: #1e232a;
  --green: #5fcf9b;
  --warn-bg: #2a2110;
  --btn: #e8ebee;
  --on-btn: #12161b;
  --amber-ink: #ffb400;
}

.act--paper {
  --paper: #f4f6f8;
  --card: #ffffff;
  --ink: #171a1f;
  --sub: #5a6472;
  --line: #e2e6ea;
  --panel: #171a1f;
  --green: #2b7455;
  --warn-bg: #fff7e0;
  --btn: #171a1f;
  --on-btn: #ffffff;
  --amber-ink: #8a6100;
}

/* ── motion ─────────────────────────────────────────────────────────────────────────────────────
   The engine already reads the preference and parks every act at its settled state. This covers the
   two things authored here rather than by it, and it is a hard stop rather than a shortening: a
   page that still moves at 100ms under the preference has not honoured it. */
@media (prefers-reduced-motion: reduce) {
  .act,
  .act *,
  .week__day {
    transition: none !important;
    animation: none !important;
  }
}

/* ── narrow ─────────────────────────────────────────────────────────────────────────────────────
   320px is the floor WCAG 1.4.10 requires and the width `qa.guard.ts` measures sideways scroll at.
   The rail is the only thing on the page that is deliberately wider than the viewport, so it is the
   only thing that has to say so: it scrolls inside its own box, which the guard explicitly does not
   count as a finding. */
.turn__rail {
  overflow-x: auto;
  scrollbar-width: none;
}

.turn__rail::-webkit-scrollbar {
  display: none;
}

@media (max-width: 480px) {
  .act__stage {
    padding: var(--step-5) 0;
    min-height: auto;
  }

  .week__day {
    grid-template-columns: 3.5rem 1fr auto;
  }
}
