Parcourir la source

Add three dashboard visual-direction samplers as static HTML

Three standalone, self-contained mocks of the same dashboard for the
upcoming overhaul: Curated Primer (GitHub/Primer lineage, light-first),
Control Room (dark-first, mono-forward), Swiss Flat (strict grid, one
accent). Identical body markup across all three so the comparison is
purely visual; embedded CSS only, no JS, no external assets, openable
via file://. Each supports light and dark via prefers-color-scheme.

Content follows the approved hierarchy: advisor composer as the first
and most prominent control, needs-a-human items tiered above queue
health, ambient notes/discoveries/tasks/activity at reduced density
with collapsed details. Sample data uses the real status vocabulary
(draft/queued/working/blocked/suspended/done/failed, saddle
idle/busy/offline) and deliberately uneven sections.

README.md records each direction's token set as the candidate :root
for the overhaul goal. No app code touched.
saddle-ClankerSaddle il y a 3 semaines
Parent
commit
288eb3f2d0
4 fichiers modifiés avec 1722 ajouts et 0 suppressions
  1. 130 0
      mocks/README.md
  2. 531 0
      mocks/dashboard-control.html
  3. 539 0
      mocks/dashboard-primer.html
  4. 522 0
      mocks/dashboard-swiss.html

+ 130 - 0
mocks/README.md

@@ -0,0 +1,130 @@
+# Dashboard visual directions — static HTML samplers
+
+Three standalone, fully self-contained mocks of the SAME dashboard.
+No frameworks, no build step, no external assets — embedded CSS only.
+Open directly via `file://`. Each supports light AND dark via
+`prefers-color-scheme` (verify by toggling devtools scheme emulation).
+
+- `dashboard-primer.html` — 1 Curated Primer (light-first)
+- `dashboard-control.html` — 2 Control Room (dark-first)
+- `dashboard-swiss.html` — 3 Swiss Flat (light-first)
+
+All three carry IDENTICAL content structure (the `<body>` markup is
+byte-identical apart from the sampler number/label in the note line
+and footer), so the comparison is purely visual.
+
+## Content model (per the approved hierarchy)
+
+- Zone 1 (top): advisor conversation composer — the first, most
+  prominent control — plus a believable recent exchange (user
+  question, advisor answer with a suggested task, follow-up).
+- Zone 2 (one small scroll below): "Needs a human" items tiered ABOVE
+  queue health — a completion awaiting review, a turn-cap parked task
+  to wake, an open question to answer; then running / stuck / queued
+  counts and saddle states.
+- Zone 3 (ambient, reduced density): notes, latest discoveries,
+  active tasks table and activity timeline — collapsed `<details>`
+  where sensible (tasks and activity start collapsed; notes and
+  discoveries open).
+
+Sample data uses the real app's vocabulary: statuses
+draft / queued / assigned / working / blocked / review_requested /
+suspended / done / failed; saddle states idle / busy / offline;
+blocks review / question; turn-cap parks. Task titles reference real
+recent fleet work. Sections are deliberately uneven — one saddle
+offline, one task with no latest progress, a sparse notes list —
+because perfection reads fake.
+
+## Direction 1 — Curated Primer
+
+GitHub/Primer lineage, disciplined, light default. Cards on a sunken
+page, 8px grid, 8px radius, tinted status pills, the existing blue as
+accent. The natural evolution of today's `app.css`.
+
+:root (light):
+```
+--surface-sunken #f6f8fa   --surface #ffffff    --surface-inset #eff2f5
+--ink #1f2328               --ink-muted #59636e  --ink-faint #6e7681
+--line #d1d9e0              --line-soft #e4eaef
+--accent #0969da            --accent-surface #ddf4ff
+--success #1a7f37           --warning #9a6700    --danger #cf222e
+--radius 8px
+```
+Dark variant: `--surface-sunken #0d1117`, `--surface #151b23`,
+`--surface-inset #1c2430`, `--ink #e6edf3`, `--ink-muted #9198a1`,
+`--ink-faint #6e7681`, `--line #3d444d`, `--line-soft #262c36`,
+`--accent #4493f8`, `--accent-surface #121d2f`, `--success #3fb950`,
+`--warning #d29922`, `--danger #f85149`.
+
+Status = tinted pill pairs: working/blocked/queued on yellow tints,
+done/progress green tints, failed red tint, review orange tint,
+question blue tint, parked/suspended neutral. Type: system-ui 15px.
+Shadows: none (1px borders only).
+
+## Direction 2 — Control Room
+
+Dark-first, mono-forward, mission-console restraint. Quiet cold
+neutrals; status colour carries the meaning; labels and numerals in
+mono. Status reads as small outline capsules in the status hue —
+colour IS the signal, fill stays quiet. Light variant is a working
+console on white, not an afterthought.
+
+:root (dark, default):
+```
+--bg #0f1317   --surface #151a20   --raise #1c232b
+--ink #c9d4de  --dim #7e8b98       --faint #525e6a
+--rule #262e38 --rule-hi #394450
+--run #4cc38a  --warn #f5b452  --crit #ef6460  --info #58a6ff
+--accent #58a6ff  --radius 4px
+--mono ui-monospace …  --sans system-ui …
+```
+Light variant: `--bg #eef1f4`, `--surface #ffffff`, `--raise #f4f6f8`,
+`--ink #1b2530`, `--dim #54626f`, `--faint #75828e`, `--rule #d7dee4`,
+`--rule-hi #b4c0ca`, `--run #10735a`, `--warn #8f5b00`,
+`--crit #c3362f`, `--info #0a5dc2`.
+
+Status semantics: run=green (running/done/busy), warn=amber
+(queued/blocked/review/stuck), crit=red (failed), info=blue
+(interactive/question). Type: sans 14px body, mono for labels,
+metrics, meta and times. Radius 4px; no shadows; saddle states are
+tiny square lamps (filled / outline / dashed).
+
+## Direction 3 — Swiss Flat
+
+Strict grid, typographic hierarchy, one strong accent, no shadows, no
+ornament. Structure lines are INK, not grey; the frame is the design.
+A hard left rail carries brand + zone labels; metrics are oversized
+light numerals (weight 200). Status is typography: weight and colour
+in near-black / greys, with red reserved for failure and the accent.
+
+:root (light):
+```
+--paper #fdfdfb  --ink #111111  --grey-1 #6b6b6b  --grey-2 #82827e
+--rule #111111   --rule-thin #d9d9d6
+--red #e2231a    --radius 0
+--font "Helvetica Neue" …  --mono ui-monospace …
+```
+Dark variant: `--paper #121212`, `--ink #f0f0ec`, `--grey-1 #a8a8a4`,
+`--grey-2 #7c7c78`, `--rule #f0f0ec`, `--rule-thin #2e2e2c`,
+`--red #ff4438`.
+
+Status: failed and the single accent share red; everything else is
+typographic (bold caps tags, question underlined in ink). Links are
+ink with a thin grey underline; red appears on hover and on the
+primary button. Radius 0, no shadows, 2px structural rules.
+
+## Anti-slop checklist (honoured by all three)
+
+No purple-blue gradients, no glassmorphism, no oversized drop
+shadows, no marketing hero, no emoji decoration, no fake-perfect
+symmetry. Status palettes avoid the blue/purple wash; accent use is
+rationed.
+
+## Verification performed
+
+- Files open standalone via `file://` (Chromium 154 headless).
+- Light/dark flip verified per file via forced scheme: page
+  backgrounds and every status colour change to the intended tokens;
+  content extents identical between schemes (no reflow breakage).
+- The three `<body>` blocks verified identical modulo sampler label.
+- 390px mobile: no horizontal overflow; all zones render.

+ 531 - 0
mocks/dashboard-control.html

@@ -0,0 +1,531 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Clanker-Saddle dashboard &mdash; Control Room (sampler 2 of 3)</title>
+<style>
+/* DIRECTION 2 — CONTROL ROOM. Dark-first, mono-forward, quiet neutrals;
+   status colour carries the meaning. Light variant via scheme query. */
+:root {
+    --bg: #0f1317;            /* page: near-black, cold */
+    --surface: #151a20;       /* panels */
+    --raise: #1c232b;         /* hover wells, inputs */
+    --ink: #c9d4de;           /* primary text */
+    --dim: #7e8b98;           /* secondary text */
+    --faint: #525e6a;         /* meta, rules */
+    --rule: #262e38;          /* hairlines */
+    --rule-hi: #394450;       /* emphasized edges */
+    --run: #4cc38a;           /* running / done / busy */
+    --warn: #f5b452;          /* queued / blocked / review */
+    --crit: #ef6460;          /* failed / stuck */
+    --info: #58a6ff;          /* interactive / question */
+    --accent: #58a6ff;        /* actions ride info blue, quietly */
+    --radius: 4px;
+    --mono: ui-monospace, "Cascadia Code", Menlo, Consolas, monospace;
+    --sans: system-ui, -apple-system, "Segoe UI", sans-serif;
+}
+@media (prefers-color-scheme: light) {
+    :root {
+        --bg: #eef1f4;
+        --surface: #ffffff;
+        --raise: #f4f6f8;
+        --ink: #1b2530;
+        --dim: #54626f;
+        --faint: #75828e;
+        --rule: #d7dee4;
+        --rule-hi: #b4c0ca;
+        --run: #10735a;
+        --warn: #8f5b00;
+        --crit: #c3362f;
+        --info: #0a5dc2;
+        --accent: #0a5dc2;
+    }
+}
+
+* { box-sizing: border-box; }
+html { scrollbar-gutter: stable; }
+body {
+    margin: 0;
+    font: 14px/1.55 var(--sans);
+    color: var(--ink);
+    background: var(--bg);
+}
+a { color: var(--info); text-decoration: none; }
+a:hover { text-decoration: underline; }
+h1, h2, .hint, .tag, .metric dt, .when, dt, th, .sampler-note, .who { font-family: var(--mono); }
+
+.top {
+    display: flex; align-items: baseline; gap: 1.25rem;
+    border-bottom: 1px solid var(--rule-hi);
+    background: var(--surface);
+    padding: 0.7rem 1.25rem;
+}
+.brand {
+    margin: 0; font-family: var(--mono); font-size: 0.875rem; font-weight: 700;
+    letter-spacing: 0.04em; color: var(--ink);
+}
+.top-nav { display: flex; gap: 1rem; flex: 1; flex-wrap: wrap; }
+.top-nav a {
+    font-family: var(--mono); font-size: 0.75rem; text-transform: uppercase;
+    letter-spacing: 0.06em; color: var(--dim);
+}
+.top-nav a:hover { color: var(--info); text-decoration: none; }
+.who { margin: 0; font-size: 0.75rem; color: var(--faint); }
+
+main { max-width: 70rem; margin: 0 auto; padding: 1.25rem 1.25rem 3rem; }
+.sampler-note {
+    font-size: 0.75rem; color: var(--faint); margin: 0 0 1.25rem;
+    border: 1px solid var(--rule); border-radius: var(--radius);
+    padding: 0.4rem 0.6rem; display: inline-block;
+}
+.sampler-note a { color: var(--dim); }
+
+/* ---- ZONE 1 ---- */
+.zone-advisor h1 {
+    margin: 0 0 0.3rem; font-size: 1.0625rem; font-weight: 700;
+    letter-spacing: 0.02em; text-transform: uppercase;
+}
+.lede { margin: 0 0 1rem; color: var(--dim); max-width: 46rem; font-size: 0.9375rem; }
+
+.composer {
+    border: 1px solid var(--rule-hi); border-radius: var(--radius);
+    background: var(--surface); padding: 0.6rem;
+}
+.composer:focus-within { border-color: var(--info); }
+.composer textarea {
+    display: block; width: 100%; border: none; resize: vertical;
+    background: transparent; color: var(--ink); font: inherit; padding: 0.35rem 0.45rem;
+}
+.composer textarea:focus { outline: none; }
+.composer textarea::placeholder { color: var(--faint); }
+.composer-bar {
+    display: flex; align-items: center; justify-content: space-between;
+    gap: 1rem; margin-top: 0.4rem; padding: 0 0.2rem;
+}
+.hint { margin: 0; font-size: 0.75rem; color: var(--faint); }
+
+.btn {
+    font: 0.8125rem var(--mono); cursor: pointer;
+    border: 1px solid var(--rule-hi); border-radius: var(--radius);
+    background: var(--raise); color: var(--ink);
+    padding: 0.3rem 0.85rem;
+}
+.btn:hover { border-color: var(--dim); }
+.btn.primary {
+    background: var(--accent); border-color: var(--accent); color: #0b0f13;
+    font-weight: 700;
+}
+@media (prefers-color-scheme: light) {
+    .btn.primary { color: #ffffff; }
+}
+.btn.quiet { color: var(--dim); }
+
+.exchange { margin-top: 1.4rem; }
+.exchange h2 {
+    font-size: 0.75rem; margin: 0 0 0.75rem; font-weight: 600;
+    text-transform: uppercase; letter-spacing: 0.08em; color: var(--dim);
+    display: flex; gap: 0.75rem; align-items: baseline;
+}
+.exchange h2 .more { font-size: 0.75rem; text-transform: none; letter-spacing: 0; }
+.msg { max-width: 44rem; margin-bottom: 0.7rem; }
+.msg p { margin: 0; }
+.from-user { text-align: right; }
+.from-user p {
+    display: inline-block; text-align: left;
+    background: var(--raise); border: 1px solid var(--rule);
+    border-radius: var(--radius); padding: 0.5rem 0.8rem;
+}
+.from-advisor > p {
+    border-left: 2px solid var(--rule-hi); padding-left: 0.85rem;
+}
+.suggested {
+    border: 1px solid var(--rule-hi); border-left: 2px solid var(--info);
+    border-radius: var(--radius); padding: 0.6rem 0.85rem; margin-top: 0.6rem;
+    background: var(--surface); max-width: 40rem;
+}
+.suggested-kind {
+    margin: 0 0 0.25rem; font-family: var(--mono); font-size: 0.6875rem;
+    text-transform: uppercase; letter-spacing: 0.1em; color: var(--info); font-weight: 700;
+}
+.suggested-title { margin: 0 0 0.2rem; font-weight: 600; }
+.suggested-meta { margin: 0 0 0.6rem; font-size: 0.8125rem; color: var(--dim); font-family: var(--mono); }
+.suggested-actions { display: flex; gap: 0.5rem; }
+.all-chats { font-size: 0.875rem; margin: 0.9rem 0 0; }
+
+/* ---- ZONE 2 ---- */
+.zone-status {
+    margin-top: 2rem; padding-top: 1.1rem; border-top: 1px solid var(--rule-hi);
+    display: grid; grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr); gap: 1.5rem;
+}
+.zone-status h2 {
+    font-size: 0.75rem; margin: 0 0 0.75rem; font-weight: 600;
+    text-transform: uppercase; letter-spacing: 0.08em; color: var(--dim);
+}
+.count { margin-left: 0.4rem; color: var(--faint); font-weight: 500; font-size: 0.75rem; }
+.needs-list { list-style: none; margin: 0; padding: 0; }
+.need {
+    display: grid; grid-template-columns: 6.5rem minmax(0, 1fr) auto;
+    gap: 0.9rem; padding: 0.7rem 0; align-items: start;
+    border-top: 1px solid var(--rule);
+}
+.need:first-child { border-top: none; padding-top: 0; }
+.need-kind { margin: 0.15rem 0 0; }
+.need-title { margin: 0 0 0.15rem; font-weight: 550; }
+.need-meta { margin: 0; font-size: 0.8125rem; color: var(--dim); font-family: var(--mono); }
+.need-act { margin: 0; display: flex; gap: 0.5rem; flex-wrap: wrap; }
+
+.tag {
+    display: inline-block; font-size: 0.6875rem; font-weight: 600;
+    padding: 0.05rem 0.45rem; border-radius: 2px; line-height: 1.55;
+    text-transform: uppercase; letter-spacing: 0.05em;
+    border: 1px solid currentColor; background: transparent;
+}
+.tag.review, .tag.working, .tag.blocked, .tag.queued { color: var(--warn); }
+.tag.question { color: var(--info); }
+.tag.parked, .tag.suspended, .tag.system { color: var(--dim); }
+.tag.done, .tag.progress { color: var(--run); }
+.tag.failed { color: var(--crit); }
+.tag.comment { color: var(--faint); }
+
+.health { border-left: 1px solid var(--rule); padding-left: 1.5rem; }
+.metrics { display: grid; grid-template-columns: repeat(4, 1fr); margin: 0 0 1rem; gap: 0.5rem; }
+.metric dt { font-size: 0.6875rem; color: var(--faint); text-transform: uppercase; letter-spacing: 0.07em; }
+.metric dd {
+    margin: 0.15rem 0 0; font-family: var(--mono); font-size: 1.7rem; font-weight: 700;
+    font-variant-numeric: tabular-nums; line-height: 1.1; color: var(--ink);
+}
+.metric dd.warn { color: var(--warn); }
+.saddles { list-style: none; margin: 0; padding: 0; font-size: 0.8125rem; font-family: var(--mono); }
+.saddles li { display: flex; align-items: center; gap: 0.5rem; padding: 0.28rem 0; }
+.state {
+    width: 0.55rem; height: 0.55rem; border-radius: 1px;
+    display: inline-block; flex: none;
+}
+.state.busy { background: var(--run); box-shadow: 0 0 0 1px var(--run); }
+.state.idle { background: transparent; border: 1px solid var(--dim); box-shadow: none; }
+.state.offline { background: transparent; border: 1px dashed var(--faint); box-shadow: none; }
+
+/* ---- ZONE 3 ---- */
+.zone-ambient { margin-top: 2rem; padding-top: 1.1rem; border-top: 1px solid var(--rule-hi); }
+.panel { margin-bottom: 1.1rem; }
+.panel > summary {
+    cursor: pointer; list-style: none; display: flex; align-items: baseline; gap: 0.5rem;
+}
+.panel > summary::-webkit-details-marker { display: none; }
+.panel > summary::after { content: "+"; color: var(--faint); font-family: var(--mono); }
+.panel[open] > summary::after { content: "–"; }
+.panel > summary h2 {
+    font-size: 0.75rem; font-weight: 600; margin: 0; text-transform: uppercase;
+    letter-spacing: 0.08em; color: var(--dim);
+}
+.summary-meta { font-family: var(--mono); font-size: 0.75rem; color: var(--faint); }
+.panel > ul, .panel > table, .panel > p { margin-top: 0.75rem; }
+
+.notes { list-style: none; margin: 0.75rem 0 0; padding: 0; }
+.note { display: flex; gap: 0.6rem; padding: 0.4rem 0; }
+.note-state {
+    flex: none; width: 0.8rem; height: 0.8rem; margin-top: 0.2rem;
+    border: 1px solid var(--faint); border-radius: 1px;
+}
+.note.done .note-state { background: var(--run); border-color: var(--run); }
+.note.promoted .note-state { border-color: var(--info); background: transparent;
+    box-shadow: inset 0 0 0 2px var(--surface), inset 0 0 0 4px var(--info); }
+.note-body p:first-child { margin: 0 0 0.1rem; }
+.note-meta { font-size: 0.75rem; color: var(--faint); font-family: var(--mono); }
+.note.done .note-body p:first-child { color: var(--dim); }
+
+.discoveries { list-style: none; margin: 0.75rem 0 0; padding: 0; max-width: 50rem; }
+.discoveries li { padding: 0.4rem 0; border-top: 1px solid var(--rule); }
+.discoveries li:first-child { border-top: none; }
+.discoveries li > p:first-child { margin: 0 0 0.1rem; }
+.more-row { margin: 0.5rem 0 0; font-size: 0.8125rem; }
+
+.tasks { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }
+.tasks th {
+    text-align: left; font-size: 0.6875rem; font-weight: 600; text-transform: uppercase;
+    letter-spacing: 0.07em; color: var(--faint); padding: 0.3rem 0.75rem 0.3rem 0;
+    border-bottom: 1px solid var(--rule-hi);
+}
+.tasks td {
+    padding: 0.45rem 0.75rem 0.45rem 0; border-bottom: 1px solid var(--rule);
+    vertical-align: top;
+}
+.tasks td.empty { color: var(--faint); }
+.tasks .when, .when { color: var(--faint); font-family: var(--mono); font-size: 0.75rem; }
+
+.activity { list-style: none; margin: 0.75rem 0 0; padding: 0; font-size: 0.8125rem; }
+.activity li { display: flex; gap: 0.75rem; padding: 0.28rem 0; }
+.activity .when {
+    flex: none; width: 3.4rem; font-variant-numeric: tabular-nums;
+}
+.activity .what { margin: 0; }
+.activity .what a { font-weight: 500; }
+
+.foot {
+    border-top: 1px solid var(--rule-hi); color: var(--faint);
+    font-family: var(--mono); font-size: 0.75rem;
+    padding: 0.9rem 1.25rem;
+}
+.foot p { margin: 0; max-width: 70rem; margin-inline: auto; }
+
+@media (max-width: 50rem) {
+    .zone-status { grid-template-columns: 1fr; }
+    .health { border-left: none; padding-left: 0; border-top: 1px solid var(--rule); padding-top: 1rem; }
+    .need { grid-template-columns: minmax(0, 1fr); }
+    .need-kind { margin: 0; }
+    .need-act { margin-top: 0.2rem; }
+}
+
+</style>
+</head>
+<body>
+<header class="top">
+    <p class="brand">Clanker-Saddle</p>
+    <nav class="top-nav" aria-label="Primary">
+        <a href="#">Queue</a>
+        <a href="#">Tasks</a>
+        <a href="#">Goals</a>
+        <a href="#">Discoveries</a>
+        <a href="#">Saddles</a>
+    </nav>
+    <p class="who">marta &middot; web-stack</p>
+</header>
+
+<main id="main">
+    <p class="sampler-note">Sampler 2 of 3 &mdash; Control Room. Static mock, not live data.
+        <a href="dashboard-primer.html">1 Curated Primer</a> &middot;
+        <a href="dashboard-control.html">2 Control Room</a> &middot;
+        <a href="dashboard-swiss.html">3 Swiss Flat</a></p>
+
+    <!-- ZONE 1: the advisor conversation composer, first and loudest -->
+    <section class="zone-advisor" aria-labelledby="advisor-h">
+        <h1 id="advisor-h">Ask the advisor</h1>
+        <p class="lede">Reads your projects, tasks, goals, rules and discoveries &mdash; asks
+            you questions and suggests work. It never runs commands.</p>
+        <form class="composer" onsubmit="return false">
+            <textarea rows="3" placeholder="What should the fleet work on next?"></textarea>
+            <div class="composer-bar">
+                <p class="hint">claude-sonnet &middot; last fleet snapshot 14:02</p>
+                <button type="submit" class="btn primary">Start chat</button>
+            </div>
+        </form>
+
+        <section class="exchange" aria-label="Recent advisor exchange">
+            <h2>Yesterday &mdash; goal-branch view <a class="more" href="#">open chat</a></h2>
+            <div class="msg from-user">
+                <p>Can the goal-branch view show parked runs separately from failed ones?</p>
+            </div>
+            <div class="msg from-advisor">
+                <p>They share a column today. Three open goals carry parked runs, all
+                    turn-cap parks from the ghost-working sweep; none failed this week.
+                    I can suggest the split as a task on web-stack.</p>
+                <div class="suggested">
+                    <p class="suggested-kind">suggested task</p>
+                    <p class="suggested-title">Split parked and failed runs on the goal branch view</p>
+                    <p class="suggested-meta">Clanker-Saddle &middot; branch goal/branch-view</p>
+                    <div class="suggested-actions">
+                        <button type="button" class="btn">Create draft</button>
+                        <button type="button" class="btn quiet">Discard</button>
+                    </div>
+                </div>
+            </div>
+            <div class="msg from-user">
+                <p>Hold on that. How many of the parked runs are older than a day?</p>
+            </div>
+            <div class="msg from-advisor">
+                <p>Two &mdash; both parked since 2 Oct on the notifications goal.
+                    <a href="#">Open goal 24 &rarr;</a></p>
+            </div>
+        </section>
+        <p class="all-chats"><a href="#">All 14 chats &rarr;</a></p>
+    </section>
+
+    <!-- ZONE 2: compact status strip. Needs-you items sit above queue health. -->
+    <section class="zone-status" aria-labelledby="needs-h">
+        <div class="needs">
+            <h2 id="needs-h">Needs a human <span class="count">3</span></h2>
+            <ol class="needs-list">
+                <li class="need">
+                    <p class="need-kind"><span class="tag review">review</span></p>
+                    <div class="need-body">
+                        <p class="need-title"><a href="#">Ghost-working sweep: requeue stale open
+                            sessions from the dispatcher tick</a></p>
+                        <p class="need-meta">task 211 &middot; Clanker-Saddle &middot; report waiting 12 min</p>
+                    </div>
+                    <p class="need-act"><button type="button" class="btn">Review report</button></p>
+                </li>
+                <li class="need">
+                    <p class="need-kind"><span class="tag parked">parked</span></p>
+                    <div class="need-body">
+                        <p class="need-title"><a href="#">Goal compare: diff two branches&rsquo;
+                            task trees</a></p>
+                        <p class="need-meta">task 198 &middot; hit the 40-turn cap at 13:51 &middot;
+                            wake to continue, or leave it parked</p>
+                    </div>
+                    <p class="need-act"><button type="button" class="btn">Wake</button>
+                        <button type="button" class="btn quiet">Leave parked</button></p>
+                </li>
+                <li class="need">
+                    <p class="need-kind"><span class="tag question">question</span></p>
+                    <div class="need-body">
+                        <p class="need-title">Should the discovery list paginate at 50 rows, or
+                            keep one long scroll?</p>
+                        <p class="need-meta">task 197 &middot; asked 2 h ago &middot; options 50 / 100 / keep scroll</p>
+                    </div>
+                    <p class="need-act"><button type="button" class="btn">Answer</button></p>
+                </li>
+            </ol>
+        </div>
+
+        <div class="health">
+            <h2>Queue health</h2>
+            <dl class="metrics">
+                <div class="metric"><dt>running</dt><dd>3</dd></div>
+                <div class="metric"><dt>stuck</dt><dd class="warn">1</dd></div>
+                <div class="metric"><dt>queued</dt><dd>5</dd></div>
+                <div class="metric"><dt>draft</dt><dd>2</dd></div>
+            </dl>
+            <ul class="saddles">
+                <li><span class="state busy"></span>atlas &mdash; busy &middot; task 214</li>
+                <li><span class="state busy"></span>meridian &mdash; busy &middot; goal 31</li>
+                <li><span class="state idle"></span>kestrel &mdash; idle &middot; 41 min</li>
+                <li><span class="state offline"></span>portland &mdash; offline &middot; 3 h</li>
+            </ul>
+        </div>
+    </section>
+
+    <!-- ZONE 3: ambient. Reduced density, collapsed where sensible. -->
+    <section class="zone-ambient" aria-label="Ambient">
+        <details class="panel" open>
+            <summary><h2>Notes</h2><span class="summary-meta">3</span></summary>
+            <ul class="notes">
+                <li class="note open"><span class="note-state"></span>
+                    <div class="note-body">
+                        <p>Dashboard hierarchy: advisor first, needs-you second, ambient
+                            below &mdash; decide between the three samplers before touching app.css.</p>
+                        <p class="note-meta">today 13:04</p>
+                    </div>
+                </li>
+                <li class="note done"><span class="note-state"></span>
+                    <div class="note-body">
+                        <p>Check goal badge contrast under the dark scheme.</p>
+                        <p class="note-meta">yesterday &middot; done</p>
+                    </div>
+                </li>
+                <li class="note promoted"><span class="note-state"></span>
+                    <div class="note-body">
+                        <p>Ship the web-push test notification end to end.</p>
+                        <p class="note-meta">promoted to <a href="#">goal 24</a></p>
+                    </div>
+                </li>
+            </ul>
+        </details>
+
+        <details class="panel" open>
+            <summary><h2>Latest discoveries</h2><span class="summary-meta">2</span></summary>
+            <ul class="discoveries">
+                <li>
+                    <p>json-glib writes invalid UTF-8 verbatim: a byte-count clamp that lands
+                        mid-character poisons the whole payload, and the stored row loses its
+                        members on read-back. Back the cut off over continuation bytes at every
+                        serialisation boundary.</p>
+                    <p class="note-meta">2 Oct &middot; Saddle</p>
+                </li>
+                <li>
+                    <p>A harness seeding a row the app also lazily creates must INSERT OR
+                        IGNORE &mdash; two read-then-insert writers race and the loser dies on
+                        UNIQUE, taking the whole sequential suite with it.</p>
+                    <p class="note-meta">1 Oct &middot; Clanker-Saddle</p>
+                </li>
+            </ul>
+            <p class="more-row"><a href="#">All discoveries &rarr;</a></p>
+        </details>
+
+        <details class="panel">
+            <summary><h2>Active tasks</h2><span class="summary-meta">6</span></summary>
+            <table class="tasks">
+                <thead>
+                <tr><th>Task</th><th>Status</th><th>Branch</th><th>Latest</th></tr>
+                </thead>
+                <tbody>
+                <tr>
+                    <td><a href="#">214 &middot; Mock dashboard: three visual directions as static
+                        HTML samplers</a></td>
+                    <td><span class="tag working">working</span></td>
+                    <td>web-stack</td>
+                    <td>writing mocks/dashboard-primer.html <span class="when">14:02</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">213 &middot; Split parked and failed runs on the goal branch
+                        view</a></td>
+                    <td><span class="tag queued">queued</span></td>
+                    <td>goal/branch-view</td>
+                    <td class="empty">&mdash;</td>
+                </tr>
+                <tr>
+                    <td><a href="#">198 &middot; Goal compare: diff two branches&rsquo; task
+                        trees</a></td>
+                    <td><span class="tag suspended">suspended</span></td>
+                    <td>goal/compare</td>
+                    <td>parked at turn cap 41/40 <span class="when">13:51</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">196 &middot; Notification digest: batch question and RFC
+                        pushes</a></td>
+                    <td><span class="tag blocked">blocked</span></td>
+                    <td>notify/digest</td>
+                    <td>asked: digest window 5 or 15 min <span class="when">12:37</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">189 &middot; Rate-limit the events endpoint</a></td>
+                    <td><span class="tag failed">failed</span></td>
+                    <td>api/rate-limit</td>
+                    <td>429 loop under parallel suites; needs backoff <span class="when">11:20</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">195 &middot; Advisor chat export to markdown</a></td>
+                    <td><span class="tag done">done</span></td>
+                    <td>advisor/export</td>
+                    <td>report accepted <span class="when">09:58</span></td>
+                </tr>
+                </tbody>
+            </table>
+        </details>
+
+        <details class="panel">
+            <summary><h2>Activity</h2><span class="summary-meta">7 events</span></summary>
+            <ul class="activity">
+                <li><p class="when">14:02</p>
+                    <p class="what"><span class="tag progress">progress</span> <a href="#">214</a>
+                        writing mocks/dashboard-primer.html</p></li>
+                <li><p class="when">13:58</p>
+                    <p class="what"><span class="tag question">question</span> <a href="#">197</a>
+                        discovery list pagination &mdash; 50, 100, or one scroll?</p></li>
+                <li><p class="when">13:50</p>
+                    <p class="what"><span class="tag review">review</span> <a href="#">211</a>
+                        report ready &mdash; ghost-working sweep</p></li>
+                <li><p class="when">13:44</p>
+                    <p class="what"><span class="tag comment">comment</span> goal 31 &mdash;
+                        &ldquo;keep needs-a-human above queue health&rdquo;</p></li>
+                <li><p class="when">13:31</p>
+                    <p class="what"><span class="tag progress">progress</span> <a href="#">196</a>
+                        digest skeleton, window still undecided</p></li>
+                <li><p class="when">13:04</p>
+                    <p class="what"><span class="tag system">saddle</span> kestrel idle after
+                        task 197 parked</p></li>
+                <li><p class="when">11:20</p>
+                    <p class="what"><span class="tag failed">failed</span> <a href="#">189</a>
+                        exit 1 &mdash; 429 loop under parallel suites</p></li>
+            </ul>
+        </details>
+    </section>
+</main>
+
+<footer class="foot">
+    <p>Control Room sampler &middot; static mock for the dashboard overhaul &middot; toggle your
+        OS or devtools colour scheme to check the second variant</p>
+</footer>
+
+</body>
+</html>

+ 539 - 0
mocks/dashboard-primer.html

@@ -0,0 +1,539 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Clanker-Saddle dashboard &mdash; Curated Primer (sampler 1 of 3)</title>
+<style>
+/* DIRECTION 1 — CURATED PRIMER. GitHub/Primer lineage, disciplined.
+   ~14 named tokens; the existing blue #0969da as accent; light default. */
+:root {
+    --surface-sunken: #f6f8fa;   /* page */
+    --surface: #ffffff;          /* cards */
+    --surface-inset: #eff2f5;    /* wells, code chips */
+    --ink: #1f2328;              /* primary text */
+    --ink-muted: #59636e;        /* secondary text */
+    --ink-faint: #6e7681;        /* meta, placeholders */
+    --line: #d1d9e0;             /* card borders */
+    --line-soft: #e4eaef;        /* dividers */
+    --accent: #0969da;           /* the existing blue */
+    --accent-surface: #ddf4ff;   /* selected/tinted blue */
+    --success: #1a7f37;          /* done / running / idle */
+    --warning: #9a6700;          /* queued / blocked / review */
+    --danger: #cf222e;           /* failed / stuck */
+    --radius: 8px;
+    --font-mono: ui-monospace, "Cascadia Code", Menlo, Consolas, monospace;
+}
+@media (prefers-color-scheme: dark) {
+    :root {
+        --surface-sunken: #0d1117;
+        --surface: #151b23;
+        --surface-inset: #1c2430;
+        --ink: #e6edf3;
+        --ink-muted: #9198a1;
+        --ink-faint: #6e7681;
+        --line: #3d444d;
+        --line-soft: #262c36;
+        --accent: #4493f8;
+        --accent-surface: #121d2f;
+        --success: #3fb950;
+        --warning: #d29922;
+        --danger: #f85149;
+    }
+}
+
+* { box-sizing: border-box; }
+html { scrollbar-gutter: stable; }
+body {
+    margin: 0;
+    font: 15px/1.55 system-ui, -apple-system, "Segoe UI", sans-serif;
+    color: var(--ink);
+    background: var(--surface-sunken);
+}
+a { color: var(--accent); text-decoration: none; }
+a:hover { text-decoration: underline; }
+
+.top {
+    display: flex; align-items: baseline; gap: 1rem;
+    max-width: 66rem; margin: 0 auto; padding: 0.9rem 1rem 0.7rem;
+    border-bottom: 1px solid var(--line);
+    background: var(--surface);
+}
+.brand {
+    margin: 0; font-size: 1rem; font-weight: 650; letter-spacing: -0.01em;
+    color: var(--ink);
+}
+.top-nav { display: flex; gap: 0.9rem; flex: 1; flex-wrap: wrap; }
+.top-nav a { color: var(--ink-muted); font-size: 0.875rem; }
+.top-nav a:hover { color: var(--accent); text-decoration: none; }
+.who { margin: 0; font-size: 0.8125rem; color: var(--ink-faint); }
+
+.sampler-note {
+    max-width: 66rem; margin: 0 auto 1rem; padding: 0.5rem 1rem 0;
+    font-size: 0.8125rem; color: var(--ink-faint);
+}
+.sampler-note a { color: var(--ink-muted); }
+
+main { max-width: 66rem; margin: 0 auto 3rem; padding: 0 1rem; }
+
+/* ---- ZONE 1: advisor, first and loudest ---- */
+.zone-advisor h1 {
+    margin: 0.2rem 0 0.35rem; font-size: 1.5rem; letter-spacing: -0.02em;
+}
+.lede { margin: 0 0 1rem; color: var(--ink-muted); max-width: 46rem; }
+
+.composer {
+    background: var(--surface); border: 1px solid var(--line);
+    border-radius: var(--radius); padding: 0.75rem;
+}
+.composer:focus-within { border-color: var(--accent); }
+.composer textarea {
+    display: block; width: 100%; border: none; resize: vertical;
+    background: transparent; color: var(--ink);
+    font: inherit; padding: 0.35rem 0.45rem;
+}
+.composer textarea:focus { outline: none; }
+.composer textarea::placeholder { color: var(--ink-faint); }
+.composer-bar {
+    display: flex; align-items: center; justify-content: space-between;
+    gap: 1rem; margin-top: 0.5rem; padding: 0 0.25rem;
+}
+.hint { margin: 0; font-size: 0.8125rem; color: var(--ink-faint); font-family: var(--font-mono); }
+
+.btn {
+    font: inherit; font-size: 0.875rem; cursor: pointer;
+    border: 1px solid var(--line); border-radius: 6px;
+    background: var(--surface); color: var(--ink);
+    padding: 0.3rem 0.9rem;
+}
+.btn:hover { border-color: var(--ink-muted); }
+.btn.primary {
+    background: var(--accent); border-color: rgba(31, 35, 40, 0.15);
+    color: #fff;
+}
+.btn.quiet { color: var(--ink-muted); }
+
+.exchange { margin-top: 1.4rem; }
+.exchange h2 {
+    font-size: 0.9375rem; margin: 0 0 0.75rem; font-weight: 600;
+    color: var(--ink-muted); display: flex; gap: 0.75rem; align-items: baseline;
+}
+.exchange h2 .more { font-size: 0.8125rem; }
+.msg { max-width: 44rem; margin-bottom: 0.75rem; }
+.msg p { margin: 0; }
+.from-user { margin-left: auto; padding-right: 0; text-align: right; }
+.from-user p { display: inline-block; text-align: left; }
+.from-user > p:first-child, .from-advisor > p:first-child { margin: 0; }
+.from-advisor { color: var(--ink); }
+.from-user > p {
+    background: var(--accent-surface); border-radius: 12px;
+    padding: 0.55rem 0.9rem; max-width: 40rem;
+}
+.from-advisor > p {
+    border-left: 2px solid var(--line); padding-left: 0.9rem;
+}
+.suggested {
+    border: 1px solid var(--line); border-left: 2px solid var(--accent);
+    border-radius: 6px; padding: 0.65rem 0.9rem; margin-top: 0.6rem;
+    background: var(--surface); max-width: 40rem;
+}
+.suggested-kind {
+    margin: 0 0 0.25rem; font-size: 0.6875rem; text-transform: uppercase;
+    letter-spacing: 0.08em; color: var(--accent); font-weight: 600;
+}
+.suggested-title { margin: 0 0 0.2rem; font-weight: 600; }
+.suggested-meta { margin: 0 0 0.6rem; font-size: 0.8125rem; color: var(--ink-muted); }
+.suggested-actions { display: flex; gap: 0.5rem; }
+.all-chats { font-size: 0.875rem; margin: 0.9rem 0 0; }
+
+/* ---- ZONE 2: compact status strip ---- */
+.zone-status {
+    margin-top: 2.2rem; padding-top: 1.2rem;
+    border-top: 1px solid var(--line);
+    display: grid; grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr);
+    gap: 1.5rem;
+}
+.zone-status h2 {
+    font-size: 0.9375rem; margin: 0 0 0.75rem; font-weight: 600;
+}
+.count {
+    margin-left: 0.4rem; color: var(--ink-faint); font-weight: 500; font-size: 0.8125rem;
+}
+.needs-list { list-style: none; margin: 0; padding: 0; }
+.need {
+    display: grid; grid-template-columns: 6.5rem minmax(0, 1fr) auto;
+    gap: 0.9rem; padding: 0.7rem 0; align-items: start;
+    border-top: 1px solid var(--line-soft);
+}
+.need:first-child { border-top: none; padding-top: 0; }
+.need-kind { margin: 0.15rem 0 0; }
+.need-title { margin: 0 0 0.15rem; font-weight: 550; }
+.need-meta { margin: 0; font-size: 0.8125rem; color: var(--ink-muted); }
+.need-act { margin: 0; display: flex; gap: 0.5rem; flex-wrap: wrap; }
+
+.tag {
+    display: inline-block; font-size: 0.6875rem; font-weight: 550;
+    padding: 0.1rem 0.5rem; border-radius: 10px; line-height: 1.5;
+}
+.tag.review { background: #fff1e0; color: #9a4700; }
+.tag.question { background: var(--accent-surface); color: var(--accent); }
+.tag.parked { background: var(--surface-inset); color: var(--ink-muted); }
+.tag.working { background: #fff8c5; color: var(--warning); }
+.tag.queued { background: #8884333d; color: #4d4d33; }
+.tag.suspended { background: var(--surface-inset); color: var(--ink-muted); }
+.tag.blocked { background: #fff8c5; color: #9a6700; }
+.tag.done { background: #dafbe1; color: var(--success); }
+.tag.failed { background: #ffebe9; color: var(--danger); }
+.tag.progress { background: #dafbe1; color: var(--success); }
+.tag.comment { background: #f0f0f0; color: #6e7781; }
+.tag.system { background: var(--surface-inset); color: var(--ink-muted); }
+@media (prefers-color-scheme: dark) {
+    .tag.review { background: #3d1e00; color: #d4a72c; }
+    .tag.question { background: #121d2f; color: #4493f8; }
+    .tag.working { background: #2b2b12; color: #d4a72c; }
+    .tag.queued { background: #2b2b12; color: #d4a72c; }
+    .tag.blocked { background: #2b2b12; color: #d4a72c; }
+    .tag.done, .tag.progress { background: #12261e; color: #3fb950; }
+    .tag.failed { background: #2d1214; color: #f85149; }
+    .tag.comment { background: #262c36; color: #9198a1; }
+}
+
+.health { border-left: 1px solid var(--line-soft); padding-left: 1.5rem; }
+.metrics { display: grid; grid-template-columns: repeat(4, 1fr); margin: 0 0 1rem; gap: 0.5rem; }
+.metric dt { font-size: 0.75rem; color: var(--ink-faint); text-transform: none; }
+.metric dd {
+    margin: 0.1rem 0 0; font-size: 1.6rem; font-weight: 650;
+    font-variant-numeric: tabular-nums; line-height: 1.1;
+}
+.metric dd.warn { color: var(--warning); }
+.saddles { list-style: none; margin: 0; padding: 0; font-size: 0.875rem; }
+.saddles li { display: flex; align-items: center; gap: 0.5rem; padding: 0.25rem 0; }
+.state {
+    width: 0.5rem; height: 0.5rem; border-radius: 50%;
+    display: inline-block; flex: none;
+}
+.state.busy { background: var(--success); }
+.state.idle { background: var(--ink-faint); }
+.state.offline { background: transparent; border: 1px solid var(--ink-faint); }
+
+/* ---- ZONE 3: ambient ---- */
+.zone-ambient { margin-top: 2.2rem; padding-top: 1.2rem; border-top: 1px solid var(--line); }
+.panel { margin-bottom: 1.1rem; }
+.panel > summary {
+    cursor: pointer; list-style: none; display: flex; align-items: baseline; gap: 0.5rem;
+}
+.panel > summary::-webkit-details-marker { display: none; }
+.panel > summary::after { content: "+"; color: var(--ink-faint); font-weight: 400; }
+.panel[open] > summary::after { content: "–"; }
+.panel > summary h2 {
+    font-size: 0.9375rem; font-weight: 600; margin: 0; color: var(--ink);
+}
+.summary-meta { font-size: 0.8125rem; color: var(--ink-faint); }
+.panel > div, .panel > ul, .panel > p, .panel > table { margin-top: 0.75rem; }
+
+.notes { list-style: none; margin: 0.75rem 0 0; padding: 0; }
+.note { display: flex; gap: 0.6rem; padding: 0.4rem 0; }
+.note-state {
+    flex: none; width: 0.8rem; height: 0.8rem; margin-top: 0.2rem;
+    border: 1px solid var(--ink-faint); border-radius: 3px;
+}
+.note.done .note-state { background: var(--success); border-color: var(--success); }
+.note.promoted .note-state {
+    background: var(--accent-surface); border-color: var(--accent);
+}
+.note-body p:first-child { margin: 0 0 0.1rem; }
+.note-meta { font-size: 0.8125rem; color: var(--ink-faint); }
+.note.done .note-body p:first-child { color: var(--ink-muted); }
+
+.discoveries { list-style: none; margin: 0.75rem 0 0; padding: 0; max-width: 50rem; }
+.discoveries li { padding: 0.4rem 0; border-top: 1px solid var(--line-soft); }
+.discoveries li:first-child { border-top: none; }
+.discoveries li > p:first-child { margin: 0 0 0.1rem; }
+.more-row { margin: 0.5rem 0 0; font-size: 0.875rem; }
+
+.tasks { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
+.tasks th {
+    text-align: left; font-size: 0.75rem; font-weight: 600;
+    color: var(--ink-faint); padding: 0.3rem 0.75rem 0.3rem 0;
+    border-bottom: 1px solid var(--line);
+}
+.tasks td {
+    padding: 0.45rem 0.75rem 0.45rem 0; border-bottom: 1px solid var(--line-soft);
+    vertical-align: top;
+}
+.tasks td.when, .tasks td.empty { color: var(--ink-faint); }
+.tasks .when { color: var(--ink-faint); }
+.when { color: var(--ink-faint); font-size: 0.8125rem; }
+
+.activity { list-style: none; margin: 0.75rem 0 0; padding: 0; font-size: 0.875rem; }
+.activity li { display: flex; gap: 0.75rem; padding: 0.28rem 0; }
+.activity .when { flex: none; width: 3.2rem; font-variant-numeric: tabular-nums; }
+.activity .what { margin: 0; }
+.activity .what a { font-weight: 500; }
+
+.foot {
+    max-width: 66rem; margin: 0 auto; padding: 1rem; font-size: 0.8125rem;
+    color: var(--ink-faint); border-top: 1px solid var(--line-soft);
+}
+.foot p { margin: 0; }
+
+@media (max-width: 50rem) {
+    .zone-status { grid-template-columns: 1fr; }
+    .health { border-left: none; padding-left: 0; border-top: 1px solid var(--line-soft); padding-top: 1rem; }
+    .need { grid-template-columns: minmax(0, 1fr); }
+    .need-kind { margin: 0; }
+    .need-act { margin-top: 0.2rem; }
+}
+
+</style>
+</head>
+<body>
+<header class="top">
+    <p class="brand">Clanker-Saddle</p>
+    <nav class="top-nav" aria-label="Primary">
+        <a href="#">Queue</a>
+        <a href="#">Tasks</a>
+        <a href="#">Goals</a>
+        <a href="#">Discoveries</a>
+        <a href="#">Saddles</a>
+    </nav>
+    <p class="who">marta &middot; web-stack</p>
+</header>
+
+<main id="main">
+    <p class="sampler-note">Sampler 1 of 3 &mdash; Curated Primer. Static mock, not live data.
+        <a href="dashboard-primer.html">1 Curated Primer</a> &middot;
+        <a href="dashboard-control.html">2 Control Room</a> &middot;
+        <a href="dashboard-swiss.html">3 Swiss Flat</a></p>
+
+    <!-- ZONE 1: the advisor conversation composer, first and loudest -->
+    <section class="zone-advisor" aria-labelledby="advisor-h">
+        <h1 id="advisor-h">Ask the advisor</h1>
+        <p class="lede">Reads your projects, tasks, goals, rules and discoveries &mdash; asks
+            you questions and suggests work. It never runs commands.</p>
+        <form class="composer" onsubmit="return false">
+            <textarea rows="3" placeholder="What should the fleet work on next?"></textarea>
+            <div class="composer-bar">
+                <p class="hint">claude-sonnet &middot; last fleet snapshot 14:02</p>
+                <button type="submit" class="btn primary">Start chat</button>
+            </div>
+        </form>
+
+        <section class="exchange" aria-label="Recent advisor exchange">
+            <h2>Yesterday &mdash; goal-branch view <a class="more" href="#">open chat</a></h2>
+            <div class="msg from-user">
+                <p>Can the goal-branch view show parked runs separately from failed ones?</p>
+            </div>
+            <div class="msg from-advisor">
+                <p>They share a column today. Three open goals carry parked runs, all
+                    turn-cap parks from the ghost-working sweep; none failed this week.
+                    I can suggest the split as a task on web-stack.</p>
+                <div class="suggested">
+                    <p class="suggested-kind">suggested task</p>
+                    <p class="suggested-title">Split parked and failed runs on the goal branch view</p>
+                    <p class="suggested-meta">Clanker-Saddle &middot; branch goal/branch-view</p>
+                    <div class="suggested-actions">
+                        <button type="button" class="btn">Create draft</button>
+                        <button type="button" class="btn quiet">Discard</button>
+                    </div>
+                </div>
+            </div>
+            <div class="msg from-user">
+                <p>Hold on that. How many of the parked runs are older than a day?</p>
+            </div>
+            <div class="msg from-advisor">
+                <p>Two &mdash; both parked since 2 Oct on the notifications goal.
+                    <a href="#">Open goal 24 &rarr;</a></p>
+            </div>
+        </section>
+        <p class="all-chats"><a href="#">All 14 chats &rarr;</a></p>
+    </section>
+
+    <!-- ZONE 2: compact status strip. Needs-you items sit above queue health. -->
+    <section class="zone-status" aria-labelledby="needs-h">
+        <div class="needs">
+            <h2 id="needs-h">Needs a human <span class="count">3</span></h2>
+            <ol class="needs-list">
+                <li class="need">
+                    <p class="need-kind"><span class="tag review">review</span></p>
+                    <div class="need-body">
+                        <p class="need-title"><a href="#">Ghost-working sweep: requeue stale open
+                            sessions from the dispatcher tick</a></p>
+                        <p class="need-meta">task 211 &middot; Clanker-Saddle &middot; report waiting 12 min</p>
+                    </div>
+                    <p class="need-act"><button type="button" class="btn">Review report</button></p>
+                </li>
+                <li class="need">
+                    <p class="need-kind"><span class="tag parked">parked</span></p>
+                    <div class="need-body">
+                        <p class="need-title"><a href="#">Goal compare: diff two branches&rsquo;
+                            task trees</a></p>
+                        <p class="need-meta">task 198 &middot; hit the 40-turn cap at 13:51 &middot;
+                            wake to continue, or leave it parked</p>
+                    </div>
+                    <p class="need-act"><button type="button" class="btn">Wake</button>
+                        <button type="button" class="btn quiet">Leave parked</button></p>
+                </li>
+                <li class="need">
+                    <p class="need-kind"><span class="tag question">question</span></p>
+                    <div class="need-body">
+                        <p class="need-title">Should the discovery list paginate at 50 rows, or
+                            keep one long scroll?</p>
+                        <p class="need-meta">task 197 &middot; asked 2 h ago &middot; options 50 / 100 / keep scroll</p>
+                    </div>
+                    <p class="need-act"><button type="button" class="btn">Answer</button></p>
+                </li>
+            </ol>
+        </div>
+
+        <div class="health">
+            <h2>Queue health</h2>
+            <dl class="metrics">
+                <div class="metric"><dt>running</dt><dd>3</dd></div>
+                <div class="metric"><dt>stuck</dt><dd class="warn">1</dd></div>
+                <div class="metric"><dt>queued</dt><dd>5</dd></div>
+                <div class="metric"><dt>draft</dt><dd>2</dd></div>
+            </dl>
+            <ul class="saddles">
+                <li><span class="state busy"></span>atlas &mdash; busy &middot; task 214</li>
+                <li><span class="state busy"></span>meridian &mdash; busy &middot; goal 31</li>
+                <li><span class="state idle"></span>kestrel &mdash; idle &middot; 41 min</li>
+                <li><span class="state offline"></span>portland &mdash; offline &middot; 3 h</li>
+            </ul>
+        </div>
+    </section>
+
+    <!-- ZONE 3: ambient. Reduced density, collapsed where sensible. -->
+    <section class="zone-ambient" aria-label="Ambient">
+        <details class="panel" open>
+            <summary><h2>Notes</h2><span class="summary-meta">3</span></summary>
+            <ul class="notes">
+                <li class="note open"><span class="note-state"></span>
+                    <div class="note-body">
+                        <p>Dashboard hierarchy: advisor first, needs-you second, ambient
+                            below &mdash; decide between the three samplers before touching app.css.</p>
+                        <p class="note-meta">today 13:04</p>
+                    </div>
+                </li>
+                <li class="note done"><span class="note-state"></span>
+                    <div class="note-body">
+                        <p>Check goal badge contrast under the dark scheme.</p>
+                        <p class="note-meta">yesterday &middot; done</p>
+                    </div>
+                </li>
+                <li class="note promoted"><span class="note-state"></span>
+                    <div class="note-body">
+                        <p>Ship the web-push test notification end to end.</p>
+                        <p class="note-meta">promoted to <a href="#">goal 24</a></p>
+                    </div>
+                </li>
+            </ul>
+        </details>
+
+        <details class="panel" open>
+            <summary><h2>Latest discoveries</h2><span class="summary-meta">2</span></summary>
+            <ul class="discoveries">
+                <li>
+                    <p>json-glib writes invalid UTF-8 verbatim: a byte-count clamp that lands
+                        mid-character poisons the whole payload, and the stored row loses its
+                        members on read-back. Back the cut off over continuation bytes at every
+                        serialisation boundary.</p>
+                    <p class="note-meta">2 Oct &middot; Saddle</p>
+                </li>
+                <li>
+                    <p>A harness seeding a row the app also lazily creates must INSERT OR
+                        IGNORE &mdash; two read-then-insert writers race and the loser dies on
+                        UNIQUE, taking the whole sequential suite with it.</p>
+                    <p class="note-meta">1 Oct &middot; Clanker-Saddle</p>
+                </li>
+            </ul>
+            <p class="more-row"><a href="#">All discoveries &rarr;</a></p>
+        </details>
+
+        <details class="panel">
+            <summary><h2>Active tasks</h2><span class="summary-meta">6</span></summary>
+            <table class="tasks">
+                <thead>
+                <tr><th>Task</th><th>Status</th><th>Branch</th><th>Latest</th></tr>
+                </thead>
+                <tbody>
+                <tr>
+                    <td><a href="#">214 &middot; Mock dashboard: three visual directions as static
+                        HTML samplers</a></td>
+                    <td><span class="tag working">working</span></td>
+                    <td>web-stack</td>
+                    <td>writing mocks/dashboard-primer.html <span class="when">14:02</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">213 &middot; Split parked and failed runs on the goal branch
+                        view</a></td>
+                    <td><span class="tag queued">queued</span></td>
+                    <td>goal/branch-view</td>
+                    <td class="empty">&mdash;</td>
+                </tr>
+                <tr>
+                    <td><a href="#">198 &middot; Goal compare: diff two branches&rsquo; task
+                        trees</a></td>
+                    <td><span class="tag suspended">suspended</span></td>
+                    <td>goal/compare</td>
+                    <td>parked at turn cap 41/40 <span class="when">13:51</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">196 &middot; Notification digest: batch question and RFC
+                        pushes</a></td>
+                    <td><span class="tag blocked">blocked</span></td>
+                    <td>notify/digest</td>
+                    <td>asked: digest window 5 or 15 min <span class="when">12:37</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">189 &middot; Rate-limit the events endpoint</a></td>
+                    <td><span class="tag failed">failed</span></td>
+                    <td>api/rate-limit</td>
+                    <td>429 loop under parallel suites; needs backoff <span class="when">11:20</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">195 &middot; Advisor chat export to markdown</a></td>
+                    <td><span class="tag done">done</span></td>
+                    <td>advisor/export</td>
+                    <td>report accepted <span class="when">09:58</span></td>
+                </tr>
+                </tbody>
+            </table>
+        </details>
+
+        <details class="panel">
+            <summary><h2>Activity</h2><span class="summary-meta">7 events</span></summary>
+            <ul class="activity">
+                <li><p class="when">14:02</p>
+                    <p class="what"><span class="tag progress">progress</span> <a href="#">214</a>
+                        writing mocks/dashboard-primer.html</p></li>
+                <li><p class="when">13:58</p>
+                    <p class="what"><span class="tag question">question</span> <a href="#">197</a>
+                        discovery list pagination &mdash; 50, 100, or one scroll?</p></li>
+                <li><p class="when">13:50</p>
+                    <p class="what"><span class="tag review">review</span> <a href="#">211</a>
+                        report ready &mdash; ghost-working sweep</p></li>
+                <li><p class="when">13:44</p>
+                    <p class="what"><span class="tag comment">comment</span> goal 31 &mdash;
+                        &ldquo;keep needs-a-human above queue health&rdquo;</p></li>
+                <li><p class="when">13:31</p>
+                    <p class="what"><span class="tag progress">progress</span> <a href="#">196</a>
+                        digest skeleton, window still undecided</p></li>
+                <li><p class="when">13:04</p>
+                    <p class="what"><span class="tag system">saddle</span> kestrel idle after
+                        task 197 parked</p></li>
+                <li><p class="when">11:20</p>
+                    <p class="what"><span class="tag failed">failed</span> <a href="#">189</a>
+                        exit 1 &mdash; 429 loop under parallel suites</p></li>
+            </ul>
+        </details>
+    </section>
+</main>
+
+<footer class="foot">
+    <p>Curated Primer sampler &middot; static mock for the dashboard overhaul &middot; toggle your
+        OS or devtools colour scheme to check the second variant</p>
+</footer>
+
+</body>
+</html>

+ 522 - 0
mocks/dashboard-swiss.html

@@ -0,0 +1,522 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Clanker-Saddle dashboard &mdash; Swiss Flat (sampler 3 of 3)</title>
+<style>
+/* DIRECTION 3 — SWISS FLAT. Strict grid, typographic hierarchy, one
+   strong accent, no shadows, no ornament. Light-first. */
+:root {
+    --paper: #fdfdfb;         /* page: warm white */
+    --ink: #111111;           /* text */
+    --grey-1: #6b6b6b;        /* secondary text */
+    --grey-2: #82827e;        /* meta */
+    --rule: #111111;          /* structure lines: INK, not grey */
+    --rule-thin: #d9d9d6;     /* quiet row dividers */
+    --red: #e2231a;           /* the one strong accent */
+    --radius: 0;
+    --gutter: 1.25rem;
+    --font: "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
+    --mono: ui-monospace, "Cascadia Code", Menlo, Consolas, monospace;
+}
+@media (prefers-color-scheme: dark) {
+    :root {
+        --paper: #121212;
+        --ink: #f0f0ec;
+        --grey-1: #a8a8a4;
+        --grey-2: #7c7c78;
+        --rule: #f0f0ec;
+        --rule-thin: #2e2e2c;
+        --red: #ff4438;
+    }
+}
+
+* { box-sizing: border-box; }
+html { scrollbar-gutter: stable; }
+body {
+    margin: 0;
+    font: 15px/1.5 var(--font);
+    color: var(--ink);
+    background: var(--paper);
+}
+a { color: inherit; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; text-decoration-color: var(--grey-2); }
+a:hover { color: var(--red); text-decoration-color: var(--red); }
+.summary-meta, .who, .hint { font-family: var(--mono); }
+
+/* Page grid: hard left rail, content column. Swiss: the frame is the design. */
+.top {
+    display: grid; grid-template-columns: 13rem minmax(0, 1fr) auto;
+    border-bottom: 2px solid var(--rule);
+}
+.brand {
+    margin: 0; padding: 0.9rem var(--gutter) 0.85rem;
+    font-size: 1rem; font-weight: 700; letter-spacing: -0.01em;
+    border-right: 1px solid var(--rule-thin);
+    text-transform: uppercase;
+}
+.top-nav { display: flex; align-items: center; gap: 1.4rem; padding: 0.9rem var(--gutter); flex-wrap: wrap; }
+.top-nav a { text-decoration: none; font-size: 0.875rem; }
+.top-nav a:hover { color: var(--red); }
+.who { margin: 0; padding: 0.9rem var(--gutter) 0.9rem 0; font-size: 0.75rem; color: var(--grey-1); }
+
+main {
+    max-width: 72rem; margin: 0 auto;
+    display: grid; grid-template-columns: 13rem minmax(0, 1fr);
+}
+.sampler-note {
+    grid-column: 1 / -1; margin: 0; padding: 0.55rem var(--gutter);
+    font-size: 0.75rem; color: var(--grey-1);
+    border-bottom: 1px solid var(--rule-thin); font-family: var(--mono);
+}
+.sampler-note a { text-decoration: none; color: var(--ink); }
+
+/* Zone rails: the sidebar column carries zone labels. */
+.zone-advisor, .zone-status, .zone-ambient { grid-column: 2; padding: 0 var(--gutter); }
+.zone-advisor { padding-top: 1.5rem; }
+
+.zone-advisor h1 {
+    margin: 0 0 0.5rem; font-size: 2rem; line-height: 1.1; font-weight: 700;
+    letter-spacing: -0.02em; max-width: 34rem;
+}
+.lede { margin: 0 0 1.25rem; color: var(--grey-1); max-width: 42rem; }
+
+.composer { border: 2px solid var(--rule); }
+.composer:focus-within { border-color: var(--red); }
+.composer textarea {
+    display: block; width: 100%; border: none; resize: vertical;
+    background: transparent; color: var(--ink); font: inherit; padding: 0.75rem;
+}
+.composer textarea:focus { outline: none; }
+.composer textarea::placeholder { color: var(--grey-2); }
+.composer-bar {
+    display: flex; align-items: center; justify-content: space-between;
+    gap: 1rem; border-top: 1px solid var(--rule-thin); padding: 0.5rem 0.75rem;
+}
+.hint { margin: 0; font-size: 0.75rem; color: var(--grey-2); }
+
+.btn {
+    font: 0.875rem var(--font); font-weight: 600; cursor: pointer;
+    border: 1.5px solid var(--rule); border-radius: 0;
+    background: transparent; color: var(--ink); padding: 0.35rem 1rem;
+}
+.btn:hover { background: var(--ink); color: var(--paper); }
+.btn.primary {
+    background: var(--red); border-color: var(--red); color: #ffffff;
+    text-transform: uppercase; letter-spacing: 0.04em;
+}
+.btn.quiet { border-color: var(--rule-thin); color: var(--grey-1); font-weight: 400; }
+.btn.quiet:hover { background: transparent; color: var(--ink); border-color: var(--rule); }
+
+.exchange { margin-top: 1.75rem; }
+.exchange h2 {
+    font-size: 0.75rem; margin: 0 0 0.9rem; font-weight: 700;
+    text-transform: uppercase; letter-spacing: 0.14em; color: var(--grey-1);
+    display: flex; gap: 1rem; align-items: baseline;
+}
+.exchange h2 .more { letter-spacing: 0; text-transform: none; font-weight: 400; }
+.msg { max-width: 44rem; margin-bottom: 0.85rem; }
+.msg p { margin: 0; }
+.from-user { text-align: right; }
+.from-user p {
+    display: inline-block; text-align: left;
+    background: var(--ink); color: var(--paper);
+    padding: 0.55rem 0.9rem;
+}
+.from-advisor > p {
+    padding-left: 0.95rem; border-left: 3px solid var(--red);
+}
+.suggested {
+    border: 1.5px solid var(--rule); border-left: 6px solid var(--red);
+    padding: 0.7rem 1rem; margin-top: 0.7rem; max-width: 40rem;
+}
+.suggested-kind {
+    margin: 0 0 0.3rem; font-size: 0.6875rem; text-transform: uppercase;
+    letter-spacing: 0.14em; color: var(--red); font-weight: 700;
+}
+.suggested-title { margin: 0 0 0.2rem; font-weight: 700; }
+.suggested-meta { margin: 0 0 0.7rem; font-size: 0.8125rem; color: var(--grey-1); }
+.suggested-actions { display: flex; gap: 0.5rem; }
+.all-chats { font-size: 0.875rem; margin: 1rem 0 0; }
+
+/* ---- ZONE 2: a ruled table row structure ---- */
+.zone-status {
+    margin-top: 2rem; padding-top: 0; 
+    border-top: 2px solid var(--rule);
+    display: grid; grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr);
+    gap: 0 2.5rem;
+}
+.zone-status h2 {
+    font-size: 0.75rem; margin: 1.1rem 0 0.9rem; font-weight: 700;
+    text-transform: uppercase; letter-spacing: 0.14em;
+}
+.count { margin-left: 0.4rem; color: var(--red); font-weight: 700; font-size: 0.875rem; }
+.needs-list { list-style: none; margin: 0; padding: 0; }
+.need {
+    display: grid; grid-template-columns: 6.5rem minmax(0, 1fr) auto;
+    gap: 1rem; padding: 0.85rem 0; align-items: start;
+    border-top: 1px solid var(--rule-thin);
+}
+.need:first-child { border-top: none; padding-top: 0; }
+.need-kind { margin: 0.15rem 0 0; }
+.need-title { margin: 0 0 0.15rem; font-weight: 700; }
+.need-title a { text-decoration: none; }
+.need-meta { margin: 0; font-size: 0.8125rem; color: var(--grey-1); }
+.need-act { margin: 0; display: flex; gap: 0.5rem; flex-wrap: wrap; }
+
+/* Swiss tags: small caps text on paper, colour by weight. Flat, no fill. */
+.tag {
+    display: inline-block; font-size: 0.6875rem; font-weight: 700;
+    padding: 0 0 0.05rem; line-height: 1.6;
+    text-transform: uppercase; letter-spacing: 0.1em;
+}
+.tag.review, .tag.working, .tag.blocked, .tag.queued { color: var(--grey-1); }
+.tag.question { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
+.tag.parked, .tag.suspended, .tag.system { color: var(--grey-2); }
+.tag.done, .tag.progress { color: var(--ink); }
+.tag.failed { color: var(--red); }
+.tag.comment { color: var(--grey-2); }
+
+.health { border-left: 1px solid var(--rule-thin); padding-left: 2.5rem; }
+.metrics { display: grid; grid-template-columns: repeat(4, 1fr); margin: 1.1rem 0 1.25rem; gap: 0.5rem; }
+.metric dt { font-size: 0.6875rem; color: var(--grey-1); text-transform: uppercase; letter-spacing: 0.1em; }
+.metric dd {
+    margin: 0.2rem 0 0; font-size: 2.4rem; font-weight: 200; line-height: 1;
+    font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
+}
+.metric dd.warn { color: var(--red); }
+.saddles { list-style: none; margin: 0; padding: 0; font-size: 0.8125rem; }
+.saddles li { display: flex; align-items: center; gap: 0.6rem; padding: 0.3rem 0; }
+.state {
+    width: 0.55rem; height: 0.55rem; display: inline-block; flex: none;
+    border: 1.5px solid var(--ink);
+}
+.state.busy { background: var(--ink); }
+.state.idle { background: var(--paper); }
+.state.offline { background: var(--paper); border: 1.5px dashed var(--grey-2); }
+
+/* ---- ZONE 3 ---- */
+.zone-ambient { margin-top: 2.5rem; border-top: 2px solid var(--rule); }
+.panel { margin-bottom: 1.4rem; }
+.panel > summary {
+    cursor: pointer; list-style: none; display: flex; align-items: baseline; gap: 0.6rem;
+    padding-top: 1.1rem;
+}
+.panel > summary::-webkit-details-marker { display: none; }
+.panel > summary::after { content: "+"; color: var(--grey-2); font-weight: 400; }
+.panel[open] > summary::after { content: "–"; }
+.panel > summary h2 {
+    font-size: 0.75rem; font-weight: 700; margin: 0; text-transform: uppercase;
+    letter-spacing: 0.14em;
+}
+.summary-meta { font-size: 0.75rem; color: var(--grey-2); }
+.panel > ul, .panel > table, .panel > p { margin-top: 0.9rem; }
+
+.notes { list-style: none; margin: 0.9rem 0 0; padding: 0; }
+.note { display: flex; gap: 0.7rem; padding: 0.45rem 0; }
+.note-state {
+    flex: none; width: 0.85rem; height: 0.85rem; margin-top: 0.15rem;
+    border: 1.5px solid var(--ink);
+}
+.note.done .note-state { background: var(--ink); }
+.note.promoted .note-state { background: var(--red); border-color: var(--red); }
+.note-body p:first-child { margin: 0 0 0.1rem; }
+.note-meta { font-size: 0.75rem; color: var(--grey-2); }
+.note.done .note-body p:first-child { color: var(--grey-1); }
+.note.done .note-body p:first-child { text-decoration: line-through; text-decoration-thickness: 1px; text-decoration-color: var(--grey-2); }
+
+.discoveries { list-style: none; margin: 0.9rem 0 0; padding: 0; max-width: 50rem; }
+.discoveries li { padding: 0.45rem 0; border-top: 1px solid var(--rule-thin); }
+.discoveries li:first-child { border-top: none; }
+.discoveries li > p:first-child { margin: 0 0 0.1rem; }
+.more-row { margin: 0.6rem 0 0; font-size: 0.875rem; }
+
+.tasks { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
+.tasks th {
+    text-align: left; font-size: 0.6875rem; font-weight: 700;
+    text-transform: uppercase; letter-spacing: 0.1em; color: var(--grey-1);
+    padding: 0.35rem 0.85rem 0.35rem 0; border-bottom: 1.5px solid var(--rule);
+}
+.tasks td {
+    padding: 0.55rem 0.85rem 0.55rem 0; border-bottom: 1px solid var(--rule-thin);
+    vertical-align: top;
+}
+.tasks td.empty { color: var(--grey-2); }
+.tasks .when, .when { color: var(--grey-2); font-size: 0.8125rem; }
+
+.activity { list-style: none; margin: 0.9rem 0 0; padding: 0; font-size: 0.875rem; }
+.activity li { display: flex; gap: 0.85rem; padding: 0.3rem 0; }
+.activity .when { flex: none; width: 3.3rem; font-variant-numeric: tabular-nums; font-family: var(--mono); }
+.activity .what { margin: 0; }
+.activity .what a { text-decoration: none; font-weight: 700; }
+
+.foot {
+    border-top: 2px solid var(--rule); color: var(--grey-1);
+    font-size: 0.75rem; padding: 1rem var(--gutter);
+}
+.foot p { margin: 0; max-width: 72rem; margin-inline: auto; }
+
+@media (max-width: 50rem) {
+    .top { grid-template-columns: 1fr; }
+    .brand { border-right: none; border-bottom: 1px solid var(--rule-thin); }
+    main { grid-template-columns: 1fr; }
+    .zone-advisor, .zone-status, .zone-ambient { grid-column: 1; }
+    .zone-status { grid-template-columns: 1fr; }
+    .health { border-left: none; padding-left: 0; border-top: 1px solid var(--rule-thin); padding-top: 1rem; }
+    .need { grid-template-columns: minmax(0, 1fr); }
+    .need-kind { margin: 0; }
+    .need-act { margin-top: 0.25rem; }
+}
+
+</style>
+</head>
+<body>
+<header class="top">
+    <p class="brand">Clanker-Saddle</p>
+    <nav class="top-nav" aria-label="Primary">
+        <a href="#">Queue</a>
+        <a href="#">Tasks</a>
+        <a href="#">Goals</a>
+        <a href="#">Discoveries</a>
+        <a href="#">Saddles</a>
+    </nav>
+    <p class="who">marta &middot; web-stack</p>
+</header>
+
+<main id="main">
+    <p class="sampler-note">Sampler 3 of 3 &mdash; Swiss Flat. Static mock, not live data.
+        <a href="dashboard-primer.html">1 Curated Primer</a> &middot;
+        <a href="dashboard-control.html">2 Control Room</a> &middot;
+        <a href="dashboard-swiss.html">3 Swiss Flat</a></p>
+
+    <!-- ZONE 1: the advisor conversation composer, first and loudest -->
+    <section class="zone-advisor" aria-labelledby="advisor-h">
+        <h1 id="advisor-h">Ask the advisor</h1>
+        <p class="lede">Reads your projects, tasks, goals, rules and discoveries &mdash; asks
+            you questions and suggests work. It never runs commands.</p>
+        <form class="composer" onsubmit="return false">
+            <textarea rows="3" placeholder="What should the fleet work on next?"></textarea>
+            <div class="composer-bar">
+                <p class="hint">claude-sonnet &middot; last fleet snapshot 14:02</p>
+                <button type="submit" class="btn primary">Start chat</button>
+            </div>
+        </form>
+
+        <section class="exchange" aria-label="Recent advisor exchange">
+            <h2>Yesterday &mdash; goal-branch view <a class="more" href="#">open chat</a></h2>
+            <div class="msg from-user">
+                <p>Can the goal-branch view show parked runs separately from failed ones?</p>
+            </div>
+            <div class="msg from-advisor">
+                <p>They share a column today. Three open goals carry parked runs, all
+                    turn-cap parks from the ghost-working sweep; none failed this week.
+                    I can suggest the split as a task on web-stack.</p>
+                <div class="suggested">
+                    <p class="suggested-kind">suggested task</p>
+                    <p class="suggested-title">Split parked and failed runs on the goal branch view</p>
+                    <p class="suggested-meta">Clanker-Saddle &middot; branch goal/branch-view</p>
+                    <div class="suggested-actions">
+                        <button type="button" class="btn">Create draft</button>
+                        <button type="button" class="btn quiet">Discard</button>
+                    </div>
+                </div>
+            </div>
+            <div class="msg from-user">
+                <p>Hold on that. How many of the parked runs are older than a day?</p>
+            </div>
+            <div class="msg from-advisor">
+                <p>Two &mdash; both parked since 2 Oct on the notifications goal.
+                    <a href="#">Open goal 24 &rarr;</a></p>
+            </div>
+        </section>
+        <p class="all-chats"><a href="#">All 14 chats &rarr;</a></p>
+    </section>
+
+    <!-- ZONE 2: compact status strip. Needs-you items sit above queue health. -->
+    <section class="zone-status" aria-labelledby="needs-h">
+        <div class="needs">
+            <h2 id="needs-h">Needs a human <span class="count">3</span></h2>
+            <ol class="needs-list">
+                <li class="need">
+                    <p class="need-kind"><span class="tag review">review</span></p>
+                    <div class="need-body">
+                        <p class="need-title"><a href="#">Ghost-working sweep: requeue stale open
+                            sessions from the dispatcher tick</a></p>
+                        <p class="need-meta">task 211 &middot; Clanker-Saddle &middot; report waiting 12 min</p>
+                    </div>
+                    <p class="need-act"><button type="button" class="btn">Review report</button></p>
+                </li>
+                <li class="need">
+                    <p class="need-kind"><span class="tag parked">parked</span></p>
+                    <div class="need-body">
+                        <p class="need-title"><a href="#">Goal compare: diff two branches&rsquo;
+                            task trees</a></p>
+                        <p class="need-meta">task 198 &middot; hit the 40-turn cap at 13:51 &middot;
+                            wake to continue, or leave it parked</p>
+                    </div>
+                    <p class="need-act"><button type="button" class="btn">Wake</button>
+                        <button type="button" class="btn quiet">Leave parked</button></p>
+                </li>
+                <li class="need">
+                    <p class="need-kind"><span class="tag question">question</span></p>
+                    <div class="need-body">
+                        <p class="need-title">Should the discovery list paginate at 50 rows, or
+                            keep one long scroll?</p>
+                        <p class="need-meta">task 197 &middot; asked 2 h ago &middot; options 50 / 100 / keep scroll</p>
+                    </div>
+                    <p class="need-act"><button type="button" class="btn">Answer</button></p>
+                </li>
+            </ol>
+        </div>
+
+        <div class="health">
+            <h2>Queue health</h2>
+            <dl class="metrics">
+                <div class="metric"><dt>running</dt><dd>3</dd></div>
+                <div class="metric"><dt>stuck</dt><dd class="warn">1</dd></div>
+                <div class="metric"><dt>queued</dt><dd>5</dd></div>
+                <div class="metric"><dt>draft</dt><dd>2</dd></div>
+            </dl>
+            <ul class="saddles">
+                <li><span class="state busy"></span>atlas &mdash; busy &middot; task 214</li>
+                <li><span class="state busy"></span>meridian &mdash; busy &middot; goal 31</li>
+                <li><span class="state idle"></span>kestrel &mdash; idle &middot; 41 min</li>
+                <li><span class="state offline"></span>portland &mdash; offline &middot; 3 h</li>
+            </ul>
+        </div>
+    </section>
+
+    <!-- ZONE 3: ambient. Reduced density, collapsed where sensible. -->
+    <section class="zone-ambient" aria-label="Ambient">
+        <details class="panel" open>
+            <summary><h2>Notes</h2><span class="summary-meta">3</span></summary>
+            <ul class="notes">
+                <li class="note open"><span class="note-state"></span>
+                    <div class="note-body">
+                        <p>Dashboard hierarchy: advisor first, needs-you second, ambient
+                            below &mdash; decide between the three samplers before touching app.css.</p>
+                        <p class="note-meta">today 13:04</p>
+                    </div>
+                </li>
+                <li class="note done"><span class="note-state"></span>
+                    <div class="note-body">
+                        <p>Check goal badge contrast under the dark scheme.</p>
+                        <p class="note-meta">yesterday &middot; done</p>
+                    </div>
+                </li>
+                <li class="note promoted"><span class="note-state"></span>
+                    <div class="note-body">
+                        <p>Ship the web-push test notification end to end.</p>
+                        <p class="note-meta">promoted to <a href="#">goal 24</a></p>
+                    </div>
+                </li>
+            </ul>
+        </details>
+
+        <details class="panel" open>
+            <summary><h2>Latest discoveries</h2><span class="summary-meta">2</span></summary>
+            <ul class="discoveries">
+                <li>
+                    <p>json-glib writes invalid UTF-8 verbatim: a byte-count clamp that lands
+                        mid-character poisons the whole payload, and the stored row loses its
+                        members on read-back. Back the cut off over continuation bytes at every
+                        serialisation boundary.</p>
+                    <p class="note-meta">2 Oct &middot; Saddle</p>
+                </li>
+                <li>
+                    <p>A harness seeding a row the app also lazily creates must INSERT OR
+                        IGNORE &mdash; two read-then-insert writers race and the loser dies on
+                        UNIQUE, taking the whole sequential suite with it.</p>
+                    <p class="note-meta">1 Oct &middot; Clanker-Saddle</p>
+                </li>
+            </ul>
+            <p class="more-row"><a href="#">All discoveries &rarr;</a></p>
+        </details>
+
+        <details class="panel">
+            <summary><h2>Active tasks</h2><span class="summary-meta">6</span></summary>
+            <table class="tasks">
+                <thead>
+                <tr><th>Task</th><th>Status</th><th>Branch</th><th>Latest</th></tr>
+                </thead>
+                <tbody>
+                <tr>
+                    <td><a href="#">214 &middot; Mock dashboard: three visual directions as static
+                        HTML samplers</a></td>
+                    <td><span class="tag working">working</span></td>
+                    <td>web-stack</td>
+                    <td>writing mocks/dashboard-primer.html <span class="when">14:02</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">213 &middot; Split parked and failed runs on the goal branch
+                        view</a></td>
+                    <td><span class="tag queued">queued</span></td>
+                    <td>goal/branch-view</td>
+                    <td class="empty">&mdash;</td>
+                </tr>
+                <tr>
+                    <td><a href="#">198 &middot; Goal compare: diff two branches&rsquo; task
+                        trees</a></td>
+                    <td><span class="tag suspended">suspended</span></td>
+                    <td>goal/compare</td>
+                    <td>parked at turn cap 41/40 <span class="when">13:51</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">196 &middot; Notification digest: batch question and RFC
+                        pushes</a></td>
+                    <td><span class="tag blocked">blocked</span></td>
+                    <td>notify/digest</td>
+                    <td>asked: digest window 5 or 15 min <span class="when">12:37</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">189 &middot; Rate-limit the events endpoint</a></td>
+                    <td><span class="tag failed">failed</span></td>
+                    <td>api/rate-limit</td>
+                    <td>429 loop under parallel suites; needs backoff <span class="when">11:20</span></td>
+                </tr>
+                <tr>
+                    <td><a href="#">195 &middot; Advisor chat export to markdown</a></td>
+                    <td><span class="tag done">done</span></td>
+                    <td>advisor/export</td>
+                    <td>report accepted <span class="when">09:58</span></td>
+                </tr>
+                </tbody>
+            </table>
+        </details>
+
+        <details class="panel">
+            <summary><h2>Activity</h2><span class="summary-meta">7 events</span></summary>
+            <ul class="activity">
+                <li><p class="when">14:02</p>
+                    <p class="what"><span class="tag progress">progress</span> <a href="#">214</a>
+                        writing mocks/dashboard-primer.html</p></li>
+                <li><p class="when">13:58</p>
+                    <p class="what"><span class="tag question">question</span> <a href="#">197</a>
+                        discovery list pagination &mdash; 50, 100, or one scroll?</p></li>
+                <li><p class="when">13:50</p>
+                    <p class="what"><span class="tag review">review</span> <a href="#">211</a>
+                        report ready &mdash; ghost-working sweep</p></li>
+                <li><p class="when">13:44</p>
+                    <p class="what"><span class="tag comment">comment</span> goal 31 &mdash;
+                        &ldquo;keep needs-a-human above queue health&rdquo;</p></li>
+                <li><p class="when">13:31</p>
+                    <p class="what"><span class="tag progress">progress</span> <a href="#">196</a>
+                        digest skeleton, window still undecided</p></li>
+                <li><p class="when">13:04</p>
+                    <p class="what"><span class="tag system">saddle</span> kestrel idle after
+                        task 197 parked</p></li>
+                <li><p class="when">11:20</p>
+                    <p class="what"><span class="tag failed">failed</span> <a href="#">189</a>
+                        exit 1 &mdash; 429 loop under parallel suites</p></li>
+            </ul>
+        </details>
+    </section>
+</main>
+
+<footer class="foot">
+    <p>Swiss Flat sampler &middot; static mock for the dashboard overhaul &middot; toggle your
+        OS or devtools colour scheme to check the second variant</p>
+</footer>
+
+</body>
+</html>