What changed, and why
Each resolved turn is tagged with terse, evocative symbols: ✒ Reckless, ⚡ Ahead of its time, ⏳ Reaching, ⚑ staked. They are not flavor — each one moves real numbers. Craft tilts the dice roll, anachronism widens the swing, the causal chain decays it, the stake doubles it. Until now a player had no way to learn any of that: no tooltip, no title, no glossary anywhere in the app.
This PR gives every in-run symbol a hover/focus tooltip that says what it means and how it bends the swing. The work splits cleanly into three moves, each below: the hint copy gets a home next to the mechanic it describes; a small component turns any inline symbol into an accessible hover trigger; and the two surfaces that render these symbols — the ledger and the thread — get wired to use it.
Hint copy lives beside the mechanic
The explanation for each symbol is data, not template strings. It lands in the same module as the number it describes, keyed by the same level type, so the two can't drift apart. Three new constants mirror the existing CHAIN_HINT (which the causal-chain module already shipped, and which this PR reuses unchanged).
CRAFT_HINT sits right under CRAFT_MODIFIER / CRAFT_LABEL — meaning plus the exact roll tilt.
utils/craft.ts · 48 lines
⋯ 33 lines hidden (lines 1–33)
⋯ 6 lines hidden (lines 43–48)
ANACHRONISM_HINT, deliberately qualitative: the precise factors live just above it.
server/utils/anachronism.ts · 91 lines
⋯ 56 lines hidden (lines 1–56)
⋯ 26 lines hidden (lines 66–91)
STAKE_HINT, next to STAKE_MULTIPLIER and applyStake.
utils/swing-bands.ts · 61 lines
⋯ 53 lines hidden (lines 1–53)
SymbolHint: one focusable trigger
One small component carries the interaction so the call sites stay quiet. It wraps an inline symbol in a Nuxt UI UTooltip (the UApp root already provides the reka-ui tooltip context) and renders a single focusable span as the trigger.
The whole component: a UTooltip around a tabindex=0 span; the slotted badge keeps its own color and testid.
components/SymbolHint.vue · 34 lines
⋯ 15 lines hidden (lines 20–34)
Wiring the ledger: spine and node-detail
The timeline ledger shows symbols in two places, and they need different treatment. The node-detail strip's badges become SymbolHints. The spine nodes can't: each node is already a role="button", and a focusable tooltip trigger nested inside it would be a focusable-in-button trap. So the spine keeps its aria-label and gains a native title instead — a hover hint with no nesting.
Spine glyphs get :title (44-46); node-detail craft/anachronism/stake badges get wrapped (71-86); anachronismHint helper (126).
components/TimelineLedger.vue · 195 lines
⋯ 43 lines hidden (lines 1–43)
⋯ 24 lines hidden (lines 47–70)
⋯ 39 lines hidden (lines 87–125)
⋯ 69 lines hidden (lines 127–195)
The thread: a flat equation becomes hinted tokens
The conversation thread shows the craft verdict and the swing equation. The verdict label is now wrapped (line 49). The equation was the one real refactor: it used to be a single joined string, which can't carry a per-symbol tooltip. It becomes a list of typed tokens, each rendered as its own hinted span.
Craft verdict wrapped (49); equation template renders base + hinted tokens + final (66); equationTokens builds the typed list (152-168).
components/MessageHistory.vue · 200 lines
⋯ 47 lines hidden (lines 1–47)
⋯ 16 lines hidden (lines 50–65)
⋯ 85 lines hidden (lines 67–151)
⋯ 32 lines hidden (lines 169–200)
Tests
The new layer is the hint constants, so the new tests are the discriminating ones: every craft and anachronism level, and the stake, must carry a non-empty hint. They mirror the existing "label for every grade" checks one block up.
One example; anachronism.spec.ts and swing-bands.spec.ts gain the parallel assertions.
tests/unit/utils/craft.spec.ts · 33 lines
⋯ 29 lines hidden (lines 1–29)
⋯ 1 line hidden (lines 33–33)
Alongside these: nuxt typecheck is clean (it type-checks the templates against generated types, so the new SymbolHint usage and equationTokens typing are verified), and the Playwright gameplay suite stays green. Manual check confirmed the tooltip opens on both hover and keyboard focus.