diff --git a/docs/handoff/20260621-website-handoff-3.md b/docs/handoff/20260621-website-handoff-3.md
new file mode 100644
index 0000000..97b7fe3
--- /dev/null
+++ b/docs/handoff/20260621-website-handoff-3.md
@@ -0,0 +1,130 @@
+# Website-branch handoff — 2026-06-21 (website-3)
+
+Third handoff for the **website** work (separate sequence from `main`'s
+`YYYYMMDD-handoff-NN.md`). Read **website-2** (2026-06-11) first for the
+scaffolding, cast pipeline, and the no-advertising constraint; this note covers
+everything since, and — importantly — the state has moved on (see §1).
+
+## §1. State (read this first)
+
+- **Branch:** `website`. **HEAD `dff7841`.** Working tree **clean**.
+- **Pushed:** `origin/website` == `dff7841` (this session's work is pushed).
+- **Already merged into `main`:** `dff7841` is an ancestor of `main` — every
+ website change below is in `main`. **`main` has since advanced ~20 commits**
+ (now `56e3456`, handoff 75) with **v0.2.0 + install/packaging** work. So
+ **`website` is ~20 commits behind `main`.**
+- **Consequence for the next session:** start by **merging `main` into
+ `website` again** (or rebranching `website` off `main`). There is real new
+ user-facing surface to document — see §4.
+- **Agent limitation:** this machine's SSH key for `git.lazyeval.net` was **not
+ available to the agent** — `git fetch`/`push` fail from inside the session.
+ **Push and fetch are the user's steps.** Local merges work fine.
+
+## §2. What shipped this session (all in `main` now)
+
+The website lives in **`website/`**; living style guide **`website/STYLE.md`**;
+decisions **`docs/website/adr/20260604-adr-website-001.md`**.
+
+**CI / deployment — the big one (ADR-website-001 §4):**
+- **`.gitea/workflows/website.yaml`** — on a push to `main` or `website` that
+ touches `website/**`, build the Astro site with pnpm and `wrangler pages
+ deploy website/dist` to the Cloudflare **Pages project `relplay`** (Direct
+ Upload, no Git integration). `--branch` selects environment vs the project's
+ production branch (`main`): **`main` → production (`relplay.org`)**,
+ **`website` → preview (`website.relplay.pages.dev`)**.
+- Pure-Node build (the `.cast` files are committed, so no cargo). Runs on the
+ bare `ci-public` runner (node present; pnpm via corepack, pinned by
+ `package.json`'s `packageManager: pnpm@10.30.3`).
+- **Secrets (set in repo Actions settings):** `CLOUDFLARE_API_TOKEN` (Pages:
+ Edit) + `CLOUDFLARE_ACCOUNT_ID`. Pages project created with production branch
+ = `main`.
+- **`ci.yaml` gate** now skips website-only pushes (`paths-ignore` += `website/**`,
+ `.gitea/workflows/website.yaml`).
+- **`staging.relplay.org`** (optional): attach the custom domain to the `website`
+ branch alias — add it in the Pages dashboard, then point its **proxied**
+ CNAME at `website.relplay.pages.dev` (external/unproxied DNS falls through to
+ production). Cloudflare Pages maps branches to **subdomains, not sub-folders**.
+
+**Content updates (from two `main` merges that landed seed/readline/hint/etc.):**
+- **Seed page** (`reference/generating-sample-data.mdx`) refreshed for **#33/#34**:
+ year-as-int columns (`*_year`/`published` → plausible years), built-in value
+ sets (`priority`/`severity`/`rating`), advisory now **status-only**. All output
+ blocks re-captured; the seed cast reflects it.
+- **`hint` feature** (ADR-0053) documented: `getting-help.md` → **`.mdx`** with a
+ "Hints" section (F1 = tier-3 live-input hint; `hint` command = last-error hint)
+ + the real rendered block; `the-assistive-editor.mdx` points at F1.
+- **Readline keys (#29)** + **cross-mode history recall (#30)** documented on
+ `the-assistive-editor.mdx`; "Planned" narrowed to multi-line entry only.
+- **Landing** (`index.mdx`): the redundant plain **`
` "RDBMS Playground"** is
+ hidden (kept for SEO/a11y via a **title-only hero**, landing-scoped in
+ `global.css`); the **Wordmark + tagline + buttons** render in the body so the
+ lockup sits where the title was and content rises above the fold (it was nearly
+ hidden on an iPad).
+- **All 10 casts re-recorded** + a **new `hint` cast** (11 total) against the
+ current app.
+
+**Casts — the F1 trick (important for future hint/keybinding casts):**
+- autocast **cannot send F1** (or arrows/function keys — escape sequences split
+ by the per-key delay). Solution shipped on `main`: **ADR-0047 Amendment 1** —
+ in `--demo` mode **Ctrl-G aliases F1** and **badges AS `[F1]`**, so a cast looks
+ like a real F1 press. The cast generator gained `CtrlG: '^G'`.
+- The **hint cast** uses it realistically: type `add column `, pause, **F1**
+ (Ctrl-G) mid-command to recall the syntax, finish the command from the example,
+ then later a failed command + `hint` for the error.
+
+**Hint-vs-docs audit (user-requested):** one genuine conflict found —
+`hint.cmd.create_table.example` declared a 3-column compound PK; **fixed upstream**
+(`5a37437`, now `create table Customers with pk id(serial)`). Everything else
+(export/import, indexes, constraints, DML, SQL forms, error hints, terminology)
+was consistent.
+
+## §3. Verification status
+
+- `cd website && pnpm build` → **clean, 27 pages**. Forbidden-terms grep clean
+ (`DSL`/`SQLite`/`STRICT`/`rusqlite`/`PRAGMA`). Output-table box-drawing intact;
+ anchors resolve; hint cast content verified (`[F1]` badge + both hint blocks).
+- **NOT done — needs a human visual pass:** the new **landing spacing/aesthetics**
+ (couldn't be eyeballed by the agent) and the **11 re-recorded casts** (verified
+ programmatically only). Do this in staging/production before relying on them.
+
+## §4. NEXT WORK — priority order
+
+1. **Re-merge `main` into `website`** (it's ~20 behind) — or rebranch off `main`.
+2. **Reconcile the installation / getting-started docs with what `main` actually
+ shipped (v0.2.0):** the website branch's `installation.md` predates several
+ real install methods now live —
+ - **crates.io v0.2.0** (`cargo install rdbms-playground`, `cargo binstall`),
+ - the **curl | sh installer** (ADR-0055),
+ - **Windows `install.ps1`** (`fix(install)` commits),
+ - **package managers**: Scoop / Homebrew / **winget** (ADR-0056; winget via
+ komac). `installation.md` mentions brew/scoop but **not** winget, the
+ curl|sh installer, or binstall — reconcile against the shipped reality
+ (check ADR-0055/0056 + handoffs 74/75 + the `publish.yaml` workflow).
+ - There's also `--version`/`-V` + an in-app `version` command (ADR-0054) — a
+ line on the command-line-options page may be warranted.
+3. **Visual sweep** (§3): landing + casts; final caption review (website-2 §2).
+4. **Carryover from website-2:** light/dark player theme (deferred), open STYLE
+ decisions (#7/#8 mostly resolved; recheck), output-pane-scroll cast still
+ blocked (PgUp/PgDn unsendable — would need a typeable scroll key like #24).
+
+## §5. Process pins
+
+- **Commits:** user-confirmed (show the message first), **no AI attribution**,
+ **append-only** (no amend/rebase/force-push). **Push/fetch are the user's
+ steps** (and the agent can't reach the remote anyway — §1).
+- **Ground every page in source** (`src/dsl/*`, `src/friendly/strings/en-US.yaml`,
+ the ADRs) — not `requirements.md` markers. No engine name, no "DSL" in copy.
+- **Output blocks captured from the real app**, never hand-drawn (STYLE.md). The
+ capture recipe (throwaway in-crate/`it` test → render → paste → delete) and the
+ cast pipeline (`pnpm casts [name]`, needs `../target/debug`) are in website-2.
+- **Cast stance (revised 2026-06-12):** default to a cast; justify its *absence*.
+- **Issues** via `tea` (repo `oli/rdbms-playground` on `git.lazyeval.net`;
+ append `< /dev/null` + `timeout 30`). This session filed **#33** (year ints)
+ and **#34** (enum value sets) — both **implemented** on `main` now.
+
+## §6. Footnote — a git oddity in this branch's history
+
+`c84a640 "docs(website): document the hint feature with a cast"` is an **empty
+rename commit** (a `git add` tooling slip staged only the `.md`→`.mdx` rename);
+its actual content is in the **next** commit `028d324`. Harmless, left in place
+per the append-only rule (user-approved). No action needed.