diff --git a/JoshHeaps.Net/wwwroot/css/casino/holdem.css b/JoshHeaps.Net/wwwroot/css/casino/holdem.css index 5bf9e03..9708bf0 100644 --- a/JoshHeaps.Net/wwwroot/css/casino/holdem.css +++ b/JoshHeaps.Net/wwwroot/css/casino/holdem.css @@ -5199,10 +5199,23 @@ body.hasActionBar #toastHost { the worst any of these phones actually publishes is 142, which lays out fine. Landscape overrides all of this outright, further down the file. */ + /* The fallback is what the felt is drawn at before actionBar.js has measured + anything, which is a real frame a dealer sees — the scripts run at the end of the + body and the table is laid out inside main.js's DOMContentLoaded, so the browser + has already painted by the time --feltRoomPx exists. + + `100vh` was the worst guess available: it says the whole window is free. Measured + at 360x640 nine-handed, the felt came up 336x504 and dropped to 336x374 as soon as + the bar was measured — 130px of table, with every seat on it, moving after it was + readable. This is a guess too, but a near one: 9rem is what two other rules in + this file already assume a bar costs before it can be asked, and 7rem is what sits + above and below the felt. It lands 10px over the truth at 360x640, and since this + is a ceiling rather than a height, over is a small shrink rather than a seat + behind the bar. Anything measured replaces it on the next frame. */ #pokerTableWrap { --feltAspect: 1.5; max-width: none; - max-height: var(--feltRoomPx, 100vh); + max-height: var(--feltRoomPx, calc(100vh - var(--actionBarHeight, 9rem) - 7rem)); } /* Stacked, with the action that ends the hand furthest from a stray thumb. */ diff --git a/JoshHeaps.Net/wwwroot/js/casino/holdem/actionBar.js b/JoshHeaps.Net/wwwroot/js/casino/holdem/actionBar.js index 02d7e2c..d57838f 100644 --- a/JoshHeaps.Net/wwwroot/js/casino/holdem/actionBar.js +++ b/JoshHeaps.Net/wwwroot/js/casino/holdem/actionBar.js @@ -16,8 +16,14 @@ const ActionBar = { state.actingSeatIndex !== null && state.actingSeatIndex !== undefined ? state.actingSeatIndex : null; + // watchHeight first, because render() may reach for publishHeight; then publish + // once there is a bar to measure. The ResizeObserver does come round on its own + // when the markup's `hidden` comes off — but it arrives a frame later at best, + // and measured on a cold load with nine seats to lay out it was 875ms behind. + // The felt is drawn inside that gap. this.watchHeight(); this.render(); + this.publishHeight(); }, // The bar is fixed to the bottom of the screen, so everything else has to know how @@ -31,13 +37,29 @@ const ActionBar = { if (!host || this.heightWatcher) return; const publish = () => { - const visible = !host.hidden; const rail = this.isRail(host); + // A bar nobody has drawn yet is not a bar of zero height. It is a bar whose + // height nobody knows, and saying zero is answering the question wrongly + // rather than declining it: the felt reads this to decide how tall to be, + // and zero tells it the whole window is free. + // + // It is the state this bar starts in — `