/* reaction
   Split from the single v22 stylesheet. Everything here is scoped to
   .card.reaction and this form's own class prefix (rule 14: a change made for one
   card form is scoped to that form, by class). */
.card.open .dropviz{gap:8px}
.card.open .dropnums b{font-size:var(--fs-22)}
.card.open .dropnums strong{font-size:var(--fs-14)}

.dropviz{width:100%;height:100%;align-self:stretch;display:flex;flex-direction:column;gap:10px;justify-content:flex-start}
.dropnums{display:flex;justify-content:space-between;align-items:flex-end}
.dropnums b{font-size:35px;line-height:1.02;color:var(--ink)}
.dropnums strong{font-size:20px;color:var(--down)}

/* ---- v14 rule fixes ------------------------------------------------ */
/* C3: a continuous path is a line. C24: bounded to its own range. */
/* The band is symmetric around the anchor, so the anchor is always the exact
   middle of the plot -- a static rule, nothing for the JS to place. Without it
   a fixed scale is an empty box: the reader cannot see that the blank half
   above the line IS the statement (the day never traded above yesterday). */
.pathwrap{width:100%;flex:1;min-height:120px;display:block;position:relative}
/* Findings 07/01, s10 - the prior-close reference. Neutral, because a level is
   not a direction (C52), and --muted rather than --dim because it is a price a
   reader has to read. The dashes are a gradient, not stroke-dasharray: see the
   .pathviz note on what non-scaling-stroke does to dashes in this file. It
   arrives just ahead of the stroke, since it is what the stroke is measured
   against. */
.priceref{position:absolute;left:0;right:0;display:flex;align-items:center;gap:8px;
  transform:translateY(-50%);pointer-events:none;opacity:0;transition:opacity .34s ease-out}
.card.in .priceref{opacity:1;transition-delay:.18s}
.priceref i{flex:1;height:1px;
  background:repeating-linear-gradient(to right,var(--dim) 0 3px,transparent 3px 7px)}
/* The label is the first item in the rule's flex row, so the dashes begin
   AFTER it and the stroke has nothing to strike through. Dropping it below the
   rule instead put it in the path's first dip, which is the same collision the
   old start tag had. */
/* font-size and letter-spacing are what the v19 label pass in css/shell.css
   already computed here (.pathends span,.priceref span). Same fold as .runzero
   in forms/streak.css. */
.priceref span{font-size:var(--fs-12-5);letter-spacing:0;color:var(--muted);white-space:nowrap;flex:none}
/* The visual's own figure stack is the price a second time, now that the
   readout carries it. Lost in the consolidation and it printed twice. */
/* Was `.card.solo .X` (fe-009, docs/reviews/frontend-2026-09-03.md): the
   shell-wide solo layout, not this form. .dropnums and .pathwrap are inert
   elsewhere today because only reaction.js emits them, but .priceref comes
   from the shared, exported `viz.js priceRef()` -- the second solo form to
   call it would have silently inherited this padding. `:where()` adds the
   archetype check at zero specificity, so the compound selector is still
   (.card + .solo), same as before this rescoping. `drop` is the pre-rename
   archetype (FORM_ALIASES in index.html); no live batch carries it, but a
   card that does still gets the same rules a `reaction` card does. */
.card.solo:where([data-archetype="reaction"],[data-archetype="drop"]) .dropnums{display:none}
.card.solo:where([data-archetype="reaction"],[data-archetype="drop"]) .priceref{padding-left:15px}
/* The replay `.pathwrap`'s own touch-action/cursor rule lived here, a
   per-form copy of exactly what css/replay.css's `.rp-scan` now owns --
   found live on PR #46 (the coordinator, reading this file after the same
   rule was fixed for the other three forms): "it is a per-form copy of the
   decision `.rp-scan` now owns, which is the thing this lane exists to
   end." The replay `.pathwrap` (reaction.js's `replayMarkup`) carries
   `rp-scan` in its class list now, the same as the Poll's `.pl-plot`, the
   Index Change's `.ixc-plot` and the Earnings' `.ern-plot` -- one
   instrument, four callers, cursor included. The STATIC `.pathwrap`
   (visualReactionStatic, the eleven frozen batches with no replay block)
   never carried `rp-scan` and drew no JS listener either way, so losing
   this rule leaves it at the browser's own default touch-action/cursor --
   invisible in any captured frame (neither property paints a pixel), and
   nothing there ever read a pointer event to protect. */
/* The inspector's own layer -- `.rp-insp`, css/replay.css -- moved out this
   session so The Poll, The Index Change and The Earnings can carry it too
   (js/inspect.js). It used to be this form's own `.scrub`; nothing here
   changed about how it looks or behaves, only where its CSS lives. */

/* The bottom-right in-chart fast-forward used to be this form's own markup
   and CSS. Session 37's first cut moved it into the top-right transport
   instead (reviewer's ask was ONE control); the reviewer then watched that
   on the real Simulator and asked for skip back in this corner specifically
   ("I liked the fast forward being in the bottom right ... standardize
   that"). It is drawn here again, but as the shared button both this form
   and The Poll now carry -- `js/replay.js`'s `skipMarkup()`, appended
   inside `.pathwrap` in reaction.js, positioned by css/replay.css's
   `.rp-tp-skip` rather than by a rule of this form's own. Nothing to style
   here any more; see css/replay.css. */

/* --- the plot ----------------------------------------------------- */
.rpviz{width:100%;height:100%;align-self:stretch;
  display:flex;flex-direction:column;gap:10px;justify-content:flex-start}

/* One wipe, two consumers. The price line (css/replay.css's own `.rp-svg`
   rule) and the volume beneath it are revealed by the same custom property,
   which is what makes "volume appears alongside its bar" true by
   construction rather than by two timers that agree until one of them
   drifts. Volume is this form's own -- The Poll's stored series carries
   none -- so the second half of that shared rule stays here. */
.rp-vol{clip-path:inset(0 calc(100% - var(--rp-p,0%)) 0 0)}

/* The plot is inset to the same 15px as every caption in the panel, so the
   whole card has one left edge -- and so the close has somewhere to be. Run
   edge to edge, the last minutes of the session and the marker on them were
   cut off by the panel's own rounded corner, which is a chart losing the one
   point the card is about. The volume takes the identical inset because the
   two are read against each other by x position.

   .pathwrap is width:100% for the static Move, and 100% plus a margin is
   30px of overflow -- which is how the close ran off the panel in the first
   place. */
.rp-wrap,.rp-vol{width:auto;margin-left:15px;margin-right:15px}

/* The line, the previous-close rule and the end-of-line dot are all
   css/replay.css now -- `.rp-line`/`.rp-ref`/`.rp-dot`, the one instrument
   this form and The Poll both draw. --stance is still set live by
   initReplay through the same two classes the rest of the renderer uses,
   so the marker, the volume and the readout all turn at the same instant. */

/* --- volume ------------------------------------------------------- */
/* Absolutely positioned by time, not laid out by index. A flex row divides
   the width by the number of bars, which is only the same thing when no
   interval is missing -- and a session with a hole would silently stretch the
   bars either side of it to cover ground nothing traded in. */
/* Heights stay linear in shares. An intraday session really is a U -- SPY's
   median 5m bar is 4% of its busiest one -- and a percentile scale or a square
   root would make the middle of the day legible by making the bars stop being
   proportional to volume, which is the C53 mistake with a different axis. The
   strip's job is where the volume was, and it says that truthfully. */
.rp-vol{position:relative;height:32px;flex:none}
.rp-vol i{position:absolute;bottom:0;height:var(--h);min-height:1px;
  background:var(--stance-dim,var(--edge));display:block}
/* The plot and its volume run the full width of the panel; every caption is
   inset to the same 15px the readout above them uses. That is the static
   Move's arrangement (.card.solo .volcap/.tickrow) and there is no reason for
   the replay to hold a different left edge to the card it replaced -- without
   it "30.5m shares" and "4:00 PM" sat hard against the rounded corner. */
/* --- the figures ---------------------------------------------------
   Four facts the readout above the plot cannot carry, each on its own row.

   They were a caption, an axis and a three-column strip, all set at 12px in
   --dim: three different arrangements of small grey text stacked under the
   chart, and the four numbers the card is actually counting were the least
   legible things on it. Then they were four rows of one weight with an
   identical hairline under each -- which is a settings screen. Nothing on it
   was more important than anything else, so the payoff, the one figure the
   card exists to deliver, read as the fourth preference in a list.

   So: the payoff first, alone, because it is the chart's conclusion; then the
   other three as a strip divided by rules *between the columns* rather than
   under the rows. Equal thirds, because those three really are peers. 107px
   where the list was 164px, and the 57px goes back to the plot.

   The four <b> counters stay in the payload's order -- volume, high, low,
   stake -- and `order` does the moving, so the payoff leads the block without
   the DOM saying so and `.rp-figs b` still reads the same four values in the
   same sequence.

   The 9:30 AM / 4:00 PM axis is gone with them. The clock in the readout runs
   the session the whole way through and names the bell at both ends, so the
   axis was restating in static type what the card spends eight seconds
   saying. `visual.replay.ticks` is still in the payload and still drawn by
   the static Move's .tickrow; this form no longer uses it.

   Tabular figures AND a min-width on every box that is rewritten as the day
   plays. The previous pass claimed "fixed tabular figures throughout" and was
   wrong: the values had them, the clocks in the <em> never did, so
   "9:40 AM" -> "12:35 PM" moved its own box by 9.5px and the volume total and
   the stake swung 11px each on HOOD as they gained a digit. A comment
   asserting a property the CSS did not have. Measured now, not asserted:
   one distinct width per box across the whole session, on all four cards. */
.rp-figs{display:flex;flex-direction:column;margin:6px 15px 0}
.rp-bar{order:0;display:flex;justify-content:space-between;align-items:baseline;
  gap:12px;padding-top:12px;border-top:1px solid var(--line);
  font-size:var(--fs-14);font-weight:600;color:var(--muted)}
.rp-bar b{font-size:var(--fs-29);font-weight:700;color:var(--ink);line-height:1;
  font-variant-numeric:tabular-nums;letter-spacing:var(--ls-n02);
  min-width:120px;text-align:right}
/* Equal thirds, so a figure that gains a digit grows inside its own column
   and nothing beside it moves. */
.rp-cols{order:1;display:grid;grid-template-columns:repeat(3,1fr);
  margin-top:16px;padding-top:13px;border-top:1px solid var(--line)}
.rp-col{display:flex;flex-direction:column;gap:3px;padding-left:11px}
.rp-col:first-child{padding-left:0}
.rp-col + .rp-col{border-left:1px solid var(--line);margin-left:1px}
.rp-clab{font-size:var(--fs-11);font-weight:600;color:var(--dim);white-space:nowrap}
.rp-clab em{font-style:normal;font-weight:400;font-variant-numeric:tabular-nums;
  display:inline-block;min-width:60px;margin-left:5px}
.rp-col b{font-size:16px;font-weight:700;color:var(--ink);line-height:1.15;
  font-variant-numeric:tabular-nums;letter-spacing:var(--ls-n01)}

/* Inspection is a post-playback affordance. Offering the crosshair while the
   line is still being drawn invites a drag that fights the animation --
   css/replay.css's `.rp-scan{cursor:default}` / `[data-rp=done|reduced]
   .rp-scan{cursor:crosshair}` owns that gate now (js/replay.js's header,
   "the walk"), and reaction.js's `.pathwrap` has carried the `rp-scan`
   class since e48b1f1. The two per-state rules that lived here
   (`.card.replay .pathwrap{cursor:default}` /
   `.card.replay[data-rp=done|reduced] .pathwrap{cursor:crosshair}`) were a
   second declaration of exactly that, at higher specificity but the same
   value in both states -- (0,2,0)/(0,4,0) here against `.rp-scan`'s
   (0,1,0)/(0,3,0), `default` vs `default` and `crosshair` vs `crosshair` --
   so removing them changes no computed cursor, only which rule a reader of
   the CSS has to trust. */
.card.replay .pathwrap:focus-visible{outline:2px solid var(--muted);outline-offset:3px}

/* --- the honest failure ------------------------------------------- */
.rp-invalid{display:flex;flex-direction:column;width:100%;min-height:0}
/* A replay block the renderer cannot trust draws the static session path and
   says so, rather than animating a session it could not verify. */
.rp-fail{margin-top:8px;padding:8px 11px;border:1px solid var(--edge);border-radius:var(--radius-sm);
  font-size:var(--fs-12);color:var(--dim);letter-spacing:0;text-transform:none}

/* Reduced motion gets the finished day, immediately and without a wipe: the
   card's whole content is the session, so skipping the animation must not
   skip the chart. initReplay paints the completed state and never starts a
   frame loop; this form's own volume strip needs the same rule css/replay.css
   already gives the line and the dot. */
@media (prefers-reduced-motion:reduce){
  .rp-vol{clip-path:none}
}

/* The Move's replay, moved out of the shell sheet. It hangs off
   `.card.replay` and the `rp-` prefix rather than `.card.reaction`, which is
   why it did not follow the form automatically -- but it is this form's CSS
   and a form's CSS is one file you can find. */
/* ------------------------------------------------------------------ *
   The Move — the session, replayed.

   Everything here hangs off `.card.replay` or a `.rp-` class, per AGENTS.md
   rule 14. `.card.replay` is set only when the payload carries a validated
   `visual.replay` block, so the eleven frozen batches that hold a `reaction`
   or `drop` card are drawn by the static path below it and are untouched by
   every rule in this section.

   The form is a claim with its ending withheld: an empty plot anchored at
   9:30 with the previous close already ruled on it, then about eight seconds
   of the real session, then the numbers. The restraint is the point — one
   line, one rule, one strip of volume and a clock. Nothing here counts down,
   pulses or instructs.
 * ------------------------------------------------------------------ */

/* One title, and it does not move. An earlier build swapped a suspense line
   for a factual one at 16:00, in the same frame that four hidden figures
   appeared -- five changes at the instant the reader was watching the chart
   finish, which reads as a snap rather than as an ending. The title says what
   the card is; every number on it says what happened, continuously.

   So there is nothing here holding the headline or the payoff back. The
   figures below are counters, and a counter that is invisible until it stops
   is not a counter. */

/* --- the readout -------------------------------------------------- */
/* Reuses .rdout's column so the panel keeps one left edge; the rows inside
   it are this form's own. `.rp-top`/`.rp-sym`/`.rp-clock` moved to
   css/replay.css at session 37: `chartTop()` draws them and The Poll now
   calls it too (for its `ctl` slot), so they are drawn by both forms and
   belong in the shared file (rule 14), not here. */
/* The three-state play/pause/replay circle that used to sit here is gone as
   of session 37 -- replaced by the shared again button (`.rp-tp-again`,
   css/replay.css), which `chartTop`'s `ctl` slot draws in the identical
   place via `margin-left:auto` on the button itself, not on a form-specific
   class. Nothing to style here any more. */

/* Fixed baselines for the price and the change -- rewritten ~79 times during
   a replay and must not move a pixel while they do -- are css/replay.css's
   `.rp-price`/`.rp-chg` now, the one row The Poll's own replay rewrites too.

   The stake lives in the panel now, on its own row with the other three
   counters. The payload keeps `sub`; this form no longer draws it, and an
   empty payoff slot would otherwise reserve its margin above Read more.

   `.card.replay .hook .sub{display:none}` moved to shell.css, consolidated
   with The Habit's and The Insider's copies of the same rule -- see shell.css
   for the declaration. This card's real deck ("$10,000 became $9,931", the
   SPY replay) wraps to 2 lines and costs 73.17px over the pinned bottom if
   shown; a one-line deck costs 37.09px. Nothing here changed what this card
   renders. Note: the archetype is `reaction`, styled here, and its display
   name is "The Move" (docs/archetypes.md) -- the `.replay` class comes from
   the opt-in replay visual, not from a different form. */
