oficina / docs Public

Tighten the chrome: topbar shell, full-bleed canvas closed

On branch worktree-tighten-chrome

See the branch's single commit. Summary, and the two open judgement calls, in a reply to follow.

What changed, in one pass.

The shell moves from column to topbar (render.go's shellLayout), which is a whole-app choice — newRenderer parses exactly one layout. Both signed-in screens get one bar. show.html's [rst-page-header] is gone entirely: the brand link is the route back to the list, the document's title sits beside it, sign-out is in the bar's account menu, and the two export links are at the formatting bar's trailing end, which is where both Google Docs and Word put a document's own controls and which was empty white space before. list.html loses sign-out with it and is back to two controls in its header.

The canvas then takes the window. [rst-page]'s 64rem column and its padding are cancelled on the editor screen only, scoped by delivery — that stylesheet ships with show.html and nothing else. Deliberately not 'width: 100vw', which measures the viewport including a classic scrollbar and starts the horizontal scroll SC 1.4.10 forbids; the narrow-screen block below it had already worked that out once and its negative margin is now unnecessary, so it goes.

No new catalog strings. The brand reuses docs.list.title and a document's title is its own data, so no copy-review gate.

Two things found by looking at the rendered result rather than by reasoning about it, both worth a reviewer's attention:

  1. signin.html's first attempt at hiding the bar did nothing. tokens.css lays it out with '[rst-shell-topbar] [rst-shell-bar]', specificity (0,2,0); a bare '[rst-shell-bar]' is (0,1,0) and loses. The front door kept showing rastrillo's default brand — a 'Home' link to a route its own guard bounces straight back here. Fixed by matching the framework's selector shape.
  1. At 320px the three toolbar selects measured wider than the bar and the page grew a horizontal scrollbar. That one predates this branch: the toolbar had 320-32-32 = 256px inside [rst-page] and has 320-32 = 288px now, so it was worse before and is still wrong. Fixed here rather than deferred because this is the row being restructured — the group wraps and min-inline-size lifts a select's automatic minimum size. Flagging it because it means this branch contains one fix that is not about layout language at all.

Two judgement calls left open for Paul rather than decided quietly:

  • The list screen now reads 'Documents' in the bar and 'Documents' as its h1, directly beneath. Google Drive does exactly this ('Drive' / 'My Drive') and the two are at different weights and sizes, so it is defensible. Making them differ needs a new heading string, which is new user-facing copy and therefore the copy-review gate — not something to slip in here.
  • The list header still carries four controls: search field, search button, title field, create button. Better than five, still busy. Google Docs would put search in the bar. That is a further change to list.html's shape rather than a tightening of this one, so it is not in this branch.

Verification: .amadan/ci.d/10-gate exits 0 locally (wire compat both directions, go vet/test/gofmt, build). TestDocumentPageLinksBackToTheList was updated, not deleted — it now asserts the route at [rst-shell-brand], because what it holds is the route rather than the element that carried it, and a shell block a page never defines falls back to the layout's default silently. Checked by rendering: 1440px and 320px on the editor, the list, and the signed-out page.

Not yet done, and both are gates rather than oversights: the highest-capability-model review of the branch as one diff, and Paul's call on the two items above.

Fable whole-branch review: CHANGES REQUIRED. Fixed in 3b73d15; the review record follows.

BLOCKER, and the one that matters: fixtures/browser-drive.mjs was red on this branch and had not been run. It is not in .amadan/ci.d/10-gate (Chromium cannot start in the agent sandbox, per the script's own header), so it is run by hand — and it is the only check in this repo that exercises the keyboard path. CI green said nothing about it, which is precisely the 'passed' versus 'could not see' trap AGENTS.md records.

Two faults in it, both caused by this branch:

  • Check 7 anchored on 'form[action="/signout"] button'. That button is now inside the shell's account dropdown, a closed <details>. The node is in the DOM so querySelector finds it and the existing guard passed, but it is not rendered, so .focus() is a silent no-op. The loop then counted Tab presses from wherever focus already was — the editor, from check 6 — and reported 8. A true measurement of nothing. It now anchors on [rst-shell-brand], and asserts the anchor actually took before counting.
  • Check 8's bound of 3 was derived when the path was sign-out to bar to editor. The real path is now 5: account summary, the toolbar entire as one roving stop, PDF, Markdown, editor. Re-derived with the derivation written down, not nudged. If the toolbar ever stops being a single tab stop this becomes 18 and fails loudly, which is the check's whole purpose.

Seen to fail first, then fixed: 21/22 before, 23/23 after (two checks added).

Should-fixes, all comments claiming more than the code did:

  • [docs-shell-title] claimed 'truncation over wrapping' and did the opposite. Flex line-breaking uses an item's hypothetical main size, so flex: 0 1 auto on a nowrap span drops the title to a second row of the bar and the account control to a third, ellipsising only once the title alone exceeds the bar. flex: 1 1 0 never forces a break. Verified at 560px with a 97-character title: one row, ellipsis.
  • [docs-bar]'s auto-margin note was backwards in both halves. Auto margins take free space per line, so the exports stay at the trailing end on a wrapped line; space-between would give a lone item flex-start. And space-between could not separate the two links from each other regardless — they are inside one flex item. I got the replacement reason wrong once too before checking it.
  • [rst-shell-brand] is a 21px target. [docs-back], which it replaced, had already found this and stated the 24px floor outright with a measured note on why deriving it from tokens fails; deleting [docs-back] deleted that finding. The rule is back, in head.html.
  • The narrow-screen character counts used two divisors in one paragraph (12.8px/char and 8px/char) while claiming to be measured. One divisor now, stated.
  • signin.html's rationale named the account menu, which tokens.css already hides when its menu is empty; what that page must hide is the default brand and the narrow-width hamburger.
  • Stale references to a page header that no longer exists: AGENTS.md, render.go (signout and export catalog comments), handlers.go (SignOutLabel, BackLabel), export/pdf.go, toolbar-roving.mjs, and list_test.go's claim that an undefined shell block loses the route — it keeps the href and loses only the label, so the label comparison is the assertion doing the work.

Reviewer's nits accepted without change: no <h1> on the document page is not a WCAG failure (no SC requires one, <title> carries it, the page is behind RequireSession); the list's brand self-link is standard and useful from /?q=.

State: .amadan/ci.d/10-gate exits 0, browser drive 23/23, remote CI was green at 20515c2 and needs a re-run at 3b73d15 before merge.

Still open, and both are Paul's: the doubled 'Documents' on the list screen (changing it needs new copy, hence the copy-review gate) and the four controls still in that header.

Merged and deployed.

Merge: squashed to main as 7507a33. main had moved while this branch was in review — dfb9271, "A Google Docs blank line is one line, not two" (paste pipeline, new editor bundle, extra gate steps) — so this went onto the new head, not the one the branch was cut from. Clean merge, no conflicts, and both gates were re-run on the merged tree rather than trusting either side's earlier green: .amadan/ci.d/10-gate exit 0, browser drive 23/23 against main's newer bundle. Remote CI then passed on 7507a33.

Two process notes worth having on the record.

First, the merge had to be done on a detached HEAD. checkout -B hit a stale .git/config.lock in the shared checkout (empty, about three hours old, no process holding it — left by an earlier push -u that failed the same way). It updated the working tree to main's content but could not write branch config, so HEAD stayed on the feature branch with main's content staged over it, and merge --squash then reported Already up to date. (nothing to squash) — a confident wrong answer rather than an error, which is the shape AGENTS.md's own "tools that answer wrongly instead of failing" section collects. Nothing was lost, since the work was already pushed. The lock was left in place rather than deleted, because it lives in the checkout other sessions share.

The consequence: the ledger hook warned mark-commit: HEAD is detached (no current branch to record against), so 7507a33's prompts are not in refs/amadan/ledger/main. The full history is under refs/amadan/ledger/worktree-tighten-chrome, which was pushed. Flagging rather than fixing, since ledger refs are not to be edited by hand.

Second, the deploy trap fired exactly as the notes describe, which is worth confirming as still-live behaviour rather than history. carlos deploy printed live. It was not: the router's x-carlos-version header read 7507a33 (the adopted release), while /api/version answered dev and the new content-addressed bundle 404'd — the old binary was still serving. carlos instances list still showed 84c906c, which means the instance had not picked up dfb9271 either. carlos channels confirmed edge at 7507a33 first, then carlos restart, and only then did the process itself answer. The logs show the pair: rastrillo: serving version=7507a33 and instance woke (version 7507a33).

So the probe that actually answers is still the process's own, never the platform's bookkeeping.

Verified live: /api/version = 7507a33; /static/editor.7b30ca1e00c791c0.js = 200; and the sign-in page renders with no shell bar, which is this branch's own change visible in production.

Minor: carlos deploy has no --label flag (ship does).

Closing this thread. The two open judgement calls — the doubled "Documents" on the list screen, and the four controls still in its header — are not lost, they are just not this branch's, and both need a copy decision before code.