diff --git a/docs/conversation-view.md b/docs/conversation-view.md index 398c5c5..a877415 100644 --- a/docs/conversation-view.md +++ b/docs/conversation-view.md @@ -256,7 +256,17 @@ pane with nothing to render (a shell) simply stays a terminal. - **The prompt band spans the pane.** Reaching into the left gutter but stopping at the text column on the right made it read as a card floating over the answer rather than as the head of it. Full bleed both sides; the meta row sits tight under the band it belongs to, and one - exchange ends well before the next begins. + exchange ends well before the next begins. The bleed is `var(--cx-gutter)`, the same variable + `.cxv-body` pays out as padding, because the phone breakpoint narrows that padding: a bleed + that restated the desktop number stayed 14px against 8px of gutter and made the conversation + column scroll sideways on a phone. +- **Nothing in the conversation scrolls sideways except the things meant to.** A code block and a + wide table each scroll inside their own box (`overflow-x: auto` on `pre` and `table`); the page, + the reading column and the answer do not. Prose therefore has to *wrap*, including a long URL + or an unbroken identifier — one long word is enough to push a paragraph wider than a phone, and + `.markdown` turns that into a sideways drag because a scroller in one axis makes the other axis + a scroller too. `overflow-x: hidden` on a parent is not the fix: it hides the symptom and clips + content people need to read. - **The reader fills the pane.** A fixed reading column left a gutter of nothing on each side while the prompt band still spanned the full width, so the two disagreed about where the conversation began. The pane is the measure: narrow the pane and the conversation narrows. diff --git a/web/src/conversation.css b/web/src/conversation.css index 3d21b51..3e67d0a 100644 --- a/web/src/conversation.css +++ b/web/src/conversation.css @@ -192,7 +192,11 @@ mark.cx-hit.on { background: var(--accent); color: var(--panel); } you scan for — still spanned the full width, so the two disagreed about where the conversation began. The pane is the measure: make it narrow and the conversation is narrow. */ -.cxv-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; background: var(--panel); padding: 4px 14px 30px; } +/* The gutter is a variable because the prompt band bleeds INTO it (below). A + hardcoded bleed against a padding that changes at a breakpoint drifts apart, + and the band ends up wider than the scroller it sits in — which is exactly + how the phone gained a sideways scroll: 14px of bleed, 8px of padding. */ +.cxv-body { --cx-gutter: 14px; flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; background: var(--panel); padding: 4px var(--cx-gutter) 30px; } .cxv-col { display: flex; flex-direction: column; min-width: 0; } .cxv-msg { font-size: 0.85em; color: var(--muted); padding: 6px 0; } /* The line above the oldest loaded exchange. Fixed height on purpose: it sits @@ -231,7 +235,7 @@ mark.cx-hit.on { background: var(--accent); color: var(--panel); } text column on the right made it read as a card floating over the answer rather than as the head of it. Full bleed both sides, with the text inside still on the column. */ -.cxv-col .cx-prompt { margin-right: -14px; padding-right: 14px; } +.cxv-col .cx-prompt { margin-right: calc(-1 * var(--cx-gutter)); padding-right: var(--cx-gutter); } .cxv-body > .cxv-col > .cx { padding-left: 16px; } /* Grouping: the meta row is the prompt's, not the answer's, so it sits tight @@ -241,7 +245,7 @@ mark.cx-hit.on { background: var(--accent); color: var(--panel); } /* ---------- phone ---------- */ @media (max-width: 720px) { - .cxv-body { padding: 4px 8px 24px; } + .cxv-body { --cx-gutter: 8px; padding: 4px var(--cx-gutter) 24px; } .cs-detail { font-size: 1em; } } diff --git a/web/src/styles.css b/web/src/styles.css index d6d83b6..ee57984 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -1147,6 +1147,17 @@ a.btn-ghost { text-decoration: none; } .markdown th, .markdown td { border: 1px solid var(--border); padding: 6px 10px; } .markdown img { max-width: 100%; } .markdown hr { border: none; border-top: 1px solid var(--border); margin: 16px 0; } +/* Prose wraps; only genuinely wide content scrolls. A URL or an unbroken + identifier is one long word, and a long word made the paragraph wider than + the pane — which .markdown then scrolled sideways, because a scroller in one + axis makes the other axis a scroller too (overflow-y: auto above). Reported + on a phone, where the pane is narrow enough for ordinary prose to do it. + `pre` and `table` keep their own overflow-x: auto: a code block or a wide + table is meant to scroll, inside its own box, and breaking a line of code to + fit would change what it says. */ +.markdown p, .markdown li, .markdown blockquote, +.markdown h1, .markdown h2, .markdown h3, .markdown h4 { overflow-wrap: anywhere; } +.markdown :not(pre) > code { overflow-wrap: anywhere; } /* usage page */ .usage { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; }