# Wise Agents motion

## Rules (enforced by `tests/test_blog.py` → `Palette` and by the browser check)

- **Only the AI moves on its own,** and only one moving thing per screen.
- **A scene plays once and settles.** It starts about 0.7 s after it is 30% in view, pauses off screen, and plays once per visit (`sessionStorage`).
- **Over 5 s gets Pause and Replay.** When it ends, Play is `aria-disabled`, not `disabled`, so focus stays.
- **Reduce motion shows the final frame.** The HTML is a meaningful final frame before JavaScript runs.
- **Transform, opacity and `stroke-dashoffset` only.** Every `@keyframes` is checked by a test. Colour changes are cross-fades between stacked layers. Hidden layers are also `visibility: hidden`, so they never count as low-contrast text.
- **No motion library.** `assets/site.js` has a small `Timeline(render, end)` on `requestAnimationFrame`; each scene is a pure function of time.
- **Content first.** The headline is the LCP element; layout shift is 0 (Lighthouse, every page measured).

## Logo motion states (`.wa-mark[data-state]`, demo on `brand/index.html`)

| State | Meaning | Timing | Where |
| --- | --- | --- | --- |
| `reveal` | Hello | The rule draws (0.7 s, dashoffset), the fill fades in at 0.55 s, the spark spins in at 0.62 s with `cubic-bezier(.34,1.56,.64,1)`. Once per visit | Top bar |
| `thinking` | The agent is working | The spark turns a quarter and breathes, 1.4 s loop | The demo's product bar while it runs |
| `speaking` | The agent is talking | Scale follows the level: fast attack (0.6), slow release (0.08) | Avatar (kit page simulation) |
| `done` | Finished | 0.6 s once: grows 28% and turns 90° to rest | The demo, once monitoring |
| `idle` | Alive | 3 s breath | Videos, slides, never in the product |
| hover | Respond | 120 ms ease-out: the spark turns 45° | Any link or button holding the mark |

## Scenes

### Hero: the rule around the spark (`src/partials/hero-guard.html`, about 2.6 s)

| Time | What happens |
| --- | --- |
| 0 | First visit only (the head script sets `data-hero="play"`): the four sides are undrawn, switches off, effect lines hidden |
| 0.7 s after 30% in view | Side 1 (a person decides) draws with dashoffset over 0.5 s; at 60% its switch flips on and its effect line appears |
| +0.5 s each | Sides 2, 3, 4 (record, minimise, disclose) |
| 2.1 s | The spark spins in at the centre |
| 2.6 s | Settled: "Ready for sign-off" |

Then it is the visitor's. Switching a control off draws that side in dashed rose, swaps the effect line ("€1,240 paid automatically", "every mailbox and the whole customer file" read), and the verdict becomes "Not releasable: …". A touch during the intro ends it at its final frame first.

### Platform demo (`src/partials/platform-demo.html`, 17.4 s to the gate)

| Time | Step | What happens |
| --- | --- | --- |
| 0–4.6 s | Brief | Four sentences fade in (0.75 s apart), then six spec chips (0.22 s apart) |
| 4.6–9.2 s | Build | Six spec rows: knowledge, tools, guardrails, model route, cost limit, hosting |
| 9.2–16.4 s | Test | Run 1: 40 cells fill (65 ms apart); safety case 33 fails → "Blocked" at 12.4 s; the fix at 13.1 s; run 2 re-colours (45 ms apart); "Clears the bar: 95%, 8 of 8" at 15.8 s |
| 16.4–17.4 s | Approve | The cream approval card. **The timeline stops here and waits for a person.** Deploy and Monitor tabs are gated |
| on Approve +0–2.4 s | Deploy | The gold seal lands; five deploy rows; a run record |
| +2.4–6.4 s | Monitor | Sparkline draws (dashoffset); conversations, hand-offs and cost count up; "Held for a person" card; Stop agent |

### Sample runs (`src/partials/sample-runs.html`, industries page): no motion

Four use cases as static step lists. The tabs switch at once, with no transition, so the industries page keeps zero moving things. Without script every run is shown and the tabs are hidden.

The rail's spark travels with the step (`translateX`) and the rail fills with the spectrum (`scaleX`). Under Reduce motion and on a second visit the demo opens at the gate; Approve shows the monitor at once. Keyboard: arrow keys, Home and End on the step tabs.

### Security and privacy scenes (`src/partials/scene-*.html`, trust page and home): under 3.5 s each

One small explainer per layer on `/trust.html#layers` (and `de/vertrauen.html`), plus one on the home page's security section. Each shows **only what the platform really does today**: no redaction of personal data (the data scene shows a *secret* being scrubbed and says personal data is not masked), no tamper-proof log, no map or arc to a fake EU region (the model scene points at "the provider in your contract").

- **Engine** (`assets/site.js`, `Scene`): a pure function of time over data attributes. `data-at="t"` fades in (opacity, translateY), `data-dim="t"` fades to its resting opacity, `data-draw="t d"` draws a stroke (dashoffset, `pathLength="1"`), `data-move="x,y@t …"` moves the spark. The HTML is the final frame; inline styles are cleared at the end.
- **The spark is the only thing that travels**, in the spectrum (it is the AI's request). Gold marks only a person's decision (the grant, the approval, "Delete agent · you ask"); cream only a record (the ledger, the receipt, "On record"); rose only a refusal or an attack.
- **Explorer:** only the selected layer plays, once per visit (`sessionStorage wa-layer-<tab id>`), ~0.7 s after the explorer is 30% in view; switching layers settles the old scene at its final frame. Every scene has Replay. Keyboard: arrows, Home, End; Tab goes into the panel.
- **Home journey** (`scene-journey`, 3.5 s): the spark drops through six bands (sign-in, workspace filter, content is data, secrets scrubbed, a person decides in gold, on record in cream). Once per visit (`wa-scene-journey`).
- **Reduce motion, no script, second visit:** the final frame, no Replay button. Off screen: paused.

| Layer | Scene | Ends at |
| --- | --- | --- |
| 01 Access | Two circles draw: the grant a person set (gold) and the AI-written spec (spectrum). The spark tries "Delete files" (✕), settles in the overlap | 3.3 s |
| 02 Separation | The spark passes the "who is signed in" filter and visits only workspace A's rows; B's show "not found" | 3.3 s |
| 03 Hosting | The reply leaves the Nuremberg box through an outbound tunnel to the HTTPS edge and the browser; an inbound arrow is refused | 3.3 s |
| 04 Data | The spark reads the two connected sources; three stay "not connected"; a tool result's key becomes "(secret removed)" | 3.3 s |
| 05 Model | The spark crosses the edge of our servers to "Model provider · Region: in your contract" and back; "On record" | 3.2 s |
| 06 Untrusted content | The spark reads a PDF with a hidden "Ignore your rules…"; "Read as data, not orders"; "Task unchanged"; safety pack | 3.0 s |
| 07 A person decides | The agent proposes "Pay out €1,240 · Sample" and stops; the gold card; "Approved by a named handler"; "On record" | 3.0 s |
| 08 Records | The spark walks input, sources, tool, model; the cream ledger writes a line per step; the approver's line last | 3.0 s |
| 09 Deletion | Six stores dim with a tick each; the cream receipt says "Backup copies: not part of it yet" | 3.0 s |
