/* Stage rail.
   Loaded only by the page that declares it. Every colour, rule, radius and type
   size comes from a token in assets/site.css, and none of them is hard-coded,
   so dropping the block inside `.sec-deep` inverts the whole thing without a
   single dark-ground override in this file.

   Two shapes share one set of markup:
     >= 901px   a sticky vertical index in the left column of a two-up grid.
     <= 900px   a horizontal strip of stage keys pinned under the site header,
                and a monospace key on every panel so the strip is a convenience
                rather than the only thing naming the stage.

   `.mono-label`, `.h-split`, `.sec-deep` and `--mono` are owned by site.css.
   This file uses them and never defines them. The one exception is the `--mono`
   fallback on `.sr-key`, which is a fallback inside `var()`, not a definition:
   the rail's monospace character is load-bearing and must not depend on
   stylesheet order. */

.sec-stagerail .sec-head { max-width: 66ch; }
.sec-stagerail .sec-head h2 { max-width: 24ch; }

/* ------------------------------------------------------------------- layout */
/* A grid, never an overlay. The rail can therefore never sit on top of the
   panels at any width: it owns a column of its own or it is not a rail. */
.stagerail {
  display: grid;
  grid-template-columns: minmax(0, 14.5rem) minmax(0, 1fr);
  gap: clamp(2rem, 3.4vw, 4.5rem);
  align-items: start;
}

/* Sticky inside `.stagerail`, not inside the viewport. The grid is the sticky
   containing block, so the rail pins when the stages arrive and releases the
   moment the last panel ends. `align-self:start` is what stops the grid from
   stretching the item to the row height, which would leave nothing to stick. */
.sr-rail {
  position: sticky;
  top: calc(var(--header-h) + 1.75rem);
  align-self: start;
  max-height: calc(100dvh - var(--header-h) - 3.5rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.sr-list {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}
/* The spine. It runs behind the markers, which carry the ground colour so the
   hollow ones read as rings rather than as beads on a thread. */
.sr-list::before {
  content: "";
  position: absolute;
  left: 5px;
  top: .95rem;
  bottom: .95rem;
  width: 1px;
  background: var(--line-2);
}

.sr-item { position: relative; }

.sr-link {
  display: flex;
  align-items: flex-start;
  gap: .85rem;
  padding: .55rem 0;
  text-decoration: none;
  color: var(--ink-3);
  transition: color .18s var(--ease), transform .18s var(--ease);
}
.sr-link:hover { color: var(--ink); }

/* Hollow ring by default, filled disc when current. Shape, not hue: the state
   survives greyscale, forced colours and a colour-blind reader. */
.sr-mark {
  flex: none;
  box-sizing: border-box;
  width: 11px;
  height: 11px;
  margin-top: .3rem;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  background: var(--paper);
  transition: transform .18s var(--ease), background-color .18s var(--ease);
}

.sr-txt { display: block; min-width: 0; }

/* `.mono-label` supplies the case, tracking and weight. Colour is taken from
   the link so the whole item lights as one thing, and the monospace family is
   restated with a literal fallback because the rail is unreadable as a stepper
   without it. */
.sr-link .sr-key {
  display: block;
  color: inherit;
  font-family: var(--mono, ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace);
  font-size: var(--t--2);
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  line-height: 1.5;
}
.sr-name {
  display: block;
  font-size: .9375rem;
  font-weight: 600;
  line-height: 1.35;
  color: inherit;
}

/* Current stage. Four cues, only one of which is colour. */
.sr-item.is-current .sr-link { color: var(--ink); transform: translateX(2px); }
.sr-item.is-current .sr-mark { background: currentColor; transform: scale(1.15); }
.sr-item.is-current .sr-key { font-weight: 700; }
.sr-item.is-current .sr-name { font-weight: 800; }

/* ------------------------------------------------------------------- panels */
.sr-stage { padding-block: clamp(1.6rem, 2.4vw, 2.4rem); }
.sr-stage:first-child { padding-top: 0; }
.sr-stage:last-child { padding-bottom: 0; }
.sr-stage + .sr-stage { border-top: 1px solid var(--line); }
/* Panels are `tabindex="-1"` so an in-page jump moves focus with the reader
   rather than stranding it on the rail link. That programmatic focus should not
   draw a box, but a keyboard user must still get the site's focus ring. */
.sr-stage:focus:not(:focus-visible) { outline: none; }

/* The rail carries the key on wide screens, so repeating it on the panel two
   inches away would be the same word twice. It comes back below 900px. */
.sr-stage-key { display: none; }

.sr-stage-title {
  font-size: var(--t-2);
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -.012em;
  margin: 0 0 .5em;
  max-width: 40ch;
}
.sr-stage > p { color: var(--ink-2); max-width: 64ch; }
.sr-stage .ticks { max-width: 64ch; }

/* -------------------------------------------------------- 900px and narrower */
/* Not a narrower rail. A different object: a horizontal strip of stage keys,
   pinned directly under the site header, with the stage name moved onto the
   panel it belongs to. */
@media (max-width: 900px) {
  .stagerail { display: block; }

  .sr-rail {
    position: sticky;
    top: var(--header-h);
    z-index: 5;
    max-height: none;
    overflow: visible;
    /* Bleed to the edges of the wrap so the pinned strip reads as a bar rather
       than as a floating card. The negative margin cancels the wrap's gutter
       exactly, so it can never push the page wider than the viewport. */
    margin-inline: calc(var(--gutter) * -1);
    margin-bottom: 1.75rem;
    background: var(--paper);
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
  }

  /* The gutter belongs to the scroller, not to the bar, so a chip scrolls all
     the way to the edge of the screen instead of being sliced off at an inset
     the reader cannot see. */
  .sr-list {
    display: flex;
    padding-inline: var(--gutter);
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .sr-list::-webkit-scrollbar { display: none; }
  .sr-list::before { display: none; }

  .sr-item { flex: none; }
  .sr-link {
    align-items: center;
    gap: .45rem;
    padding: .7rem .7rem .55rem;
    white-space: nowrap;
    border-bottom: 2px solid transparent;
    transform: none;
  }
  .sr-mark { width: 8px; height: 8px; margin-top: 0; }
  .sr-name { display: none; }

  .sr-item.is-current .sr-link {
    transform: none;
    border-bottom-color: currentColor;
  }

  /* Each panel now names its own stage, so a reader who scrolled past the strip
     still knows which one they are in. */
  .sr-stage-key {
    display: block;
    margin: 0 0 .5rem;
    color: var(--ink-3);
    font-family: var(--mono, ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace);
  }
  .sr-stage { padding-block: 1.6rem; }
  .sr-stage-title { max-width: none; }
}

/* Short viewports. site.css un-sticks the header here, so the rail follows it
   rather than pinning to an offset that no longer exists. */
@media (max-height: 520px) {
  .sr-rail {
    position: static;
    max-height: none;
    overflow: visible;
  }
}

/* Reduced motion. The rail is state, not motion: the resting frame is always a
   fully resolved stage, so killing the transitions leaves it correct rather
   than stranded. This is belt and braces over the blanket rule in site.css. */
@media (prefers-reduced-motion: reduce) {
  .sr-link,
  .sr-mark { transition: none; }
}
