From 1ed8646a0434bfa2fd1dd7a3c8436080adc4f49b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 30 Aug 2026 06:56:34 +0000 Subject: [PATCH] Let a long change chip wrap instead of running off the phone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A chip's value carried `white-space: nowrap`, which was there so a signed number never breaks between its sign and its digits. It was applied to every value a chip can hold, and most of them are phrases rather than numbers: a refusal reason, "no change — at its limit", and the whole new value of a free-text stat, which is a sentence the AI wrote rather than a word. An unbreakable phrase sets the chip's minimum width to the width of the phrase, so `max-width: 100%` capped the box while the text kept painting past the rounded border and off the screen. The chip row sits inside the story text, which has nothing to scroll, so the page grew a horizontal scrollbar instead: a 87-character status value measured 470px against a 320px phone. The nowrap now applies only to the signed number, under `chg-num`. Every other value wraps inside its chip, which is what the surrounding `overflow-wrap` already did for the label. Measured in Chromium at 320, 360, 390 and 430px wide: that same value paints between 55px and 165px outside its chip before, and 0px after, with the page no longer scrolling sideways. The number chip stays on one line. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_017imUKVPhqophVUZZwJK7ST --- frontend/src/index.css | 14 ++++++++++---- frontend/src/pages/Play.jsx | 5 +++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/frontend/src/index.css b/frontend/src/index.css index 1324cc5..b606071 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1163,13 +1163,19 @@ button:disabled { opacity: 0.45; cursor: default; transform: none; box-shadow: n font-variant-numeric: tabular-nums; /* A chip must never be wider than the column it sits in: an NPC stat like "bandit leader aggression +10" overruns a phone, and the chip row is - inside the story text, which has nothing to scroll. The label may break - mid-word as a last resort; the value is glued to it by its own nowrap so - the sign and number never end up on separate lines. */ + inside the story text, which has nothing to scroll. Text may break + mid-word as a last resort, which is what keeps a chip's minimum width + small enough for the flex row to shrink it. */ max-width: 100%; overflow-wrap: anywhere; } -.chg-val { white-space: nowrap; } +.chg-val { overflow-wrap: anywhere; } +/* Only a signed number is held on one line, so the sign never ends up on a + line of its own. The other values a chip can carry are phrases — a refusal + reason, "no change — at its limit", or the whole new value of a free-text + stat — and holding those together set the chip's minimum width to the width + of the phrase, which is what pushed a chip out of the message on a phone. */ +.chg-num { white-space: nowrap; } .chg-up { color: var(--player, #4caf82); border-color: color-mix(in srgb, var(--player, #4caf82) 40%, var(--border)); } .chg-down { color: var(--danger, #e5484d); border-color: color-mix(in srgb, var(--danger, #e5484d) 40%, var(--border)); } .chg-flag { color: var(--accent-bright); } diff --git a/frontend/src/pages/Play.jsx b/frontend/src/pages/Play.jsx index 1854b40..93bd2f9 100644 --- a/frontend/src/pages/Play.jsx +++ b/frontend/src/pages/Play.jsx @@ -1252,9 +1252,10 @@ function StateChangeChips({ changes }) { // neither an update nor a refusal, and "+0" read as the former. const blocked = c.clamped && d === 0 const dir = blocked ? 'refused' : typeof d === 'number' ? (d > 0 ? 'up' : d < 0 ? 'down' : 'flat') : 'flat' + const signed = !blocked && typeof d === 'number' const txt = blocked ? 'no change — at its limit' - : typeof d === 'number' ? (d > 0 ? `+${d}` : `${d}`) : `→ ${c.value}` + : signed ? (d > 0 ? `+${d}` : `${d}`) : `→ ${c.value}` const title = blocked ? c.fix || 'The story asked to change this and it is already at the limit the scenario allows.' : c.clamped @@ -1262,7 +1263,7 @@ function StateChangeChips({ changes }) { : undefined return ( - {nice(c.label)} {txt} + {nice(c.label)} {txt} {c.clamped && !blocked ? (limited) : null} )