oficina / docs Public

On a phone the document stops pretending to be paper

Above 36rem nothing changes: the sheet keeps its 1in, which is a real
measurement standing in for the document's page margin. Below it, that
inch was taking more than it left. Three insets stacked up — the shell's
own padding, the canvas tray's, and then the inch — so a 375px phone
showed a 151px column of text, and at 320px, which this app supports
without exemption, 96px: under ten characters of 12pt Georgia a line.

So on narrow screens the tray's side padding goes, the sheet runs to the
screen edge, and one 1rem margin survives inside it. Measured in a real
browser: text goes 151px to 343px at 375, and 96px to 288px at 320. No
horizontal scroll at any width, and the desktop rendering is byte for
byte what it was.

Reaching the edge means cancelling the shell's padding with a negative
margin rather than the usual width:100vw, and the comment says why: 100vw
counts a classic scrollbar, so on a desktop browser narrowed under the
breakpoint — which is how anyone actually tests a 320px reflow — it
overhangs and starts a horizontal scroll, which is the same failure this
block exists to fix. It also buys alignment: with the sheet at 0 and its
margin inside, the document's first character lines up with the page
header's title above it.

Verified in headless Chromium at 320/375/414/768/1280: the column widths
above, no sideways scroll, an edit from a second connection still landing
live 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>
Paul Campbell pushed by paul@keymail.dev d31890784d19e8a719e57da98b162fd5fc61d543 parent cafb696
1 file changed, +65 −0
  • internal/docs/views/show.html +65 −0

CI passed — run details

Intent

Attributed to this commit: 380 g CO₂e (40408201 tokens). This is an attribution, not a measurement — usage counted from this commit's own marker forward to the next one on worktree-mobile-margins, never backward from it. A turn that produced more than one commit books all of its tokens to the last one, and a concurrent session on this branch can add to the same figure. Some of it was priced using the shared default rate, because no model-specific factor row exists yet for at least one model involved. The Carbon view has the repo total, which is never derived from this attribution.

diff --git a/internal/docs/views/show.html b/internal/docs/views/show.html
index 8a147a0..e2cd8e8 100644
--- a/internal/docs/views/show.html
+++ b/internal/docs/views/show.html
@@ -97,6 +97,71 @@
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 two nested insets: [docs-canvas]'s
+ 1rem tray padding either side, and then [docs-page]'s own 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 same arithmetic (375 - 32 - 192) leaves a 151px column, and at
+ 320px, which this app supports without exemption (WCAG 2.2 AA SC
+ 1.4.10), it leaves 96px: under ten characters of 12pt Georgia per
+ line. A page margin that squeezes the page is no longer describing
+ the page.
+
+ So below 36rem the tray's side padding goes to nothing, 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 derived, not fashionable: it is about where the two insets
+ stop leaving 45 characters a line (576 - 32 - 192 = 352px), which is
+ the low end of a comfortable measure. Phones in portrait are all
+ well under 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. */
+ @media (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