/* ══ WALKTHROUGHS ════════════════════════════════════════════════════════════════════════════
   A demo shows that a thing exists. A walkthrough shows a person doing something.

   ── WHY THIS EXISTS, MEASURED RATHER THAN ASSERTED ─────────────────────────────────────────
   releases.html carries 120 hand-built demos. Rendered and counted:

     rdSlide alone          50 demos   42%
     rdIn alone             29 demos   24%
     no animation at all     7 demos
     top 3 signatures       86/120     72%
     slide + fade + rise   339 of 372 animated elements   91%

   rdType, rdPop, rdPulse and rdCaret animate exactly one element each across the whole page.

   So: 120 bespoke compositions, and nine tenths of the motion is one gesture — things arriving.
   None of them shows a click, a route change, or a person choosing between two options. "They all
   look the same" is not a matter of taste; it is what the numbers say.

   ── WHAT A WALKTHROUGH IS ──────────────────────────────────────────────────────────────────
   An ordered list of STEPS. Each step names the action a person took and shows the state that
   resulted. The motion between two steps is a TRANSITION, not a reveal — the difference is that a
   reveal has no before, so it can only ever say "here it is", which is the thing being complained
   about.

   Three rules the old demos broke:
     1. Every step has a caption in the user's voice — what they did, not what the system did.
     2. The chrome is visible and it CHANGES. If a step navigates, the location line changes with
        it. That is what "shows navigations" means.
     3. The last frame is not the point. You can stop, go back, and re-read any step.

   ── MOTION IS NEVER LOAD-BEARING (ADR-0058) ────────────────────────────────────────────────
   Under prefers-reduced-motion, and with no JavaScript at all, every step renders as a numbered
   list — the whole journey readable at once, nothing hidden behind a transition. The stepped
   version is the enhancement; the list is the floor.                                            */

.gw{
  border-top:2px solid var(--text);
  padding-top:0;
  margin:26px 0;
  font-family:var(--f-fur,system-ui,sans-serif);
}

/* ── the bar: location + controls ──────────────────────────────────────────────────────────── */
.gw-bar{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  border-bottom:1px solid var(--line);padding:10px 0;
}
/* The location line. It is furniture, and it MOVES — that is the whole point of showing it. */
.gw-where{
  font-family:var(--f-num,ui-monospace,monospace);font-size:12px;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;flex:1 1 140px;
}
.gw-where b{color:var(--text);font-weight:500}

.gw-ctrls{display:flex;align-items:center;gap:6px;margin-inline-start:auto}
.gw-ctrls button{
  font:inherit;font-size:12px;font-weight:600;letter-spacing:.02em;
  background:transparent;color:var(--text);border:1px solid var(--line-firm);border-radius:0;
  /* 36, not 32. These six — prev/play/next on two walkthroughs — were the only tap targets on the
     homepage failing `check-ui.mjs`, at exactly 32px against its 34px floor, and they failed it in
     all three themes because the cause is geometry rather than colour. Two pixels short is still
     short: WCAG 2.5.5 asks for 44 and this check settles for 34, so 36 clears it without pushing
     the control row into the headline beside it. `min-height` alone was already here — the value
     was simply set below the bar the deploy enforces. */
  min-height:36px;min-width:36px;padding:0 10px;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;gap:5px;
}
/* Gated: :hover latches after a tap on touch, so a pressed control stays lit until you press
   another one. Motion QA #11. The focus-visible rule below gives the keyboard the same signal. */
@media (hover:hover) and (pointer:fine){
  .gw-ctrls button:hover:not(:disabled){border-color:var(--text)}
}
.gw-ctrls button:disabled{opacity:.38;cursor:default}
.gw-ctrls button:focus-visible{outline:2px solid var(--text);outline-offset:2px}
.gw-play{background:var(--text)!important;color:var(--bg)!important;border-color:var(--text)!important}
.gw-count{
  font-family:var(--f-num,ui-monospace,monospace);font-variant-numeric:tabular-nums;
  font-size:11px;color:var(--muted);min-width:52px;text-align:center;
}

/* ── the step rail ─────────────────────────────────────────────────────────────────────────
   The identity's rail, used for what it means: how far through you are, and how much of the
   journey has actually been shown to you. Weight and texture, never hue. */
.gw-rail{display:flex;gap:3px;padding:10px 0 0}
.gw-rail i{flex:1;height:3px;background:var(--line);transition:background .2s;
  position:relative;overflow:hidden}
.gw-rail i.done{background:var(--line-firm)}

/* ── the current segment: a clock, not a decoration ────────────────────────────────────────
   It used to be `background:var(--text)` under a `transition:background .2s`, so the segment
   went fully dark in 200ms and then sat still for the remaining 2,800ms of a 3,000ms dwell.
   That reads as a progress bar that has finished while the step it measures has barely started
   — the rail was making a claim about time that was false for 93% of every step.

   Now the fill sweeps across the ACTUAL dwell, so the bar answers "how long until the next
   step" honestly. `--gw-hold` is written by glance-walk.js from the same `data-hold` the timer
   uses, so there is one number and the bar cannot drift from the thing it is measuring.

   PAUSED AND MANUAL STEPPING SHOW A SOLID SEGMENT, NOT AN EMPTY ONE. When no timer is running
   there is no time left to represent, and a bar creeping toward a step that will never arrive
   on its own is the same lie in the other direction. Solid = "you are here"; sweeping = "and
   this is how long you have". `scaleX` on a pseudo-element composites (Motion QA #8) — the
   earlier `background` transition did not. */
.gw-rail i.now{background:var(--line-firm)}
.gw-rail i.now::after{
  content:"";position:absolute;inset:0;background:var(--text);
  transform-origin:left center;transform:scaleX(1);
}
.gw.gw-playing .gw-rail i.now::after{animation:gwFill var(--gw-hold,3000ms) linear both}
@keyframes gwFill{from{transform:scaleX(0)}to{transform:scaleX(1)}}

/* ── the stage ─────────────────────────────────────────────────────────────────────────────── */
/* min-height here is only the pre-measurement floor — it stops the stage collapsing in the frames
   before script runs. The REAL reservation is written inline by glance-walk.js's reserve(), which
   measures the tallest step so a flip cannot resize the stage. Do not tune this number expecting it
   to fix a layout shift; it is not the one that governs. */
.gw-stage{position:relative;padding:20px 0 0;min-height:150px}
.gw-step{display:none}
.gw-step.on{display:block}

/* The caption is the user's voice: "Clicked the Friday bar", not "The drill page opens". */
.gw-say{
  display:flex;gap:10px;align-items:baseline;
  font-size:13px;line-height:1.55;color:var(--text);margin:0 0 14px;
}
.gw-say .n{
  font-family:var(--f-num,ui-monospace,monospace);font-size:11px;color:var(--accent);
  border-top:2px solid var(--accent);padding-top:4px;flex:0 0 auto;min-width:18px;
}
.gw-say .what{max-width:62ch}
.gw-say .what em{font-style:normal;color:var(--muted)}

/* The screen being walked through. A rule and a ground — not a card, not a browser chrome
   illustration, because a fake browser frame is decoration that claims to be a screenshot. */
.gw-screen{border:1px solid var(--line);background:var(--panel,#fff);padding:16px;min-height:96px}
/* The click target. An INSET ring in --text was invisible the moment the target was itself dark —
   which the highlighted bar always is, because being dark is how it is highlighted. An outline in
   the accent sits outside the box, so it reads on any ground. Caught in a screenshot, not a test. */
.gw-screen .gw-hl{outline:2px solid var(--accent);outline-offset:2px}

/* ── the pointer ───────────────────────────────────────────────────────────────────────────
   Shows WHERE the click landed. It is a mark, not a cursor illustration: a ring that lands on the
   target and stays for the length of the step, so a paused walkthrough still says what was hit. */
.gw-hit{position:absolute;width:26px;height:26px;border:2px solid var(--accent);border-radius:50%;
  pointer-events:none;transform:translate(-50%,-50%);opacity:0}
.gw-step.on .gw-hit{opacity:1;animation:gwHit .4s cubic-bezier(.22,1,.36,1)}
@keyframes gwHit{from{transform:translate(-50%,-50%) scale(1.9);opacity:0}}

/* Transitions between steps: the OUTGOING state is still there for a beat, which is what makes it
   read as a change rather than an arrival. Deliberately short — this is punctuation, not theatre. */
.gw-step.on .gw-screen{animation:gwStep .26s ease-out .04s both}
@keyframes gwStep{from{opacity:.35;transform:translateY(3px)}}

/* THE CAPTION USED TO HAVE NO ANIMATION AT ALL — which is what made a step change read as a hard
   cut rather than a transition. Measured frame-by-frame on the live homepage: at the 2→3 flip,
   7.53s was fully step 2 and 7.60s fully step 3, caption included. `.gw-screen` was carrying the
   whole transition on its own while the sentence above it — the part you actually read — swapped
   between two frames.

   Same `gwStep` gesture, not a second one invented beside it (the motion skill's first rule). The
   caption leads and the card follows 40ms later, matching reading order: you take in the sentence,
   then the state it produced. Both are `both`-filled so the pair holds its start frame during the
   delay instead of flashing at full opacity first. */
.gw-step.on .gw-say{animation:gwStep .26s ease-out both}

/* The location line changes by innerHTML, so each step builds a NEW <b> — which restarts this
   animation for free, with no class toggling and no JS in the path. It was the third thing the
   frame-by-frame caught swapping instantly. */
.gw-where b{animation:gwStep .26s ease-out both}

/* ── reduced motion, and no JavaScript ─────────────────────────────────────────────────────
   Both land in the same place on purpose: every step visible, numbered, in order. The controls are
   hidden under reduced motion because there is nothing left to control — you are already looking
   at the whole journey. */
/* In the floor view every step must carry its OWN location, or the one thing the stepped version
   adds — showing a route change — is exactly what the fallback drops. attr() does it with no
   script, so the floor keeps the feature rather than a summary of it. */
/* The floor needs the same treatment: a step with no location prints nothing, which in a numbered
   list reads as a missing line rather than a deliberate one. Only steps that navigate print. */
.gw-step[data-where]::before{
  content:attr(data-where);display:none;
  font-family:var(--f-num,ui-monospace,monospace);font-size:11px;color:var(--muted);
  margin-bottom:8px;overflow-wrap:anywhere}
@media (prefers-reduced-motion:reduce){
  .gw-step[data-where]::before{display:block}
  .gw-step{display:block!important;border-top:1px solid var(--line);padding-top:16px;margin-top:16px}
  .gw-step:first-of-type{border-top:0;margin-top:0}
  .gw-ctrls,.gw-rail{display:none}
  /* Every animation this file can start, named explicitly. The rail is display:none here so its
     fill could not run anyway — it is listed because a guard that depends on a display rule three
     lines above it is a guard that breaks the day someone shows the rail. */
  .gw-hit,
  .gw-step.on .gw-screen,
  .gw-step.on .gw-say,
  .gw-where b,
  .gw.gw-playing .gw-rail i.now::after{animation:none}
  .gw-rail i.now::after{transform:scaleX(1)}
  .gw-hit{opacity:1}
}
/* Script sets .gw-js on <html>. Until then — and forever, if script never runs — every step is
   shown. The stepped view is the enhancement; the list is the floor. Same shape as the demos'
   js-demos flag, which had to be retrofitted after 270 elements went invisible without script. */
html:not(.gw-js) .gw-step[data-where]::before{display:block}
html:not(.gw-js) .gw-step{display:block;border-top:1px solid var(--line);padding-top:16px;margin-top:16px}
html:not(.gw-js) .gw-step:first-of-type{border-top:0;margin-top:0}
html:not(.gw-js) .gw-ctrls,html:not(.gw-js) .gw-rail{display:none}

@media(max-width:520px){
  .gw-bar{gap:8px}
  .gw-where{flex:1 1 100%;order:2}
  .gw-ctrls{margin-inline-start:0}
}
