docs(player): record the phone transport, and four silent failures
The model in CLAUDE.md beside the volume rule it qualifies; the measurements and the four things that cost a cycle each in NOTES.md, dated. Three of the four are invisible to every assertion in the repo: a button not inheriting its font, a nested rule out-specifying a later one, and art whose height is bounded by nothing.
This commit is contained in:
@@ -4487,3 +4487,75 @@ is not orphaned" and "a docked column is not in the stack" are both
|
||||
vacuously true of a build that pushes no entry at all. Reverting the
|
||||
source and re-running is what established which were which, and the
|
||||
file says so in its header rather than implying all nine reproduce.
|
||||
|
||||
## The phone's transport, and three things that only a screenshot or a stash could see (measured 2026-08-21)
|
||||
|
||||
#59 and #56 were done as one PR — argued on #73 first — because they are
|
||||
the same row of pixels: one removes controls from the phone's bar and
|
||||
the other enlarges what is left, and both are one property on
|
||||
`player-controls`. Measured at 424x439 before:
|
||||
|
||||
| control | before | after |
|
||||
|---|---|---|
|
||||
| bar: shuffle / prev / play / next / repeat | 33x21 each | prev/next 44, play 56, shuffle+repeat moved |
|
||||
| bar: favourite | **18x14** | 44x44 |
|
||||
| bar: queue button | 33x29 | gone (#59) |
|
||||
| Now Playing: all five | 33x21 each | 44, play 64 |
|
||||
| desktop bar: all five | 33x21 | **33x21** |
|
||||
|
||||
Four things cost a cycle each and are worth keeping.
|
||||
|
||||
**A `<button>` does not inherit its font from its parent.** The UA
|
||||
stylesheet gives it one, so `font-size: inherit` on a button is a
|
||||
*change*, not a no-op: it took every desktop control from 33x21 to
|
||||
36x24 by moving them from 13.3px to the shell's 16px. Nothing failed.
|
||||
The only way it surfaced was measuring the baseline by stashing the file
|
||||
and re-running — which is now what `phone-transport.spec.ts` pins, with
|
||||
a literal `'33x21'` rather than a range, because a range swallows three
|
||||
pixels.
|
||||
|
||||
**A rule at the bottom of `index.css` still loses to a nested rule
|
||||
above it.** The phone block is last on purpose because a media query
|
||||
adds no specificity — but `#queue-button` is written *nested* inside
|
||||
`.bottom-bar`, so it builds to a descendant selector one class more
|
||||
specific, and a bare `#queue-button { display: none }` in the phone
|
||||
block did nothing at all. Silently: the button simply stayed. Nesting
|
||||
adds specificity the source does not show.
|
||||
|
||||
**Removing a control moved the question of how you reach what is left,
|
||||
and ten specs were quietly asserting the old answer.** Hiding the bar's
|
||||
queue button failed ten tests in four files about the back stack and
|
||||
about layout, every one of which opened the queue by clicking
|
||||
`#queue-button`. `openTheQueue` in `e2e/support/fixtures.ts` is the
|
||||
route *this viewport* offers, and the fix was to stop hard-coding one.
|
||||
|
||||
**And the route it takes did not exist in the state that matters.**
|
||||
`now-playing` renders two branches, and the no-track one had no
|
||||
`.expand` button — so with nothing loaded there was no way to Now
|
||||
Playing, and once the queue button left the bar the queue was
|
||||
unreachable outright. The queue is persisted across restarts, so this
|
||||
is a state the app launches into, not a corner. It first appeared as a
|
||||
*flake* (#168: the long-lived e2e app meant whether a track was loaded
|
||||
depended on which spec ran first), which is worth remembering — a leak
|
||||
made a deterministic bug look like a race.
|
||||
|
||||
## Now Playing does not fit a 439px screen, and #56 makes that visible (measured 2026-08-21)
|
||||
|
||||
Two separate things, and only the first is a defect.
|
||||
|
||||
**The art overflowed its own box and drew over the header and the
|
||||
title.** It is `width: min(100%, 60vh); aspect-ratio: 1`, so its height
|
||||
is derived from its width and bounded by nothing — 60vh bounds the
|
||||
*viewport*, not the room left over, and those differ by all the chrome
|
||||
above and below. `max-height: 100%` is the fix and shipped with #56.
|
||||
Pre-existing: screenshotted on `main`. **Found by reading a screenshot,
|
||||
which is the only tier that can see it** — nothing fails, the shell does
|
||||
not overflow, and every control is still hittable.
|
||||
|
||||
**With that fixed, the art is a 39px sliver**, because the transport is
|
||||
now 172px of a 439px screen. That is a consequence of #56 rather than a
|
||||
fault in it, and it is filed as #172 with the per-element budget. #64
|
||||
(no in-app volume on Android) is ~30px of pure gain there and #51 is the
|
||||
umbrella; folding shuffle and repeat back onto the primary row was
|
||||
considered and rejected — it buys 52px, leaves the art at 91px, and
|
||||
costs a third arrangement of the same five buttons.
|
||||
|
||||
@@ -1728,6 +1728,55 @@ rather than after the state, because with the slider beside it there is
|
||||
nothing left to disclose. It stands down below 600px whatever the
|
||||
setting says — that is about the platform rather than preference, and
|
||||
is why `mediacontrols`' Android handler implements no volume callback.
|
||||
(Only the *bar's* copy: `now-playing-view` renders one and it is
|
||||
visible on a phone. #64 asks for it to be gone on Android outright,
|
||||
which is a platform question the frontend cannot currently ask.)
|
||||
|
||||
**And below 600px that bar carries three controls, not five** (#59).
|
||||
Shuffle, repeat and the queue button leave it; what is left is art,
|
||||
title/artist, favourite, and prev/play/next. `player-controls` is one
|
||||
component in two places and **the context is a property rather than a
|
||||
media query**, which is the exception to the rule two paragraphs down:
|
||||
on a phone the bar wants three controls and `now-playing-view` wants
|
||||
five, larger still, *at the same viewport* — so the host states the
|
||||
context and the viewport states the size band, and neither alone can
|
||||
express it. Sizes come from `--yj-control-*` custom properties set per
|
||||
context; play/pause alone goes above the 44px floor, because a row of
|
||||
identical squares says every action is equally likely and that is not
|
||||
true of play. Measured before #56: every one of them was **33×21px**,
|
||||
and the mini bar's favourite was **18×14**, the smallest control in the
|
||||
app.
|
||||
|
||||
Four things about it are load-bearing.
|
||||
|
||||
**The phone draws three buttons rather than hiding two**, from
|
||||
`matchMedia` — `job-band`'s pattern, and the rule that a decision about
|
||||
whether an element *exists* is not a stylesheet's to make. A
|
||||
`display: none` control is still in the shadow root and still something
|
||||
a positional query finds, so "the phone has three controls" would have
|
||||
been true of the pixels and false of the element.
|
||||
|
||||
**Removing a control is only allowed because it is still reachable.**
|
||||
Plan 018's matrix promises no action is unreachable at any supported
|
||||
size, and all three are on `now-playing-view`, one tap away through the
|
||||
mini player's art. That promise is what `phone-transport.spec.ts`
|
||||
asserts — it walks the route — rather than counting buttons.
|
||||
|
||||
**So the route to Now Playing must not depend on what is playing**, and
|
||||
it did. `now-playing` renders two branches and the no-track one had no
|
||||
`.expand` button on its placeholder, so with nothing loaded there was
|
||||
no way to the full-screen view — which, once the queue button left the
|
||||
bar, made the *queue* unreachable. The queue is persisted across
|
||||
restarts, so "tracks queued, nothing playing" is a state the app
|
||||
launches into.
|
||||
|
||||
**The desktop bar is untouched and a spec says so with a literal.**
|
||||
Both issues are `Platform/Android`. The trap is that a `<button>` does
|
||||
not inherit its font from its parent — the UA stylesheet gives it one —
|
||||
so a generic `font-size: inherit` is not the no-op it reads as: it took
|
||||
every desktop button from 33×21 to 36×24, silently. The sizes are
|
||||
asserted as `'33x21'` rather than as a range, because the regression
|
||||
was three pixels.
|
||||
|
||||
**900 is the worst desktop width, not the 800×600 minimum.** The
|
||||
sidebar collapses to icons *below* 900, so the main panel is 843px at
|
||||
|
||||
Reference in New Issue
Block a user