On a phone the document stops pretending to be paper
Three insets stacked on the document view: rastrillo's shell padding, the canvas tray's, and then the sheet's own 1in. Measured, that left a 119px text column on a 375px phone and 64px at 320px — about five characters of 12pt Georgia a line, on a width this app supports without exemption. The inch is a real measurement standing in for the document's page margin, and on a desktop it is worth every pixel; at phone widths it was describing the page by squeezing it. So below 36rem the tray's side padding goes, the canvas cancels the shell's padding so the sheet reaches the screen edge, and one 1rem margin survives inside it. Measured after: 343px at 375, 288px at 320, nothing changed at 768 or above. The 1in is untouched at every width above the breakpoint. Reaching the edge uses a negative margin in the shell's own token rather than width:100vw, because 100vw counts a classic scrollbar — and rastrillo sets scrollbar-gutter:stable, so it would overhang even with no scrollbar drawn, starting a horizontal scroll on a desktop browser narrowed below the breakpoint. That is how a person tests a 320px reflow, so the reflex fix would have reintroduced the failure it was fixing. The query is `screen and` for the same class of reason: an untyped one applies to print, where A5 portrait crosses the breakpoint and would print an edge-bleeding sheet. Reviewed by Fable, which caught the comment counting two insets when there are three — the third being the one the same comment already explained how to cancel — and the print case. Verified in headless Chromium at 320/375/414/768/1280: the column widths above, no horizontal scroll at any width, a live update from a second connection still landing at 375px, and a click in the surviving margin still placing the caret in the document.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 file changed,
+89
−0
internal/docs/views/show.html+89 −0
CI passed — run details
diff --git a/internal/docs/views/show.html b/internal/docs/views/show.html| index cf34fbb..2d2b75c 100644 |
| --- a/internal/docs/views/show.html |
| +++ b/internal/docs/views/show.html |
| @@ -97,6 +97,95 @@ |
| color: #1a1a1a; |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 1px 12px rgba(0, 0, 0, 0.12); |
| } |
| + /* Narrow screens stop simulating paper, because at phone widths the |
| + simulation costs more than it says. |
| + |
| + Above this breakpoint a reader sees THREE nested insets, and the |
| + first one is easy to miss because it belongs to the framework: the |
| + shell this template renders into (rastrillo's [rst-page]) pads |
| + --rst-sp-4 either side, then [docs-canvas] adds its own 1rem tray |
| + padding, then [docs-page] adds 1in. That inner inch is a real |
| + measurement — it stands for the document's page margin, which page |
| + setup and the layout engine will own properly later — and on a |
| + desktop it is worth every pixel. On a 375px phone the three together |
| + (375 - 32 - 32 - 192) left a 119px column, and at 320px, which this |
| + app supports without exemption (WCAG 2.2 AA SC 1.4.10), 64px: about |
| + five characters of 12pt Georgia per line. A page margin that |
| + squeezes the page is no longer describing the page. |
| + |
| + (An earlier version of this comment counted two insets and said |
| + 151px and 96px. It was wrong in the direction that flatters the |
| + code, and it was wrong while the paragraph below it described |
| + cancelling the very inset it had forgotten. The numbers here are |
| + measured, not derived.) |
| + |
| + So below 36rem the tray's side padding goes to nothing, its block |
| + padding drops from --rst-sp-6 to --rst-sp-4, the sheet runs edge to |
| + edge, and ONE margin survives inside it. Text goes to 343px at 375px |
| + wide and 288px at 320px. The 1in is untouched at every width above |
| + the breakpoint, so where the print margin can be shown honestly it |
| + still is. |
| + |
| + 36rem is a judgement rather than a formula, and the honest version |
| + of the arithmetic says so: at 576px the three insets leave a 320px |
| + column, about 40 characters of this face, and holding out for the |
| + 45 characters that make a comfortable measure would put the |
| + breakpoint nearer 38rem. 36rem is the choice because reflow only |
| + promises 320px viewports, and between 577 and 600px the paper still |
| + yields 306-330px — cramped, readable, and still recognisably a |
| + page. Phones in portrait are all well below it; a tablet or a small |
| + window keeps the paper. |
| + |
| + The shadow goes with the tray — it exists to lift the sheet off the |
| + grey, and once there is no grey beside it, it is a dark smear on the |
| + screen edge. What deliberately does NOT change: the flex column and |
| + min-block-size, because the editable node fills the page's text area |
| + so that a click in the empty space below the last paragraph still |
| + lands in the document (see fixtures/editor-entry.js's |
| + placeCaretFromPage), and the literal colours, which must not repaint |
| + under anyone's theme at any width. |
| + |
| + `screen and`, not a bare width query, and it is not decoration. A |
| + media query with no type matches print too, and a print box is |
| + measured in CSS pixels like any other: US Letter and A4 come out |
| + around 700-800px and stay above this breakpoint, but A5 portrait is |
| + about 559px and crosses it. Printing a document on A5 would then |
| + drop the 1in and apply a negative margin meant for a phone screen — |
| + an edge-bleeding sheet with 1rem margins, in the one medium where |
| + the page margin is not a metaphor at all. `screen` is what keeps |
| + the paragraph above true. */ |
| + @media screen and (max-width: 36rem) { |
| + [docs-canvas] { |
| + padding-inline: 0; |
| + padding-block: var(--rst-sp-4); |
| + /* The tray's own padding is not the only inset in the way: the |
| + shell this template renders into ([rst-page], rastrillo's own |
| + chrome) carries --rst-sp-4 either side, measured. Cancelling it |
| + here is what actually reaches the screen edge, and it buys more |
| + than the 32px: with the sheet at 0 and its own 1rem inside it, |
| + the document's first character lines up exactly with the page |
| + header's title above it, which an inset sheet does not do. |
| + |
| + A negative margin in the shell's own token rather than the |
| + 100vw trick on purpose. `width: 100vw` measures the viewport |
| + INCLUDING a classic scrollbar, so on a desktop browser narrowed |
| + under this breakpoint — which is exactly how anyone tests the |
| + 320px reflow this app promises — it overhangs by the scrollbar's |
| + width and starts a horizontal scroll: the same WCAG 1.4.10 |
| + failure this whole block exists to fix, reintroduced by the fix. |
| + Cancelling a known padding cannot overhang. It does couple this |
| + rule to [rst-page]'s padding staying --rst-sp-4; if that ever |
| + changes, the sheet sits slightly inset or slightly proud, which |
| + is visible and harmless rather than silent. */ |
| + margin-inline: calc(var(--rst-sp-4) * -1); |
| + } |
| + [docs-page] { |
| + inline-size: 100%; |
| + margin-block-end: 0; |
| + padding: var(--rst-sp-4); |
| + box-shadow: none; |
| + } |
| + } |
| /* [docs-text] holds Store.HTML's rendered markup (core/src/fragment.rs |
| — <p>, <h1>-<h6>, <ul>/<ol>/<li>, <blockquote>, and the marks |
| <strong>/<em>/<code>; no attributes are ever emitted, so nothing |