fix(queue): draw the scrim only where it can be tapped #182

Merged
logan merged 2 commits from fix/171-phone-queue-scrim into main 2026-08-21 16:47:46 +00:00
Collaborator

The issue. queue-panel's scrim has zero reachable pixels below
600px, so #24's tap-outside-to-close does not exist on a phone. Measured
at 424x439 with the queue open: host 424x318, .panel-content 424x318,
.scrim 424x318 and entirely underneath. It is not a bug in either rule
— the host draws the scrim across the content area, and the phone rule
:host([overlay]) .panel-content { width: 100% } then covers it.

Which direction, and why. The issue offers two and asks for the
choice to be made before the spec, because the spec differs. This takes
the second.

A gutter is the drawer pattern, and it buys "tap past it" by taking
width off a full-screen surface on a 424px viewport. #55 already
settled what this surface is at that width: a screen, with a history
entry, back as its dismissal and a 44x44 close button. A screen has no
outside, so the honest answer is that there is no scrim there — not one
drawn as a cursor: pointer dismissal target nobody can reach.

What changed. One conditional in queue-panel's render, plus the
matchMedia that feeds it.

  • The scrim renders when overlay && !phone. Existence rather than
    display: none, on job-band/search-trigger's rule: a hidden scrim
    is still an element carrying the dismissal handler.
  • phone is read in connectedCallback and follows the media query,
    which is also what lets a component test answer it — the runner's
    viewport is fixed at 1280x800.
  • The 600-899 band is untouched: there the panel is a 320px column
    of a wider content area, the scrim has real uncovered pixels, and
    clicking it closes the queue. Verified at 700x600: host 644x472, panel
    320x472, scrim 644x472.
  • Nothing moves visually on a phone, which is the point — the scrim was
    invisible there too.

Verification.

tier result
make e2e (chromium, against make dev-headless) 221 passed, incl. the new queue-as-a-screen.spec.ts case
make ui-test 986 passed, incl. two new in queue-overlay-mode.test.ts
npx tsc --noEmit (frontend + e2e), make css-check clean
screenshots at 424x439 and 700x600 phone unchanged; the compact scrim still dims and still closes

Both new tests were watched failing on the pre-fix build. The e2e one
needed a stash and a rebuild to fail honestly — the frontend is
embedded, so a stash alone re-runs the old bundle and passes green.

The e2e assertion is absence, not a click: the issue points out that
a naive phone-width case clicks the scrim's centre, hits the panel, and
passes on the broken build. WebKit is CI's half.

No Go changed, so make lint / make test were not run.

Deliberately not done. The gutter. It is recorded in CLAUDE.md as
the declined alternative rather than filed as an issue, since it is this
same decision stated the other way. No device tier either — unverified
on Chrome 113, though matchMedia and an absent element are nowhere
near that engine's documented gaps.

Closes #171

**The issue.** `queue-panel`'s scrim has zero reachable pixels below 600px, so #24's tap-outside-to-close does not exist on a phone. Measured at 424x439 with the queue open: host 424x318, `.panel-content` 424x318, `.scrim` 424x318 and entirely underneath. It is not a bug in either rule — the host draws the scrim across the content area, and the phone rule `:host([overlay]) .panel-content { width: 100% }` then covers it. **Which direction, and why.** The issue offers two and asks for the choice to be made before the spec, because the spec differs. This takes the second. A gutter is the drawer pattern, and it buys "tap past it" by taking width off a *full-screen* surface on a 424px viewport. #55 already settled what this surface is at that width: a **screen**, with a history entry, back as its dismissal and a 44x44 close button. A screen has no outside, so the honest answer is that there is no scrim there — not one drawn as a `cursor: pointer` dismissal target nobody can reach. **What changed.** One conditional in `queue-panel`'s render, plus the `matchMedia` that feeds it. - The scrim renders when `overlay && !phone`. **Existence** rather than `display: none`, on `job-band`/`search-trigger`'s rule: a hidden scrim is still an element carrying the dismissal handler. - `phone` is read in `connectedCallback` and follows the media query, which is also what lets a component test answer it — the runner's viewport is fixed at 1280x800. - The **600-899 band is untouched**: there the panel is a 320px column of a wider content area, the scrim has real uncovered pixels, and clicking it closes the queue. Verified at 700x600: host 644x472, panel 320x472, scrim 644x472. - Nothing moves visually on a phone, which is the point — the scrim was invisible there too. **Verification.** | tier | result | |---|---| | `make e2e` (chromium, against `make dev-headless`) | **221 passed**, incl. the new `queue-as-a-screen.spec.ts` case | | `make ui-test` | **986 passed**, incl. two new in `queue-overlay-mode.test.ts` | | `npx tsc --noEmit` (frontend + e2e), `make css-check` | clean | | screenshots at 424x439 and 700x600 | phone unchanged; the compact scrim still dims and still closes | Both new tests were **watched failing on the pre-fix build**. The e2e one needed a stash *and* a rebuild to fail honestly — the frontend is embedded, so a stash alone re-runs the old bundle and passes green. The e2e assertion is **absence**, not a click: the issue points out that a naive phone-width case clicks the scrim's centre, hits the panel, and passes on the broken build. WebKit is CI's half. No Go changed, so `make lint` / `make test` were not run. **Deliberately not done.** The gutter. It is recorded in `CLAUDE.md` as the declined alternative rather than filed as an issue, since it is this same decision stated the other way. No device tier either — unverified on Chrome 113, though `matchMedia` and an absent element are nowhere near that engine's documented gaps. Closes #171
Author
Collaborator

CI is green. Run 17400, both required jobs:

  • check — commit messages, lint, test (all three build configurations),
    frontend typecheck, css literals, the component/store suite, bindings
    and skill-check: all passed.
  • e2echromium and webkit both passed, which is the half this
    machine cannot run: Playwright's Linux WebKit links Ubuntu 24.04
    libraries Arch does not provide, so it is the closest available
    approximation of the WebKit2GTK renderer that ships.

Nothing left outstanding here beyond the device tier, which is stated in
the description.

**CI is green.** Run 17400, both required jobs: - `check` — commit messages, lint, test (all three build configurations), frontend typecheck, css literals, the component/store suite, bindings and skill-check: all passed. - `e2e` — **chromium and webkit both passed**, which is the half this machine cannot run: Playwright's Linux WebKit links Ubuntu 24.04 libraries Arch does not provide, so it is the closest available approximation of the WebKit2GTK renderer that ships. Nothing left outstanding here beyond the device tier, which is stated in the description.
logan force-pushed fix/171-phone-queue-scrim from ebe27ca3f0 to b0d4df5b48 2026-08-21 14:38:28 +00:00 Compare
logan added 2 commits 2026-08-21 16:24:05 +00:00
Below 600px `.panel-content` is `width: 100%`, so the scrim sat
entirely underneath an opaque panel -- measured at 424x439, host,
panel and scrim all 424x318. It dimmed nothing and dismissed nothing
there while wearing `cursor: pointer`, so #24's tap-outside-to-close
did not exist on the device it was drawn for.

Of the issue's two directions this takes the second. A gutter is the
drawer pattern and buys the affordance by taking width off a
full-screen surface on a 424px viewport; #55 already made the queue a
*screen* at that width, whose ways out are back and a 44px close
button. So there is no scrim there rather than an unreachable one.

Existence is `matchMedia` rather than `display: none`, on `job-band`'s
rule: a hidden scrim is still an element carrying the handler. The
600-899 band, where the panel is a 320px column of a wider content
area and the scrim has real uncovered pixels, is untouched.

The e2e half asserts *absence* at 424x439 rather than clicking,
because a phone-width case that clicks the scrim's centre hits the
panel and passes on the broken build -- which the issue anticipates.

Closes #171
test(queue): pin the breakpoint listener the scrim rule rests on
CI / check (push) Skipped
CI / e2e (push) Skipped
CI / check (pull_request) Successful in 2m30s
CI / e2e (pull_request) Successful in 9m18s
7ba5d321f6
The scrim's existence comes from matchMedia rather than a stylesheet, which only holds if the query is listened to — and the stub's addEventListener was a no-op, so deleting the listener left all 986 tests green. The stub records its listeners now and the new case carries a panel across the breakpoint in both directions. Watched failing with the listener removed.
logan force-pushed fix/171-phone-queue-scrim from 2155be8b28 to 7ba5d321f6 2026-08-21 16:24:05 +00:00 Compare
logan merged commit 327785e5ec into main 2026-08-21 16:47:46 +00:00
Sign in to join this conversation.