/* ==========================================================================
   THE THESIS (pinned, accumulating)

   Four statements on one vertical spine. They ARRIVE as you scroll and then
   STAY: by the last screen all four are on the stage at once and the section
   reads as a four-line manifesto. This replaces the earlier build, where
   each statement replaced the last and only one was ever visible.

   THE RULES THIS SECTION DEPENDS ON

   1. TEAL IS A CURSOR, not an emphasis: it marks where the argument
      currently is, travels down the stack as statements arrive, and comes to
      rest permanently on 04. When a statement is superseded its teal is
      RELEASED back to grey, so in general only one phrase is lit at a time —
      four simultaneous teal phrases would be noise.

      ONE deliberate exception: statement 03's "reason across them" carries
      .home-thesis__accent--hold and keeps its teal after it is superseded.
      So the last screen shows exactly two lit phrases:
        reason across them → what PULSAR does.
      That pairing is the point — it states the need and the answer together,
      which is what makes 04 legible as a conclusion rather than a boast.
      Do not add a third; the exception works only because it is the only one.

   2. THREE STATES, and only three:
        future  — opacity 0, translated down ~1.5rem
        present — verdict at full --text, lead at --muted, phrase in --accent
        past    — everything at --thesis-past-ink (65% of --text), no teal
      Past is deliberately READABLE, not a ghost. The accumulated stack is
      the deliverable; a past statement you cannot read is a statement that
      did not accumulate.

   3. ONE type size for 01–03. Statement 04 is the only size change in the
      section (1.5x) and it earns it by being the only line that is a
      conclusion rather than a premise. Within a statement the lead and the
      verdict are the SAME size and differ only in colour — the earlier
      build set them at two sizes, which with four coexisting statements
      put eight competing weights on one screen.

   4. NOTHING ALREADY READ EVER MOVES. All four statements sit in normal
      flow at their final positions from the first paint; the scroll only
      changes opacity, transform and colour. Each statement reserves its space
      too. There is no reflow anywhere in the mechanic, so the fixed slot
      positions come for free rather than from measured absolute offsets.

   5. The readable stacked layout is the DEFAULT. The pinned layout only
      comes in under .home-thesis--pinned, which the JS adds on init. So
      JS-off, a JS error, and prefers-reduced-motion all degrade to the same
      fully readable stack — in the FULL present-state colour, with teal on
      04 only — rather than to four invisible statements.

   6. No display:none, no visibility:hidden, no JS-injected text. Every
      statement is real DOM at all times and stays in the accessibility
      tree and in the document order of the argument.

   7. There is NO progress rail. The accumulating stack and the growing
      spine are the progress indicator. Do not reintroduce another.

   THE SPINE
   A hairline on the left carrying the four marks. It is drawn downward as
   each statement arrives — the argument is literally being drawn. All four
   marks are visible dim from the first frame: because the slots hold
   fixed positions, the stage would otherwise open on emptiness. The dim
   marks make the reserved space read as structure waiting to be filled,
   so the reader sees the SHAPE of a four-part argument before it is made.
   The spine grows via scaleY on a 1px rule, so it composites.

   COLOUR
   Every value is a main.css token: --text, --muted, --accent, --line.
   The dim ink, the spine and the past state are mixed from those with
   color-mix() rather than written as rgba literals, so they cannot drift
   from the band. Each has a flat fallback first for browsers without
   color-mix(); those lose only the transparency.
   ========================================================================== */

.home-thesis {
  /* ---- The two numbers worth tuning ---------------------------------- */

  /* PAST-STATE CONTRAST. 0.65 of --text over .band--dark measures 6.2:1
     (5.8:1 over the band's lightest corner) — AA for body text with room
     to spare. Lower this and re-check before shipping. */
  --thesis-past: 0.65;

  /* THE 04 SIZE STEP. The only size change in the section. */
  --thesis-step-04: 1.5;

  /* ---- Type ---------------------------------------------------------- */

  /* One size for 01-03. Monumental type is no longer possible now that all
     four statements coexist. At 1440 this resolves to 2.2vw = 31.68px. */
  --thesis-size: clamp(1.35rem, 2.2vw, 2.1rem);
  --thesis-size-04: calc(var(--thesis-size) * var(--thesis-step-04));
  /* THE MEASURE — no line of copy is ever allowed to be cut, so this is
     sized from the copy rather than from a comfort rule of thumb.
     Measured against the real face (DM Sans 300, -0.03em tracking) at the
     1440 size of 31.68px, the longest lines advance:
       01 lead     "More documentation. …taskforces."   944px  ← the longest
       03 verdict  "Today you search …across them."     836px
       02 lead     "Complexity cannot be managed."      ~410px
     The old 840px cap wrapped both of the top two. 1020px clears the
     longest with ~8% of headroom for font fallback, and is the widest value
     the copy can actually use — past it the extra width is empty, and the
     line gets harder to track for nothing. There is room: at 1440 the
     section leaves 1332px inside its padding and the gutter.
     80vw is what carries that cap down through the mid widths. */
  --thesis-measure: clamp(280px, 80vw, 1020px);
  /* Gap between a statement's lead and its verdict. They are one thought
     at one size, so this is a hair, not a paragraph break. */
  --thesis-line-gap: 0.2em;

  /* ---- Rhythm -------------------------------------------------------- */

  /* The gutter the spine and the marks live in. */
  --thesis-gutter: clamp(42px, 5vw, 76px);
  --thesis-slot-gap: clamp(28px, 5.4vh, 58px);

  /* ---- Mixed ink ----------------------------------------------------- */

  --thesis-past-ink: #b6bcc6;
  --thesis-past-ink: color-mix(in srgb, var(--text) calc(var(--thesis-past) * 100%), transparent);
  /* The dim mark, before its statement arrives. 34% of --text over
     .band--dark lands near 2.3:1 — well under text minimums, which is
     correct: the marks are aria-hidden decoration and the statements carry
     all the meaning. It is still plainly visible as a hairline shape, not a
     ghost; raise the 34% if a future band ground is lighter. */
  --thesis-dim: #6b7789;
  --thesis-dim: color-mix(in srgb, var(--text) 34%, transparent);
  --thesis-spine-ink: rgba(255, 255, 255, 0.16);
  --thesis-spine-ink: color-mix(in srgb, var(--text) 16%, transparent);

  position: relative;
}

/* ---- The stack (default: no JS, JS error, or reduced motion) ----------- */

.home-thesis__stage {
  position: relative;
}

/* The four statements, and the spine behind them. The spine is a child of
   this box rather than of the stage, so it stops at statement 04. */
.home-thesis__stack {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--thesis-slot-gap);
}

.home-thesis__spine {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--thesis-spine-ink);
  /* Full length by default: with no JS the whole argument is already on the
     page, so the spine has nothing left to draw. */
  transform: scaleY(1);
  transform-origin: top center;
}

.home-thesis__statement {
  position: relative;
  padding-left: var(--thesis-gutter);
  max-width: calc(var(--thesis-measure) + var(--thesis-gutter));
}

/* ---- The gutter marks ------------------------------------------------- */

/* Four hairline glyphs in place of the old 01-04 numerals: ✕ (this does not
   work), ? (you do not understand it), a bulb outline (the insight), ✓
   (solved). Drawn as inline stroke SVG in the site's line style, never as
   emoji or filled icons. Every stroke is currentColor, so the mark inherits
   its statement's state colour and needs no per-state colour rule of its
   own. All four are visible dim from the first frame — the reserved space
   has to read as the shape of a four-part argument, not as emptiness. */
.home-thesis__mark {
  position: absolute;
  left: 0;
  display: block;
  padding-left: 12px;
  /* The mark carries no text, but it inherits the statement's type size so
     that the em in `top` below resolves against the line it aligns to. */
  font-size: var(--thesis-size);
  line-height: 1;
  /* Optically on the first line's cap height rather than on its box.
     0.625em is half the 1.25 line-height; in DM Sans at this size the
     line-box centre and the cap-height centre coincide to within a pixel
     (baseline ~30.7px, cap top ~8.5px at 1440), so this lands the mark on
     the cap rather than merely inside the box. */
  top: calc(0.625em - (var(--thesis-mark-size) / 2));
  /* MARK SIZE — tune here. */
  --thesis-mark-size: 19px;
  /* Stacked default (JS-off, JS error, reduced motion): full ink, because
     in that fallback the whole argument is already made. The pinned layout
     below is what dims the not-yet-arrived marks. */
  color: var(--text);
  transition: color 0.45s ease, opacity 0.4s ease, transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.home-thesis__mark svg {
  display: block;
  width: var(--thesis-mark-size);
  height: var(--thesis-mark-size);
  stroke: currentColor;
}

/* Statement 04 steps up in type, so its mark steps up with it. */
.home-thesis__statement--conclusion .home-thesis__mark {
  --thesis-mark-size: 23px;
  font-size: var(--thesis-size-04);
  /* 04's line-height is 1.18, not 1.25. */
  top: calc(0.59em - (var(--thesis-mark-size) / 2));
  /* The section's resting place. In the stacked default the argument is
     already over, so the checkmark is already teal. */
  color: var(--accent);
}

.home-thesis__lead,
.home-thesis__verdict {
  /* -0.03em is the site's display tracking (see .token-h1). */
  letter-spacing: -0.03em;
  line-height: 1.25;
  font-weight: 300;
  font-size: var(--thesis-size);
  text-wrap: pretty;
  margin: 0;
  transition: color 0.45s ease;
}

.home-thesis__lead {
  color: var(--muted);
  margin-bottom: var(--thesis-line-gap);
}

.home-thesis__verdict {
  color: var(--text);
}

/* Statement 04: the crescendo, and the only size change in the section. */
.home-thesis__statement--conclusion .home-thesis__lead,
.home-thesis__statement--conclusion .home-thesis__verdict {
  font-size: var(--thesis-size-04);
  line-height: 1.18;
  letter-spacing: -0.035em;
}

/* The teal cursor. In the stacked default it is lit on 04 only — the
   argument is over, so the cursor is already at rest. */
.home-thesis__accent {
  color: inherit;
  transition: color 0.45s ease;
}

.home-thesis__statement--conclusion .home-thesis__accent,
.home-thesis__accent--hold {
  color: var(--accent);
}



/* ---- The pinned layout (JS present, motion allowed) -------------------- */

.home-thesis--pinned {
  /* THE RUNWAY. Four beats share (min-height - stage height) of scroll.
     300vh cost ~50vh a beat — four or five wheel notches before the first line
     moved. 200vh brought it to ~27vh. Reported still slow on a Windows laptop,
     where a notch travels less than a Mac trackpad flick, so 160vh: the track
     is about 70vh and a beat lands every ~17vh, a notch and a half.

     The arrival transition came down with it. At 0.55s a beat could arrive
     while the next was already being scrolled to, which reads as lag rather
     than as pacing — the two numbers have to move together, and this is the
     floor for both. Below it a single flick outruns the fade and skips a
     statement outright. TUNE THE RUNWAY HERE. */
  min-height: 160vh;
}

.home-thesis--pinned .home-thesis__stage {
  position: sticky;
  top: var(--nav-h, 80px);
  height: calc(100vh - var(--nav-h, 80px));
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
}

/* The spine is drawn downward. --thesis-spine is set by the JS to the
   fraction of the stack the argument has reached; the four marks are
   already there, dim, waiting for it. */
.home-thesis--pinned .home-thesis__spine {
  transform: scaleY(var(--thesis-spine, 0.06));
  transition: transform 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: transform;
}

/* Statements stay in normal flow, at the positions they will hold for the
   whole section. Only opacity, transform and colour move — so nothing
   already read can drift, and there is no reflow to schedule.

   The fade is carried by the lead and the verdict rather than by the
   statement box, because the gutter mark is a child of the box and has to
   stay visible (dim) while its statement is still in the future. The two
   paragraphs share one transition, so they arrive as one thought. */
.home-thesis--pinned .home-thesis__lead,
.home-thesis--pinned .home-thesis__verdict {
  opacity: 0;
  transform: translateY(1.5rem);
  transition: opacity 0.38s ease, transform 0.38s ease, color 0.32s ease;
  will-change: opacity, transform;
}

.home-thesis--pinned .home-thesis__statement[data-state="future"] .home-thesis__lead,
.home-thesis--pinned .home-thesis__statement[data-state="future"] .home-thesis__verdict {
  opacity: 0;
  transform: translateY(1.5rem);
}

/* PRESENT. The only teal on screen. */
.home-thesis--pinned .home-thesis__statement[data-state="present"] .home-thesis__lead,
.home-thesis--pinned .home-thesis__statement[data-state="present"] .home-thesis__verdict {
  opacity: 1;
  transform: translateY(0);
}

.home-thesis--pinned .home-thesis__statement[data-state="present"] .home-thesis__lead {
  color: var(--muted);
}

.home-thesis--pinned .home-thesis__statement[data-state="present"] .home-thesis__verdict {
  color: var(--text);
}

.home-thesis--pinned .home-thesis__statement[data-state="present"] .home-thesis__accent {
  color: var(--accent);
}

/* The marks under the pinned layout.

   The mark lives inside the statement, and the statement's FADE is what
   would hide it — so under the pinned layout the fade is carried by the
   lead and the verdict instead of by the statement box (see above). The
   statement box itself never changes opacity, which is what lets all four
   marks be dim and on screen from the very first frame. */
.home-thesis--pinned .home-thesis__mark {
  /* Dim before any state is set, so the first frame is already structure. */
  color: var(--thesis-dim);
}

.home-thesis--pinned .home-thesis__statement[data-state="present"] .home-thesis__mark {
  color: var(--text);
  /* A cheap settle rather than a stroke-dash draw-on, so the dim-from-the
     -first-frame requirement is never at the mercy of a dash offset. */
  transform: scale(1.06);
}

/* 04's checkmark goes teal when it arrives and stays teal: the only teal
   mark in the section, and the only element that keeps its teal after the
   cursor has passed on. */
.home-thesis--pinned .home-thesis__statement--conclusion[data-state="present"] .home-thesis__mark,
.home-thesis--pinned .home-thesis__statement--conclusion[data-state="past"] .home-thesis__mark {
  color: var(--accent);
}

.home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__mark {
  color: var(--thesis-dim);
  transform: none;
}

/* PAST. Readable, uniform, and the teal is released. The lead/verdict
   colour split is dropped on purpose: a superseded statement is one grey
   block of settled argument, and a dimmed-lead-on-top-of-a-dim-verdict
   would put the lead under 4.5:1. */
.home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__lead,
.home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__verdict {
  opacity: 1;
  transform: translateY(0);
}

.home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__lead,
.home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__verdict,
.home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__accent {
  color: var(--thesis-past-ink);
}

/* The one accent that does NOT release: statement 03's "reason across them"
   holds its teal once superseded, so that by the last screen it stands lit
   beside 04's "what PULSAR does." The need and the answer are the only two
   teal phrases left, which is what makes the conclusion legible. Same
   specificity as the release rule above, so it must stay after it. */
.home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__accent--hold {
  color: var(--accent);
}

/* ---- Narrow ----------------------------------------------------------- */

@media (max-width: 720px) {
  .home-thesis {
    --thesis-gutter: 40px;
    --thesis-line-gap: 0.24em;
  }

  .home-thesis__mark {
    padding-left: 10px;
    --thesis-mark-size: 17px;
  }

  .home-thesis__statement--conclusion .home-thesis__mark {
    --thesis-mark-size: 20px;
  }
}

/* ---- Short viewport --------------------------------------------------- */

/* On a ~600px-tall landscape phone the stack risked outgrowing the stage.
   Type and rhythm step down together so it keeps clearing. */
@media (max-height: 700px) {
  .home-thesis {
    --thesis-size: clamp(1.15rem, 1.7vw, 1.6rem);
    --thesis-step-04: 1.4;
    --thesis-slot-gap: clamp(16px, 2.8vh, 26px);
    --thesis-gutter: clamp(38px, 4vw, 60px);
  }


}

/* ---- Reduced motion: back to the stack, in CSS as well as in JS ------- */

/* The JS returns before adding .home-thesis--pinned, so this only matters
   if the user turns reduced motion ON mid-visit. It has to undo every
   pinned rule above. */
@media (prefers-reduced-motion: reduce) {
  .home-thesis--pinned {
    min-height: 0;
  }

  .home-thesis--pinned .home-thesis__stage {
    position: static;
    height: auto;
    display: block;
    overflow: visible;
  }

  .home-thesis--pinned .home-thesis__spine {
    transform: scaleY(1);
    transition: none;
  }

  .home-thesis--pinned .home-thesis__lead,
  .home-thesis--pinned .home-thesis__verdict,
  .home-thesis--pinned .home-thesis__statement[data-state="future"] .home-thesis__lead,
  .home-thesis--pinned .home-thesis__statement[data-state="future"] .home-thesis__verdict,
  .home-thesis--pinned .home-thesis__statement[data-state="present"] .home-thesis__lead,
  .home-thesis--pinned .home-thesis__statement[data-state="present"] .home-thesis__verdict,
  .home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__lead,
  .home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__verdict {
    opacity: 1;
    transform: none;
    transition: none;
  }

  /* Full present-state colour for every statement, teal on 04 only —
     the same place JS-off lands. */
  .home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__lead {
    color: var(--muted);
  }

  .home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__verdict {
    color: var(--text);
  }

  .home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__accent,
  .home-thesis--pinned .home-thesis__statement[data-state="present"] .home-thesis__accent {
    color: inherit;
  }

  .home-thesis--pinned .home-thesis__statement--conclusion .home-thesis__accent,
  .home-thesis--pinned .home-thesis__accent--hold {
    color: var(--accent);
  }

  /* Marks at full ink too, teal on 04 only — the same place JS-off lands. */
  .home-thesis--pinned .home-thesis__mark,
  .home-thesis--pinned .home-thesis__statement[data-state="future"] .home-thesis__mark,
  .home-thesis--pinned .home-thesis__statement[data-state="present"] .home-thesis__mark,
  .home-thesis--pinned .home-thesis__statement[data-state="past"] .home-thesis__mark {
    color: var(--text);
    transform: none;
    transition: none;
  }

  .home-thesis--pinned .home-thesis__statement--conclusion .home-thesis__mark {
    color: var(--accent);
  }
}


/* THE CHAPTER LABEL. "The Challenge" above, "The shift" here: the two bands
   are a matched pair, the problem and the turn away from it, which "What we
   do" on the platform band below then answers. It sits
   inside the pinned stage, so it holds for all four statements — see the
   comment on the markup in index.html. Flush with the statements' own left
   edge, and quiet enough that statement 01 is still the first thing read. */
.home-thesis__eyebrow{margin-bottom:clamp(20px,3vh,40px);opacity:.85}
