diff --git a/static/day.js b/static/day.js
index 8405a9a..41f0931 100644
--- a/static/day.js
+++ b/static/day.js
@@ -132,6 +132,22 @@ function render(data) {
].join("");
}
+// Collapse a space-separated unit shared by both bounds ("17.3 g/m³–19.9 g/m³"
+// → "17.3–19.9 g/m³") so ranges fit the narrow value column on phones. Attached
+// units (76°, 0.25") pass through untouched.
+function fmtRange(fmt, lo, hi) {
+ const a = fmt(lo), b = fmt(hi);
+ const i = a.lastIndexOf(" ");
+ if (i > 0 && b.endsWith(a.slice(i))) return `${a.slice(0, i)}–${b}`;
+ return `${a}–${b}`;
+}
+// The unit-less value for the ◀ marker — the unit is already on the range beside
+// it and in the card's summary, and dropping it keeps the marker on one line.
+const bareVal = (fmt, v) => {
+ const s = fmt(v), i = s.lastIndexOf(" ");
+ return i > 0 ? s.slice(0, i) : s;
+};
+
// One metric card: an observed summary line + the tier ladder (highest tier on
// top). The tier the observed value falls into is highlighted with its value.
function ladderCard(title, m, fmt, kind) {
@@ -153,7 +169,7 @@ function ladderCard(title, m, fmt, kind) {
? `median ${fmt(m.ladder.median)}`
: `${m.ladder.rain_days.toLocaleString()} rain days · dry ${m.ladder.dry_pct}%`;
const note = `${noteLeft}` +
- `Historical Range ${fmt(m.ladder.min)}–${fmt(m.ladder.max)}`;
+ `Historical Range ${fmtRange(fmt, m.ladder.min, m.ladder.max)}`;
const rows = m.ladder.tiers.map((t) => {
const active = t.c === activeClass ? " active" : "";
@@ -163,9 +179,9 @@ function ladderCard(title, m, fmt, kind) {
if (t.c === "dry") { val = t.range; pct = ""; }
else if (t.hi == null) val = `> ${fmt(t.lo)}`; // top tier: strictly beyond p99
else if (t.lo == null) val = `< ${fmt(t.hi)}`; // bottom tier: strictly below p1
- else val = `${fmt(t.lo)}–${fmt(t.hi)}`;
+ else val = fmtRange(fmt, t.lo, t.hi);
const marker = t.c === activeClass && obs
- ? `◀ ${fmt(obs.value)}` : "";
+ ? `◀ ${bareVal(fmt, obs.value)}` : "";
return `
${t.label}
diff --git a/static/style.css b/static/style.css
index a86365c..26a0f40 100644
--- a/static/style.css
+++ b/static/style.css
@@ -459,10 +459,12 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 24px 60px; }
.day-step:disabled { opacity: .4; cursor: default; }
/* Metric cards: one column on phones, side by side on monitors so the page
- doesn't run as a single long strip of full-width ladders. */
-#day-body { display: grid; grid-template-columns: 1fr; gap: 16px; align-items: start; }
-@media (min-width: 1000px) { #day-body { grid-template-columns: repeat(2, 1fr); } }
-@media (min-width: 3400px) { #day-body { grid-template-columns: repeat(3, 1fr); } }
+ doesn't run as a single long strip of full-width ladders. minmax(0, 1fr)
+ (not bare 1fr, whose min is the content) so one wide ladder row can't inflate
+ the shared column track past the viewport and push the whole page off-center. */
+#day-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; align-items: start; }
+@media (min-width: 1000px) { #day-body { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
+@media (min-width: 3400px) { #day-body { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.ladder-card {
background: var(--surface); border: 1px solid var(--border);
@@ -502,10 +504,14 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 24px 60px; }
.ladder-sw { width: 14px; height: 14px; border-radius: 4px; }
.ladder-label { font-weight: 700; color: color-mix(in oklab, var(--cat, var(--text)), var(--text) 22%); }
.ladder-pct { color: var(--muted); font-size: 12px; }
-.ladder-val { justify-self: end; font-variant-numeric: tabular-nums; white-space: nowrap; }
+/* Value ranges may wrap (long unit strings like "8.1 g/m³–12.9 g/m³" on narrow
+ phones) — nowrap here would widen the row past the card and scroll the page. */
+.ladder-val { justify-self: end; text-align: right; font-variant-numeric: tabular-nums; }
/* Observed marker: stays in the rightmost column but reads from its left edge,
so the arrow sits right beside the value range it points at. */
.ladder-mk { justify-self: start; min-width: 0; }
+/* Markers are unit-less ("◀ 11.5") so nowrap can't push them past the card —
+ the widest (precip, ◀ 0.25") bleeds a few px into the row padding at most. */
.ladder-mark { color: var(--accent); font-weight: 800; white-space: nowrap; font-size: 12.5px; }
@@ -857,10 +863,13 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 24px 60px; }
#cal-tip .tt-type { font-size: 13.5px; margin: 1px 0 5px; padding-bottom: 5px; }
#cal-tip .tt-grid { column-gap: 8px; row-gap: 2px; }
/* Day ladder on mobile: tighten the fixed tracks but keep every column (including
- the percentile range) so the ranges still line up down the ladder. */
+ the percentile range) so the ranges still line up down the ladder. Slack moved
+ from the pct/marker tracks to the value column keeps the longest range
+ ("17.3–19.9 g/m³", ~88px) on one line down to ~375px screens; narrower than
+ that it wraps at the unit. The label track can't give ("Above Normal" ≈ 89px). */
.day-nav { width: 100%; }
.day-date { flex: 1; }
- .ladder-row { grid-template-columns: 13px 90px 54px 1fr 48px; column-gap: 8px; font-size: 12.5px; }
+ .ladder-row { grid-template-columns: 13px 90px 46px 1fr 42px; column-gap: 8px; font-size: 12.5px; }
header { padding: 14px 16px; }
h1 { font-size: 19px; }