# Direction 2, Tracks, pass 5: Now becomes the multi-token Clock

*W-design-pass5-now, Opus 5.5, 2026-09-27 15:28 to 15:45 Beirut. Brief: `briefs/W-design-pass5-now.md`. Built on copies of the pass 4 files. Files: `now.html`, `situation.html` (two edits only), `scripts/shots.cjs`, `scripts/verify-output.txt`, `scripts/palette_cvd.py`, `palette-cvd.txt`, `shots/`. Design choices and the five example timelines are grade C (judgement). Verification numbers are grade A, from our own script output. To re-run: `NODE_PATH=/home/botbox/node_modules node scripts/shots.cjs`.*

**Look first:** `shots/now-desktop.jpg`, `now-desktop-1657.jpg`, `now-desktop-hover.jpg`, `now-phone.jpg`, `now-phone-1657.jpg`. `situation-desktop.jpg` is the unchanged page.

## (a) What changed against pass 4

All four blocks are built and verified, **Block D included**, because A to C were verified well inside the budget. Nothing was cut. Every rule from pass 4 still holds: Geist, tabular figures, mono only for the address (Now has no mono at all), the pass 2 palette, `last(m)` with no interpolation, reduced motion, phone behaviour, and no "playhead" anywhere.

**A1 Mini Clock.** Each row has one strip: one baseline, one shared 60-minute axis (16:27Z to 17:27Z), and the same geometry on every row. The glyphs are the Situation lanes' own marks at small size (table in c). Under each strip is one readout caption at the moment, in the lane-label voice. The column head reads `16:27Z · Situation · 60 min · 17:27Z`. A legend under the list, one line per glyph, replaces the pass 4 foot line. It names the bars as "wallets entering a minute, scaled within each row". Bars are drawn only for intervals complete at the moment, and they are scaled by the largest visible bar, so later magnitudes cannot leak into an earlier picture (C). **A2 Row anatomy.** The desktop has five cells: State (the word plus a smaller Developing descriptor) | Token (name, chain · tracked age, which follows the moment, plus `Following` on SPRING) | What is happening (sentence, then `Latest: … · clock`) | Situation · 60 min (strip plus caption) | For you. The phone card has exactly six elements. The state word is a button: hovering it on desktop, or tapping it, shows `Why here` in one line. There is no score or rank anywhere. **A3 Copy.** The head reads `6 situations surfaced · Live 17:27Z`, the end line reads `No other situations meet the surfacing rules at 17:27Z.`, and the Developing rows read `Developing · wallet-led` and `Developing · attention-led`. "Worth a look" is gone. **A4** The two `situation.html` edits are listed in (e).

**B1 Rail.** A custom slider (role=slider, arrow keys, Home/End, PageUp/PageDown, pointer drag) sits in the strips' own grid column, so it spans exactly their x range. Play sits left of it (8 s, reduced motion steps a minute at a time, `?play=1`). The title strip reads `Live · 17:27Z`, or `Now at 16:57Z` with a `Historical` caption, `Back to live` and `Copy link`. The historical cue is the same one Situation uses: a 2 px ice rule under the clock area. On desktop, a moment line runs from the rail down through every strip. **B2 Rebuild.** Each row has `surf` (surfacedAt), state functions and an event list. At m, rows with `surf > m` are removed from the DOM, and everything else is computed at m. The future side of the strip is clean ground. SPRING was Developing before 16:32Z, but that is never shown, because SPRING was not on the surface then (Situation still shows it). **B3 Links** are covered in (b). **B4 Order** uses buckets, recomputed at every moment (b). **B5** The five example rows have no `href` and carry `aria-disabled="true"`. The cursor stays default and nothing else marks them. No page is faked.

**C1 For you** priority is: in, then looked, then new. `Following · n material` is written into the rule, but nothing on this page triggers it: SPRING is the only followed row, and it has a look. So that branch is not coded. The C1 wording `Following` appears only as the token-cell marker. **C2** Clicking For you on SPRING opens the right comparison. **C3** `Before your look` shows in muted ink.

**D1** During playback, if the pointer is over the list or a row has focus, rows neither move nor get added. A pill above the list reads `3 new situations surfaced` or `Order changed`, and clicking it applies the new order. It also applies when playback ends with the pointer away, or when the pointer leaves the list. **D2 Rail landmarks** use three glyph classes: surfaced (ice dot), state change (ice tick), safety change (crimson diamond). Each has a hover title, and a landmark is drawn only at or before the moment.

**Deviations (C):** (1) KESTREL and OBOL have no last look ("never opened"), so they read `New to you`, as the verify list requires. Pass 4's `S[i][10]` gave them 17:17Z and 17:19Z. (2) KESTREL's single watched wallet is drawn as the participant mark and not also as a bar, because a lone wallet scaled within its row would be a full-height bar and a loud false wave. (3) The Latest line names the latest material event **that changed what the row says**. SPRING's 17:27Z read is material against your look, so it counts in For you, but it does not change the sentence. That is why Latest at live stays `first profiled trader · 17:08Z`, as the brief asks.

## (b) Behaviour

- **URL grammar (Now).** No query means live. `?t=16:57Z` is a moment. `?play=1` plays. Changes go through `replaceState`, debounced 120 ms, never during playback, and written once when playback stops. `Copy link` copies `now.html?t=16:57Z` when historical and the plain `now.html` URL at live, then shows `Copied` for 1 s.
- **Links out.** The SPRING row opens `situation.html` at live and `situation.html?t=<m>` when historical. The hover actions (`Open Situation`, `Copy address`, SPRING only) appear on desktop hover or focus and carry the same `?t=`. For you opens `situation.html?a=16:57Z&t=<m>` (look) or `?a=<entry clock>&t=<m>` (in).
- **Entry key.** `localStorage['caverio.spring.entry']` is the JSON the Situation page writes (`{m, price, mc, w, state}`), and only `m` is read. If the read fails (for example from `file://`), the page treats you as not in. With an entry, SPRING's For you reads `In · n material since entry HH:MMZ`, with `n since last look` under it, and its strip draws the chalk entry diamond.
- **Order.** (1) a safety change in the last 60 min; (2) past Developing, with the Latest event in the last 30 min; (3) other rows past Developing; (4) Developing. Inside each bucket, the newest Latest comes first. The rule is printed in plain words in About this data. No number is shown.
- **Material rule.** This is pass 4's rule: a first of something, price 25%, wallets 50, top-20 0.05, any safety change, any state change. SPRING computes it from the reads exactly as Situation does (`springMat`). The example rows carry an authored `mat` flag per event.
- **A vs B Now (f, architecture only).** Compare would reuse `order(m)` and the per-row `state/sen/latest` functions at two moments. The diff is set arithmetic over the two surfaces: entered (in B, not in A), left (in A, not in B), state changes (state(A) differs from state(B) for rows in both), and material events per row (events with `mat` in (A, B], or `springMat(A,B)`). The URL would be `now.html?a=16:57Z&t=17:27Z`, mirroring Situation. Rows would render at B with a chalk A tick on every strip and the rail. No control was built.

## (c) Glyph grammar

| Glyph | Meaning | Colour | From Situation lane |
|---|---|---|---|
| bars up from baseline | wallets entering a minute, scaled within the row | ice `#72C3E6` | Money |
| hollow ring with ice dot, on baseline | profiled or watched participant | ice | Participants |
| hollow ring above the baseline, dotted stem | public attention (a call, a mention) | ink `#E6EAED` | Attention (its cadence ring, enlarged) |
| short tick below baseline (wider = burst) | holders weakening, exits | `#C8742E` | Holders / weakening family |
| tall filled diamond | safety change, the only glyph louder than bars | crimson `#D6336C` | Safety |
| chalk flag, chalk diamond | your look, your entry | chalk `#E9E3A4` | You |
| 45° hatch | not on our tape yet | 22% ink | hatch everywhere |

**Missing-data cases (reviewer 24):** *observed absence* is clean ground on the baseline, with nothing drawn and a caption like `none seen` (attention on SPRING, AGRIPPA, KESTREL) or `no money seen` (OBOL after 17:05Z). *Not observed* is the hatch (MARLIN before 16:39Z, KESTREL before 17:13Z, OBOL before 17:05Z). *Not read* draws nothing, and the caption says so: `safety not read`, `holders not read`. *No exits read* on SPRING draws nothing, and the caption omits exits, as on the Situation Money lane. *No safety change, reader present* has no instance here. *Stale* is carried by the readout: each value is `last(m)`. The future is clean ground to the right of the moment line, and it is never hatched.

## (d) Example values (all grade C, listed in About this data)

Minutes are from 16:27Z. Bars are given as [from, to, wallets].

- **SPRING** (real, from `fixture.py`): surf 5 (16:32Z), look 30 (16:57Z), followed. Example only: the look and the follow.
- **AGRIPPA**, Robinhood, tape from 0, surf 20 (16:47Z) as `Developing · wallet-led`, look 20. Bars: [0,10,40] [10,20,50] [20,30,52] [30,38,120] [38,46,260] [46,54,300] [54,60,248], a total of 142 by 16:57Z and 1,070 by 17:27Z. Events: 20 surfaced (M); 38 (17:05Z) state became Crowd arriving (M); 40 (17:07Z) first profiled participant (M); 50 (17:17Z) top-20 share 0.52 to 0.37, weakening tick (M). For you: 3 material since 16:47Z.
- **LUMEN**, Robinhood, tracked 70 min before the window, on the surface before 16:27Z, look 35 (17:02Z). Bars: [0,10,40] [10,20,55] [20,30,30] [30,40,20] [40,50,12] [50,60,8] (165). Caller calls at 14 (16:41Z, M), 33 (17:00Z, M) and 54 (17:21Z, M). Early-50 reductions (weakening ticks) at 22 (8%, obs), 29 (16%, obs), 36 (17:03Z, 24%, M; state became Early money leaving), 43 (31%, M) and 51 (41%, M). For you: 4 material since 17:02Z.
- **MARLIN**, BSC, tape from 12 (16:39Z), surf 52 (17:19Z), look 45 (17:12Z). Bars: [12,20,80] [20,30,60] [30,40,45] [40,50,30] [50,60,15] (230). Events: 52 safety, pool liquidity down 38% (M); 54 (17:21Z) exit burst of 20 wallets (obs, wide weakening tick). For you: 1 material.
- **KESTREL**, BSC, tape from 46 (17:13Z), surf 48 (17:15Z), watched wallet at 48 (M), never opened.
- **OBOL**, Solana, tape from 38 (17:05Z), surf 54 (17:21Z), Telegram call at 54 (M), never opened.
- Every sentence, Why here line and readout for these rows is authored as a function of the moment. The surfaced counts are 16:42Z: 2, 16:57Z: 3 (SPRING, LUMEN, AGRIPPA), 17:15Z: 4, 17:19Z: 5, 17:21Z: 6.
- Carried over from pass 4: market cap, liquidity, the Telegram cadence, "tape 12 s", "Developing until 16:32Z", the thresholds, and the entry kept only in this browser.

## (e) `situation.html` against pass 4 (`diff`, 3 lines)

```
298  <a href="now.html">Now</a>  ->  <a href="now.html" id="navNow">Now</a>
637  ...$('hBack').hidden=at;  ->  ...$('hBack').hidden=at;$('navNow').setAttribute('href','now.html'+(at?'':'?t='+clk(m)));
723  Source: our tape, wallet balance read.  ->  Source: our tape; holders counted from the tape, balances not read yet.
```
Edit (i) needs two lines: an id on the link, and one statement in `render()`. Edit (ii) is one line. Nothing else changed.

## (g) Verification (15:41 Beirut, full output in `scripts/verify-output.txt`)

```
shots: now-desktop 149 KB, now-desktop-1657 106, now-desktop-hover 153, now-phone 126, now-phone-1657 82, situation-desktop 205;
       scrollWidth ok, no overflowing element, fonts Geist (+Geist Mono on Situation), no page errors
axis: stripX(16:57Z) = 875 for all rows and the rail at 1280 (moment line 875 at ?t=16:57Z); 195 for all at 390. SAME at live and 16:57Z
live order: MARLIN (b1, 17:19Z) > LUMEN (b2, 17:21Z) > AGRIPPA (b2, 17:17Z) > SPRING (b2, 17:08Z) > OBOL (b4, 17:21Z) > KESTREL (b4, 17:15Z)
live SPRING readout "939 entered · 1 profiled · none seen · top 20: 0.59 · safety not read"; Latest "first profiled trader · 17:08Z"
  MARLIN "230 entered · none profiled · none seen · 20 exited · pool down 38%" | LUMEN "165 entered · none profiled · 3 calls · 41% of first 50 reduced · safety not read"
  AGRIPPA "1,070 entered · 1 profiled · none seen · top 20: 0.37 · safety not read" | OBOL "no money seen · attention 1 · holders not read · safety not read"
  KESTREL "1 entered · 1 watched · none seen · holders not read · safety not read"
?t=16:57Z: head "3 situations surfaced · Now at 16:57Z", Historical + Back to live, ice rule on; rows SPRING, LUMEN, AGRIPPA; MARLIN row absent
  SPRING sentence == Situation ?t=16:57Z header, byte for byte: true; SPRING href situation.html?t=16:57Z
  page text (drawers open, titles, tooltips): 876 false, 17:08 false, 17:19 false  (the word MARLIN appears only in About this data's example list)
  readouts SPRING "861 entered · none profiled · none seen · top 20: 0.57 · safety not read" | LUMEN "125 entered · none profiled · 1 call · 16% ..." | AGRIPPA "142 entered ..."
For you: live SPRING "3 material since 16:57Z", href situation.html?a=16:57Z&t=17:27Z | 16:42Z "Before your look"
  stubbed entry 17:11Z: "In · 2 material since entry 17:11Z | 3 since last look", href situation.html?a=17:11Z&t=17:27Z, mark "You entered, 17:11Z"
  KESTREL "New to you", OBOL "New to you"; "0 changes" nowhere; no bare "n changes" at live, 16:57Z or 16:42Z
Copy link: 16:57Z -> now.html?t=16:57Z, label Copied then Copy link | after Back to live -> now.html, no query
rail: click at the 16:57Z x -> 16:57Z, ArrowRight -> 16:58Z, End -> 17:27Z; moving to 17:08Z writes ?t=17:08Z and SPRING href ?t=17:08Z
Why here SPRING live "Surfaced because the first profiled participant arrived after 876 wallets." | 16:57Z "Surfaced at 16:32Z because 638 ..."
D1: from 17:10Z, pointer on a row, play: rows stay LUMEN,SPRING,AGRIPPA, pill "3 new situations surfaced"; click -> MARLIN,...,KESTREL
    pointer away, play: rows update in place, no pill | reduced motion: 17:17Z -> 17:27Z in 1.3 s, label Replay
D2 landmarks at 16:57Z: SPRING surfaced 16:32Z, AGRIPPA surfaced 16:47Z only (none from the future)
situation: nav Now href now.html at live, now.html?t=17:08Z at ?t=17:08Z; read source line is the new wording
phone 390: no overflow at live and 16:57Z, six elements per card on every card, legend visible
```

- **Absent strings** in the rendered DOM of now.html at live, 16:57Z and 16:42Z: `playhead`, `worth a look`, `money in`, `Back to now`, and a bare `changes` count. None were found.
- **Grep:** there is no U+2014 in any file in this directory. The banned words and internal strings were checked in the rendered DOM at three moments and in the `now.html` source: zero hits. `situation.html` still has **2** uses of "contract" in its source (the Safety tile and Not yet known, carried over from pass 4 as accepted). The rendered DOM at live shows 1. Hex colours in now.html are only the pass 2 palette. No green or red appears, and change is told in words.
- **Contrast** (WCAG, our computation) on new surfaces: For you chalk on row 13.07; No material change and Latest 8.23; Before your look, readout captions and Following 5.90 (5.59 on a hovered row); title strip 15.17; Historical ice 9.32; Back to live 7.84; Copy link 8.67; rail clocks 6.07; pill 8.05; Why here 13.10, with its label at 5.59; legend 8.67; Early money leaving orange 4.90. Graphics (3:1 needed): attention ring 14.19, weakening tick 4.90, participant 8.72, safety diamond 3.72, look chalk 13.07, moment line 8.41, rail landmarks 9.32 ice and 3.98 crimson. **One item is under AA:** the `Safety changed` pill text is 4.22, dark ground on crimson at 16 px semibold. It is carried unchanged from pass 2 to 4, and the fix would be a larger word or a lighter crimson. I am flagging it for Vesper rather than retuning the palette in this pass.

Status: DONE
