/* ============================================================
   RESPECT letters — the Carriage device

   The seven letters sit on a rail, and a single jade carriage slides
   beneath them as the reader travels the principles. The letter it
   stops under swells; its neighbours ease aside to make room.

   Why a rail with one moving carriage instead of a row of numbered
   circles: a circle-per-stage says "seven separate things." A rail
   with one moving carriage says "one method, seven positions" — which
   is what the client's own copy says.

   The number is gone from the letters entirely. It survives as the
   caption's "Stage 3 of 7", where it is read as language rather than
   competing as a graphic on the letter itself.

   ⚠️ The bundled Fraunces/Inter subsets carry a 400–600 weight axis
   only (tokens.css:31,41,51). Any "thin → black" letter-weight effect
   is impossible here without shipping another font file, so the motion
   is carried by scale, tracking and the carriage instead.
   ============================================================ */

.rlx {
  margin-bottom: var(--space-2xl);
}

.rlx--carriage .rlx__word {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: clamp(0.1rem, 1.4vw, 0.9rem);
  margin: 0;
  padding: 0 0 1.15rem;
}

.rlx--carriage .rlx__letter {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 600;
  font-size: clamp(2.8rem, 10vw, 7rem);
  line-height: 0.9;
  letter-spacing: 0;
  text-decoration: none;
  color: var(--jade-500);
  transform-origin: 50% 100%;
  /* font-size is in the transition list because .is-stuck flips it once,
     at the moment the bar sticks — a single threshold toggle, the same
     pattern .site-header.is-scrolled already uses, not a value the scroll
     handler writes every frame. */
  transition:
    color var(--dur-mid) var(--ease-soft),
    transform var(--dur-mid) var(--ease-out),
    font-size var(--dur-fast) var(--ease-out);
}

.rlx--carriage .rlx__letter.is-active,
.rlx--carriage .rlx__letter:hover,
.rlx--carriage .rlx__letter:focus-visible {
  color: var(--jade-300);
  transform: scale(1.28) translateY(-0.02em);
}

/* Dock easing: the letters either side of the active one give way a
   little, so the swell reads as displacement rather than overlap. */
.rlx--carriage .rlx__letter.is-neighbour {
  transform: scale(1.06);
  color: var(--jade-400);
}

.rlx--carriage .rlx__letter:focus-visible {
  outline: 2px solid var(--jade-300);
  outline-offset: 4px;
  border-radius: 2px;
}

/* ---------- The rail and its carriage ---------- */
.rlx__rail {
  position: relative;
  height: 2px;
  margin: 0 auto;
  background: linear-gradient(90deg, transparent, var(--ink-700) 6%, var(--ink-700) 94%, transparent);
}

.rlx__carriage {
  position: absolute;
  top: -1px;
  left: 0;
  width: 3rem;
  height: 4px;
  border-radius: 2px;
  background: var(--jade-400);
  box-shadow: 0 0 1.2rem rgba(95, 201, 172, 0.45);
  transform: translateX(0);
  /* box-shadow rides the same easing as the move so the glow reads as a
     trailing streak rather than a glow that snaps into a new position. */
  transition: transform var(--dur-mid) var(--ease-soft),
    width var(--dur-mid) var(--ease-soft),
    box-shadow var(--dur-fast) var(--ease-out);
}

/* A hairline drop from the carriage to the section it points at —
   the one piece of ornament, and it is load-bearing: it says "this
   letter belongs to the row below." */
.rlx__carriage::after {
  content: "";
  position: absolute;
  top: 4px;
  left: 50%;
  width: 1px;
  height: 0.9rem;
  background: linear-gradient(180deg, var(--jade-400), transparent);
}

/* ---------- Caption ---------- */
.rlx__caption {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.5rem;
  min-height: 2.6em;
  margin: 0;
  padding-top: 1rem;
  text-align: center;
}

.rlx__caption-step {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-500);
}

.rlx__caption-text {
  font-family: var(--font-sans);
  font-size: var(--step-0);
  color: var(--text-300);
  transition: opacity var(--dur-fast) var(--ease-out);
}

.rlx__caption.is-swapping .rlx__caption-text { opacity: 0; }

/* ============================================================
   Sticky table of contents

   Once the reader scrolls past the device it holds under the header
   and behaves as a table of contents: the letter for the row on screen
   lights up, and the rail fill behind the carriage says how far through
   the seven the reader is. It lets go on its own after the last row —
   position: sticky stops holding once its containing block (.rlx-scope)
   runs out, so "unstick after the last letter" comes from the box
   model instead of scroll-position bookkeeping in JS.
   ============================================================ */

.rlx-scope {
  position: relative;
  /* JS keeps this in sync with the compacted bar's real height so the
     rows' scroll-margin-top below never has to guess it. */
  --rlx-bar: 8rem;
}

.rlx-scope__sentinel {
  display: block;
  height: 0;
}

.rlx {
  position: sticky;
  top: var(--rlx-top);
  z-index: 40; /* under .site-header (100), over the rows */
  /* margin-bottom already set above; only the sticky/holding behaviour
     is new here. */
  padding: 0 0 0.35rem;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    padding var(--dur-fast) var(--ease-out);
}

.rlx {
  --rlx-top: 68px; /* = .nav min-height; the site header is sticky above us */
}

/* Holding state. The rows scroll underneath, so the bar has to turn
   opaque enough to read against them and small enough to leave the
   rows room. */
.rlx.is-stuck {
  padding: 0.55rem 0 0.5rem;
  background: rgba(15, 27, 23, 0.92);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-bottom-color: var(--border-soft);
  box-shadow: 0 14px 30px -20px rgba(0, 0, 0, 0.9);
}

/* The held bar must not cover the row an anchor click lands on. */
.mindset__row--respect {
  scroll-margin-top: calc(var(--rlx-top, 68px) + var(--rlx-bar, 8rem) + 1.25rem);
}

/* The row being read is echoed on the row itself, so the highlight in
   the bar and the highlight on the page can never disagree. */
.mindset__row--respect.is-current {
  background: rgba(95, 201, 172, 0.05);
}
.mindset__row--respect.is-current .mindset__letter {
  color: var(--jade-300);
}

/* ---------- Carriage-specific: compact state ---------- */

.rlx--carriage.is-stuck .rlx__letter {
  font-size: clamp(1.4rem, 4.6vw, 2.6rem);
}
.rlx--carriage.is-stuck .rlx__word {
  padding-bottom: 0.7rem;
}
.rlx--carriage.is-stuck .rlx__caption {
  min-height: 0;
  padding-top: 0.55rem;
}
/* A compacted letter swelling to 1.28x would collide with its
   neighbours, so the held bar caps the swell lower. */
.rlx--carriage.is-stuck .rlx__letter.is-active,
.rlx--carriage.is-stuck .rlx__letter:hover,
.rlx--carriage.is-stuck .rlx__letter:focus-visible {
  transform: scale(1.16);
}

/* The hairline drop now points at a much shorter gap between the held
   bar and the row it is naming. */
.rlx--carriage.is-stuck .rlx__carriage::after {
  height: 0.55rem;
}

@media (max-width: 560px) {
  .rlx--carriage .rlx__letter { font-size: clamp(2.1rem, 13vw, 3.6rem); }
  .rlx--carriage .rlx__word { gap: 0.05rem; }
  .rlx__caption { min-height: 3.4em; }
}

@media (prefers-reduced-motion: reduce) {
  /* Sticky itself stays under reduced motion — it is layout, the
     navigation aid, not the animation. Only the morph is dropped. */
  .rlx { transition: none; }
  .rlx--carriage .rlx__letter,
  .rlx__carriage { transition: color 1ms linear; }
  .rlx--carriage .rlx__letter.is-active,
  .rlx--carriage .rlx__letter:hover,
  .rlx--carriage .rlx__letter:focus-visible,
  .rlx--carriage .rlx__letter.is-neighbour,
  /* .is-stuck raises specificity on the compact-state swell above the
     three rules this selector list already neutralises, so it needs its
     own line here or reduced motion would lose to it. */
  .rlx--carriage.is-stuck .rlx__letter.is-active,
  .rlx--carriage.is-stuck .rlx__letter:hover,
  .rlx--carriage.is-stuck .rlx__letter:focus-visible { transform: none; }
  .rlx__carriage { box-shadow: none; }
  .rlx__caption-text { transition: none; }
}
