diff --git a/scripts/board.py b/scripts/board.py
index 19c7fcf..a4fd22c 100644
--- a/scripts/board.py
+++ b/scripts/board.py
@@ -1565,14 +1565,23 @@ def _fresh_span(fresh: dict, now_text: str, stale_text: str,
# section that is a human's merge, and an empty "nothing waiting" line
# would only teach the eye to skip it.
filings_block = (
- f"
Filings awaiting merge ({len(filing_items)} "
+ f"Filings awaiting merge ({len(filing_items)} "
f"on a branch, not yet in memory — merge the PR to finish the "
f"intake)
"
if filing_items else "")
- hero = t_.hero(BOARD_KEY, "Dashboard", _LEDE)
- stats = t_.stats((t["pages"], "Pages"), (f"{pct}%", "Cited"),
- (t["todo"], "To cite"), (t["queued"], "Queued"))
+ navigation = [
+ {"href": "#arxiv-inbox", "label": "arXiv inbox"},
+ {"href": "#arxiv-interests", "label": "arXiv interests"},
+ {"href": "#reading-queue", "label": "Reading queue", "count": t["queued"]},
+ {"href": "#citation-work", "label": "To cite", "count": t["todo"]},
+ {"href": "#sub-wikis", "label": "Pages", "count": t["pages"], "context": f"{pct}% cited"},
+ ]
+ if _catch_up_html(snapshot):
+ navigation.insert(0, {"href": "#catch-up", "label": "Catch up"})
+ if filing_items:
+ navigation.insert(0, {"href": "#filings", "label": "Filings awaiting merge", "count": len(filing_items)})
+ hero = t_.hero(BOARD_KEY, "Dashboard", _LEDE, navigation=navigation)
# The way back from the Pages board to the repository front door; the
# segment drops out when the snapshot carries no owner/repo.
repo_url = _repo_url(snapshot)
@@ -1594,27 +1603,26 @@ def _fresh_span(fresh: dict, now_text: str, stale_text: str,
-{_catch_up_html(snapshot)}
{hero}
-{stats}
+{_catch_up_html(snapshot)}
markdown version{github_link}{onetap}
{filings_block}
-arXiv inbox (suggested overnight — un-acted papers
+arXiv inbox (suggested overnight — un-acted papers
lapse after {inbox_actions.INBOX_WINDOW_DAYS} days)
{inbox_block}
-arXiv interests (everything that is not strong
+arXiv interests (everything that is not strong
lensing — one day's ten at a time; \U0001f9f9 clears the day and shows the
next; un-cleared batches lapse after {inbox_actions.INBOX_WINDOW_DAYS} days
{interests_backlog_note})
{interests_block}
-Reading queue ({trend_bits}){spark}
+Reading queue ({trend_bits}){spark}
{filter_box}
{''.join(queue_blocks)}
-Citation work queue ({t['todo']} sections need a
+Citation work queue ({t['todo']} sections need a
canonical key)
-Sub-wikis ({snapshot.get('bib_entries', 0)} bibliography
+Sub-wikis ({snapshot.get('bib_entries', 0)} bibliography
entries · {snapshot.get('links', {}).get('wanted', 0)} wanted pages)
{_boards_nav(snapshot)}
diff --git a/tests/test_board.py b/tests/test_board.py
index 083306b..0b50928 100644
--- a/tests/test_board.py
+++ b/tests/test_board.py
@@ -961,13 +961,13 @@ def test_banner_at_the_threshold_carries_the_day_count(tmp_path):
assert md.index("Strong-lensing catch-up due") < md.index("_Contents")
-def test_banner_html_sits_above_the_hero_with_a_copy_button(tmp_path):
+def test_catchup_html_follows_banner_and_navigation_with_a_copy_button(tmp_path):
snap = _banner_snap(tmp_path, "2026-09-11")
page = board.render(snap, "html")
assert "…so… I've been lost for a while" in page
assert "2026-09-11 (19 days ago)" in page
assert 'data-cmd="Read PyAutoMemory/skills/catch_up/SKILL.md and follow the catch_up skill with arguments: lensing."' in page
- assert page.index("class='catchup'") < page.index('class="hero"')
+ assert page.index('class="hero"') < page.index('class="board-nav"') < page.index("class='catchup'")
assert board.to_state(snap)["days_since_ingest"] == 19