diff --git a/assets/css/table.css b/assets/css/table.css index 712c0d7..7386b2f 100644 --- a/assets/css/table.css +++ b/assets/css/table.css @@ -77,24 +77,29 @@ pointer-events: none; } -/* Fixed first column naming the two numbers stacked in each tab — which - metrics those are changes with the active profile (SunSoak/Shade, Indoors/ - Managed, Fur/Shade, Vehicle/Windows Open), so without this the numbers are - unlabelled. Sits outside .utci-day-tabs so it never scrolls away. +/* Fixed first column naming every stacked row in each tab — day name, date, + the weather/status icon, and the two numbers (which metrics those are + changes with the active profile: SunSoak/Shade, Indoors/Managed, Fur/Shade, + Vehicle/Windows Open) — so without this column the tabs read as unlabelled + numbers. Sits outside .utci-day-tabs so it never scrolls away. - Alignment: .utci-day-tabs stretches every tab to equal height and the - numeric block is the last thing in each one, so bottom-aligning this column - with matching padding lands the labels on the same lines as the values — - no need to replicate the day-name / date / icon stack above them. */ + Alignment: every label is absolutely positioned at a fixed offset from the + top of the column, matching the corresponding row inside .utci-day-tab. + Taking the labels out of normal flow is what makes this robust across + profiles: they no longer stack against each other, so a label that wraps + to two lines ("Managed Indoors") can't push the rows below it, and a + shorter one ("Shade Air") can't pull them up. Previously every label's + position depended on the height of the ones above it, so alignment tuned + against one profile drifted on the others. + + The offsets below are measured from the tab's own stack: + 1px border + 10px padding → day 16px → +3px date 16px → +6px icon 30px + → +2px values + The legend column has no top border of its own, hence the leading 11px. */ .utci-day-legend-col { + position: relative; flex: 0 0 var(--day-legend-w); - display: flex; - flex-direction: column; - justify-content: flex-end; - align-items: flex-end; - gap: 1px; - /* Bottom 11px = the tab's 10px padding + its 1px bottom border. */ - padding: 10px 6px 11px; + padding: 0 6px 0 0; background: #fdf8ee; text-align: right; font-family: Manrope, sans-serif; @@ -103,10 +108,76 @@ overflow-wrap: break-word; } +/* Shared anchoring for every absolutely-positioned label row. `left: 0` + + `right` (rather than a width) keeps them right-aligned against the column's + padding while still allowing long labels to wrap leftwards. */ +.utci-day-legend-day, +.utci-day-legend-date, +.utci-day-legend-icon, +.utci-day-legend-values { + position: absolute; + left: 0; + right: 6px; +} + +.utci-day-legend-day { + top: 11px; + height: 16px; + /* Explicit line-height (not the browser default "normal") so the row's + height is identical in Chrome and Firefox — those engines compute + "normal" differently for the same font and size. */ + line-height: 16px; + font-size: 8px; + font-weight: 700; + color: #9a7d5a; +} +.utci-day-legend-date { + top: 30px; + height: 16px; + line-height: 16px; + font-size: 8px; + font-weight: 700; + color: #9a7d5a; +} +.utci-day-legend-icon { + top: 52px; + height: 30px; + display: flex; + align-items: center; + justify-content: flex-end; + font-size: 8px; + font-weight: 700; + color: #9a7d5a; +} + +/* Positioning context for the two value labels. The separator and the + secondary label are pinned to fixed offsets inside it (matching the tab's + own hi/lo block) rather than stacking after the main label, so a main + label that wraps to two lines can't shove them down. */ +.utci-day-legend-values { + top: 84px; + height: 0; +} + +/* Divider between the top (warmer) and bottom (cooler) values — mirrors the + thin line added between the hi/lo numbers inside each tab. */ +.utci-day-legend-sep { + position: absolute; + top: 17px; + left: 0; + right: 0; + height: 1px; + background: rgba(0, 0, 0, 0.15); +} + /* Each label matches the weight and colour family of the value beside it, so the big/small pairing reads without a legend. Heights match the value line boxes: 14px x 1.1 and 11px x 1.1 (see the numeric block in DayTabs.js). */ .utci-day-legend-main { + position: absolute; + top: 0; + left: 0; + right: 0; display: flex; align-items: center; justify-content: flex-end; @@ -117,8 +188,17 @@ color: #6b4f2a; } .utci-day-legend-sec { + /* 20px matches the tab's secondary number, measured from the top of its + hi/lo block (15px main line + 5px separator gap). Absolute, so it holds + that offset even if the main label above it wraps. */ + position: absolute; + top: 20px; + left: 0; + right: 0; display: flex; - align-items: center; + /* Top-aligned (not centred) so the label stays level with the TOP of the + cooler/secondary value beside it even when the label text wraps. */ + align-items: flex-start; justify-content: flex-end; min-height: 12px; font-size: 8px; @@ -135,6 +215,11 @@ scroll-behavior: smooth; scrollbar-width: none; /* Firefox */ -ms-overflow-style: none; /* old Edge */ + /* Grab cursor hints drag-to-scroll, matching .utci-tbody-scroll */ + cursor: grab; +} +.utci-day-tabs:active { + cursor: grabbing; } .utci-day-tabs::-webkit-scrollbar { display: none; /* Chrome/Safari */ @@ -161,6 +246,15 @@ border-left: none; } +/* Explicit line-height (rather than the browser-default "normal") so this + row's rendered height is identical across browsers — Firefox and Chrome + compute "normal" differently for the same font/size, which threw off the + legend column's row-matching in .utci-day-legend-day (table.css). */ +.utci-day-name { + display: block; + line-height: 16px; +} + .utci-day-tab:hover:not(.active):not(.locked) { filter: brightness(1.05) !important; } @@ -191,6 +285,9 @@ font-family: Fraunces, serif; font-style: italic; font-size: 13px; + /* Explicit, not "normal" — pins the row height so it renders identically + across browsers (see .utci-day-name for why this matters). */ + line-height: 16px; text-transform: none; letter-spacing: 0; display: block; @@ -1100,6 +1197,7 @@ possible on phones. */ .utci-day-tabs-wrap { --day-legend-w: 56px; } .utci-day-legend-col { padding: 10px 4px 11px; letter-spacing: 0.04em; } + .utci-day-legend-day, .utci-day-legend-date, .utci-day-legend-icon { font-size: 7px; } .utci-day-legend-main { font-size: 8px; } .utci-day-legend-sec { font-size: 7px; } } diff --git a/assets/js/components/DayTabs.js b/assets/js/components/DayTabs.js index 768bb0d..4ec01bc 100644 --- a/assets/js/components/DayTabs.js +++ b/assets/js/components/DayTabs.js @@ -204,14 +204,21 @@ export function DayTabs({ onClick=${() => scrollDayTabs(1)} aria-label="Scroll days right" type="button">› - ${/* Fixed label column outside the scroller — names the two stacked - numbers in every tab, since which metrics they are changes with - the active profile. Bottom-aligned against the tabs' numeric - block (see .utci-day-legend-col in table.css). */''} + ${/* Fixed label column outside the scroller — names every stacked row + in each tab (day name, date, icon, then the two numbers, since + which metrics those are changes with the active profile). Mirrors + the tabs' own top-down layout row for row (see .utci-day-legend-col + in table.css). */''}