Android: every control that is not the transport is below the 44px touch floor #186

Closed
opened 2026-08-21 19:39:55 +00:00 by logan · 5 comments
Collaborator

Report

Every control in the app that is not the transport is below the 44px
touch floor on a phone. #56 sized the playback controls for a thumb and
nothing else was resized, so the controls a user meets on every
screen — the sort control, the sort direction, the overflow menu, the
page actions — are between a third and two thirds of the floor the same
issue established.

Measured on the reference device (TLP301, Android 14, WebView Chrome
113, 424x439 CSS px) with a real 1,577-track library, by walking every
primary view and reading getBoundingClientRect() on everything
matching a control selector.

control size where
page-sort-direction 28x21 tracks, albums, artists, genres, playlists
page-sort select 66-107 x 23 every list view
page-actions-more 38x27 playlists
page-action-shuffle-suggestions 168x29 home
search-trigger 40x40 every list view — and it is phone-only
explore search-mode tabs 89x26, 79x26 explore
explore search input 325x18 explore
config-field select 335x30 settings
scan action buttons 108x30, 85x30, 107x30 settings
library row overflow 31x31 settings
library-filter select 120x32 settings
first-run wizard buttons 120x33, 105x33 the first screen a user sees

Findings

  • This is not a reachability failure and the audit says so. Plan
    018's promise is that no action is unreachable at any supported size,
    and it holds: at 424x439 the shell does not overflow on any view
    (documentElement.scrollWidth is 424 against a 424 viewport
    everywhere), nothing is stranded outside a scrollable ancestor, and a
    hit test at each control's centre reaches the control. They are all
    hittable — they are just small enough that hitting them is the
    user's problem rather than the app's.
  • The floor is already the app's own number. #56's Findings name
    44px, #55 sized the queue header's buttons to it, and the queue panel
    measures 44x44 throughout — so this is one rule applied unevenly
    rather than a new rule.
  • search-trigger is the sharpest case, because it exists only
    on a phone: #57 created it as the phone's replacement for the header
    search box, and it shipped at 40x40. A control introduced for touch
    is the one that should not have to be argued about.
  • The sort direction arrow is the smallest at 28x21, and it has no
    visible box at all — it reads as an icon rather than a button, which
    is a second problem on top of the size.
  • Settings is the densest offender and also the least surprising: it is
    a form, and config-field's control is the shape every row uses, so
    one rule there covers 93 controls.

Direction

One pass over page-header covers five views at once and is the
obvious place to start — the sort control, its direction button, the
overflow trigger and the action buttons all live there, and the
component already measures itself for the overflow rule (#69), so it is
a stylesheet change rather than a layout one. Then config-field for
Settings, and explore-view's own search row.

The floor is 44px and should be reached by growing the hit area
rather than the visual weight where the two can differ — a phone header
that becomes three rows of chunky buttons trades this problem for #69's.
Padding on the control, not size on the icon.

Two things to decide rather than assume. Whether this is phone-only:
page-header has no phone branch today and CLAUDE.md's stated reason
is that a second declaration of what a phone shows is a second thing to
keep in step — but a 44px sort control on a desktop is merely large,
not wrong, so "grow it everywhere" may be the cheaper answer. And the
seek bar is filed separately (its drag target is 6px) because the fix
there is a hit area that is deliberately larger than the painted
control, which is a different move from padding a button.

**Report** Every control in the app that is not the transport is below the 44px touch floor on a phone. #56 sized the playback controls for a thumb and nothing else was resized, so the controls a user meets on *every* screen — the sort control, the sort direction, the overflow menu, the page actions — are between a third and two thirds of the floor the same issue established. Measured on the reference device (TLP301, Android 14, WebView Chrome 113, 424x439 CSS px) with a real 1,577-track library, by walking every primary view and reading `getBoundingClientRect()` on everything matching a control selector. | control | size | where | |---|---|---| | `page-sort-direction` | **28x21** | tracks, albums, artists, genres, playlists | | `page-sort` select | 66-107 x **23** | every list view | | `page-actions-more` | **38x27** | playlists | | `page-action-shuffle-suggestions` | 168x**29** | home | | `search-trigger` | **40x40** | every list view — and it is phone-only | | explore search-mode tabs | 89x**26**, 79x**26** | explore | | explore search input | 325x**18** | explore | | `config-field` select | 335x**30** | settings | | scan action buttons | 108x**30**, 85x**30**, 107x**30** | settings | | library row overflow | **31x31** | settings | | `library-filter` select | 120x**32** | settings | | first-run wizard buttons | 120x**33**, 105x**33** | the first screen a user sees | **Findings** - **This is not a reachability failure and the audit says so.** Plan 018's promise is that no action is unreachable at any supported size, and it holds: at 424x439 the shell does not overflow on any view (`documentElement.scrollWidth` is 424 against a 424 viewport everywhere), nothing is stranded outside a scrollable ancestor, and a hit test at each control's centre reaches the control. They are all *hittable* — they are just small enough that hitting them is the user's problem rather than the app's. - **The floor is already the app's own number.** #56's Findings name 44px, #55 sized the queue header's buttons to it, and the queue panel measures 44x44 throughout — so this is one rule applied unevenly rather than a new rule. - **`search-trigger` is the sharpest case**, because it exists *only* on a phone: #57 created it as the phone's replacement for the header search box, and it shipped at 40x40. A control introduced for touch is the one that should not have to be argued about. - **The sort direction arrow is the smallest at 28x21**, and it has no visible box at all — it reads as an icon rather than a button, which is a second problem on top of the size. - Settings is the densest offender and also the least surprising: it is a form, and `config-field`'s control is the shape every row uses, so one rule there covers 93 controls. **Direction** One pass over `page-header` covers five views at once and is the obvious place to start — the sort control, its direction button, the overflow trigger and the action buttons all live there, and the component already measures itself for the overflow rule (#69), so it is a stylesheet change rather than a layout one. Then `config-field` for Settings, and `explore-view`'s own search row. The floor is 44px and should be reached by growing the *hit* area rather than the visual weight where the two can differ — a phone header that becomes three rows of chunky buttons trades this problem for #69's. Padding on the control, not size on the icon. Two things to decide rather than assume. Whether this is phone-only: `page-header` has no phone branch today and CLAUDE.md's stated reason is that a second declaration of what a phone shows is a second thing to keep in step — but a 44px sort control on a desktop is merely large, not wrong, so "grow it everywhere" may be the cheaper answer. And the seek bar is filed separately (its drag target is 6px) because the fix there is a hit area that is deliberately larger than the painted control, which is a different move from padding a button.
Author
Collaborator

The sweep was extended to the detail views, Downloads and Autotag,
which the first table did not cover. Same device, same method. Six more
controls, and two of them are smaller than anything in the original
list.

control size where
folders-menu-trigger 32x18 autotag
section-toggle 187x15 autotag
back-button 32x32 artist-details
page-action-check-now 113x29 downloads
Requests / Downloads tabs 85x34, 96x34 downloads
fav-btn (mini player) 44x44 every view — at the floor, listed for completeness

artist-details' back button is the one to look at first, because
it is not merely small — it is the way out of a detail view, and #55
already settled that case one component over: "the way out is 44px on a
phone", when the queue's close button was 25x21 and the scrim had no
uncovered pixels to tap. An artist page reached from a card has the
platform's back gesture as well, so this is less severe than the queue
was, but it is the same control wearing the same mistake.

Autotag's 15px section toggle is the smallest control measured
anywhere in the app
— smaller than the 18x14 favourite #56 called out
as the worst case. Autotag is off by default (#25), which is presumably
why nobody has met it.

Nothing new for the null result: at 424x439 the shell does not overflow
and no control is stranded on any view — the ten primary ones, the
queue, album-details, artist-details, Downloads or Autotag.

**The sweep was extended to the detail views, Downloads and Autotag**, which the first table did not cover. Same device, same method. Six more controls, and two of them are smaller than anything in the original list. | control | size | where | |---|---|---| | `folders-menu-trigger` | **32x18** | autotag | | `section-toggle` | 187x**15** | autotag | | `back-button` | **32x32** | artist-details | | `page-action-check-now` | 113x**29** | downloads | | Requests / Downloads tabs | 85x**34**, 96x**34** | downloads | | `fav-btn` (mini player) | 44x44 | every view — at the floor, listed for completeness | **`artist-details`' back button is the one to look at first**, because it is not merely small — it is the way *out* of a detail view, and #55 already settled that case one component over: "the way out is 44px on a phone", when the queue's close button was 25x21 and the scrim had no uncovered pixels to tap. An artist page reached from a card has the platform's back gesture as well, so this is less severe than the queue was, but it is the same control wearing the same mistake. **Autotag's 15px section toggle is the smallest control measured anywhere in the app** — smaller than the 18x14 favourite #56 called out as the worst case. Autotag is off by default (#25), which is presumably why nobody has met it. Nothing new for the null result: at 424x439 the shell does not overflow and no control is stranded on **any** view — the ten primary ones, the queue, `album-details`, `artist-details`, Downloads or Autotag.
logan self-assigned this 2026-08-21 23:36:00 +00:00
logan added the
Status
In Progress
label 2026-08-21 23:36:01 +00:00
Author
Collaborator

Taking this, scoped to the Direction's first step: page-header (the
sort control, its direction button, the overflow trigger and the action
buttons) plus search-trigger. config-field's 93 Settings controls
and explore-view's search row are the obvious second pass and are
deliberately not in this one -- Settings is a form with one shape for
every row and wants its own argument.

Both open questions answered by measurement rather than by taste, and
the same answer settles both.
Measured on the device at 424x439: the
header is 63px tall while its controls are 20-23px, so the vertical
room is already there; the select and its direction arrow are 6px
apart, so the horizontal room is not.

So the target grows the way #187's did -- padding with the margins
cancelling it -- and that decides the rest:

  1. Not phone-only. With the layout box unchanged there is nothing
    to key on a breakpoint, so page-header grows no phone branch (the
    thing CLAUDE.md declines to add) and no media query that no tier
    renders, which is exactly the trap #187 just turned up. A 44px hit
    area on a desktop is invisible.
  2. #69's fit pass does not move, by construction rather than by
    re-tuning: it measures the rendered boxes, and the boxes are the
    same. header-action-overflow.spec.ts's expectations should stand
    as written, which is the check rather than the assumption.

The direction arrow is the one that needs horizontal growth (28x21),
and it will be asymmetric for #187's reason: the select is 6px to its
left and there is free space to its right, so the target takes the side
that has nothing to steal from.

Taking this, scoped to the Direction's first step: `page-header` (the sort control, its direction button, the overflow trigger and the action buttons) plus `search-trigger`. `config-field`'s 93 Settings controls and `explore-view`'s search row are the obvious second pass and are deliberately not in this one -- Settings is a form with one shape for every row and wants its own argument. **Both open questions answered by measurement rather than by taste, and the same answer settles both.** Measured on the device at 424x439: the header is 63px tall while its controls are 20-23px, so the *vertical* room is already there; the select and its direction arrow are 6px apart, so the horizontal room is not. So the target grows the way #187's did -- padding with the margins cancelling it -- and that decides the rest: 1. **Not phone-only.** With the layout box unchanged there is nothing to key on a breakpoint, so `page-header` grows no phone branch (the thing CLAUDE.md declines to add) and no media query that no tier renders, which is exactly the trap #187 just turned up. A 44px hit area on a desktop is invisible. 2. **#69's fit pass does not move**, by construction rather than by re-tuning: it measures the rendered boxes, and the boxes are the same. `header-action-overflow.spec.ts`'s expectations should stand as written, which is the check rather than the assumption. The direction arrow is the one that needs horizontal growth (28x21), and it will be asymmetric for #187's reason: the select is 6px to its left and there is free space to its right, so the target takes the side that has nothing to steal from.
Author
Collaborator

First pass landed (PR #195, merged as 52038dc): page-header's
sort control, its direction arrow, the action buttons and the overflow
trigger, plus search-trigger. Measured on the device afterwards, every
control in the header is now at least 44x44:

control before after
page-sort 99x23 99x44
page-sort-direction 28x21 44x44
page-actions-more 38x27 44x44
action buttons 168x29 168x44
search-trigger 40x40 44x44

Both questions this issue left open are answered, and the answer to
the first is not the one I reached first.

Phone-only or everywhere? Everywhere. A 44px control on a desktop is
merely large, and a second declaration of what a phone shows is a
second thing to keep in step -- which is why this component has never
had one. It also avoids a media query no tier renders, which is exactly
how the seek bar's phone rule came to be dead for months (#187).

Does #69's fit move? It did, and that is the finding worth
recording.
Growing the two square controls to 44px as boxes added
22px to the header. It fit at every width Chromium was checked at and
clipped the overflow trigger at 320x600 in WebKit -- caught only by
CI, because Playwright's Linux WebKit cannot run on this machine. I had
stated it as a property on the strength of one engine.

The repair is what this issue's own Direction asked for and I had
deviated from: "reached by growing the hit area rather than the visual
weight ... padding on the control, not size on the icon"
. #69's pass
measures inline size, so a taller control is free and a wider one is
not. Height is a box; width is padding with a negative margin handing
the space back. The three controls now occupy 29, 38 and 40 px -- what
they occupied before any of this -- so the fit sees an unchanged header.

The general rule, for the second pass and for anything else here:
in a container that measures itself, only the width of a touch target
is contested. Where the two must differ, getBoundingClientRect()
still measures the target directly, because it includes padding while
the negative margin removes the space from layout -- so this stays
checkable in the component tier rather than needing a stylesheet
assertion the way #187 did.

What remains, and why it is not in that PR.

  • config-field, the 93 Settings controls. Close to a one-rule
    change and easier than the header, since a form has no overflow fit
    and the width is therefore uncontested -- only height, which is free.
    What it needs instead is a density argument: every row on a long page
    gets taller on a 439px screen, and it should go through
    make ui-visual rather than be asserted only by numbers.
  • explore-view's own search row.
  • The controls from the second table in the comment above --
    folders-menu-trigger (32x18), section-toggle (187x15),
    back-button (32x32), page-action-check-now (113x29) and the
    Downloads tabs (85x34, 96x34).

One thing not in either table, so the next pass does not spend time
on it:
the skip link is 147x35. It is keyboard-only and unreachable
by touch, so it is not a touch-target defect.

Unclaiming: the header pass is done and the rest is a separate piece of
work that wants the visual suite.

**First pass landed** (PR #195, merged as `52038dc`): `page-header`'s sort control, its direction arrow, the action buttons and the overflow trigger, plus `search-trigger`. Measured on the device afterwards, every control in the header is now at least 44x44: | control | before | after | |---|---|---| | `page-sort` | 99x23 | 99x44 | | `page-sort-direction` | **28x21** | 44x44 | | `page-actions-more` | 38x27 | 44x44 | | action buttons | 168x29 | 168x44 | | `search-trigger` | 40x40 | 44x44 | **Both questions this issue left open are answered, and the answer to the first is not the one I reached first.** *Phone-only or everywhere?* Everywhere. A 44px control on a desktop is merely large, and a second declaration of what a phone shows is a second thing to keep in step -- which is why this component has never had one. It also avoids a media query no tier renders, which is exactly how the seek bar's phone rule came to be dead for months (#187). *Does #69's fit move?* **It did, and that is the finding worth recording.** Growing the two square controls to 44px as *boxes* added 22px to the header. It fit at every width Chromium was checked at and **clipped the overflow trigger at 320x600 in WebKit** -- caught only by CI, because Playwright's Linux WebKit cannot run on this machine. I had stated it as a property on the strength of one engine. The repair is what this issue's own Direction asked for and I had deviated from: *"reached by growing the hit area rather than the visual weight ... padding on the control, not size on the icon"*. #69's pass measures **inline size**, so a taller control is free and a wider one is not. Height is a box; width is padding with a negative margin handing the space back. The three controls now occupy 29, 38 and 40 px -- what they occupied before any of this -- so the fit sees an unchanged header. **The general rule, for the second pass and for anything else here:** in a container that measures itself, only the *width* of a touch target is contested. Where the two must differ, `getBoundingClientRect()` still measures the target directly, because it includes padding while the negative margin removes the space from layout -- so this stays checkable in the component tier rather than needing a stylesheet assertion the way #187 did. **What remains, and why it is not in that PR.** - **`config-field`, the 93 Settings controls.** Close to a one-rule change and *easier* than the header, since a form has no overflow fit and the width is therefore uncontested -- only height, which is free. What it needs instead is a density argument: every row on a long page gets taller on a 439px screen, and it should go through `make ui-visual` rather than be asserted only by numbers. - **`explore-view`'s own search row.** - The controls from the second table in the comment above -- `folders-menu-trigger` (32x18), `section-toggle` (187x15), `back-button` (32x32), `page-action-check-now` (113x29) and the Downloads tabs (85x34, 96x34). **One thing not in either table, so the next pass does not spend time on it:** the skip link is 147x35. It is keyboard-only and unreachable by touch, so it is not a touch-target defect. Unclaiming: the header pass is done and the rest is a separate piece of work that wants the visual suite.
logan removed their assignment 2026-08-22 00:32:58 +00:00
logan removed the
Status
In Progress
label 2026-08-22 00:32:59 +00:00
logan self-assigned this 2026-08-22 02:33:57 +00:00
logan added the
Status
In Progress
label 2026-08-22 02:33:57 +00:00
Author
Collaborator

Taking the second pass, scoped to Settings. explore-view's search
row and the second table's five one-off controls (folders-menu-trigger,
section-toggle, back-button, page-action-check-now, the Downloads
tabs) stay for a third pass unless this one lands small enough to carry
them.

Branch: 186-touch-targets-settings.

The sweep found 120 controls below the floor on Settings, not 93, and
config-field is 8 of them.
Re-measured on the device just now
(TLP301, 424x439, main at 52038dc, index build stopped and jobs
empty), walking every shadow root with all eleven config-sections
expanded:

control size count
column-arrow-btn 16x14, 18x14 36
column-toggle (checkbox) 16x16 29
shortcut-capture button 80x25 26
download client checkbox 16x16 8
config-field select 335x30 7
wa-input control 204x20, 271x20 4
wa-button 185x21, 163x21 2
config-field colour swatch 33x33 1
library-filter select 120x32 1
scan actions (Add Library / Scan All / Full Rescan) 108x30, 85x30, 107x30 3
library row overflow-btn 31x31 1
btn-ghost 133x23 1

So the 16x14 column arrows are the smallest controls in the app --
smaller than autotag's 15px section toggle, and there are 36 of them.
The original table's config-field row was the visible offender on a
collapsed page; the density lives behind the disclosures.

The density argument, measured rather than guessed, and it is
smaller than I expected.
The rows are already close to the floor:
.column-item is 335x36 and .shortcut-row is 335x37 — it is the
controls inside them that are 14-25px, not the rows. So raising a row
to 44 costs 8px, and the two column lists (10 and 19 items) grow by 232px
in total. That is about half a screen of extra scroll on a 439px
viewport, on a page that already scrolls, which is a real cost and not
one worth trading a 16x14 target for.

That reframes the approach and makes it cheaper than the header's
was.
Where a row is already ~36px and its control is 16px, the fix is
to grow the control into the row it already occupies rather than to
grow the row. Three shapes:

  1. The arrows take padding. .column-arrow-btn has
    background: none and a transparent border, so padding is
    invisible until hover — the target grows and the visual weight does
    not, which is this issue's own Direction.
  2. The column toggle gets a label rather than a bigger box. A
    native checkbox cannot grow its hit area without growing its paint,
    and a 44px checkbox is not what anyone wants. Wrapping the checkbox
    and its text in a <label> makes the row's text the target, which
    is ~250x44 — and config-field's own comment already argues for
    exactly this ("a real label association also makes the label text a
    click target for the control, which is behaviour, not annotation").
  3. The rest is min-height, which is free: there is no overflow fit
    on this page, so the header pass's "only width is contested" rule
    does not bind here at all.

The wa-input and wa-button rows are Web Awesome's own shadow roots,
so they are the one part that may need wa-slider-label.css.ts's
treatment — the library's API first, and only reach into the shadow
root if it has none.

Taking the second pass, scoped to **Settings**. `explore-view`'s search row and the second table's five one-off controls (`folders-menu-trigger`, `section-toggle`, `back-button`, `page-action-check-now`, the Downloads tabs) stay for a third pass unless this one lands small enough to carry them. Branch: `186-touch-targets-settings`. **The sweep found 120 controls below the floor on Settings, not 93, and `config-field` is 8 of them.** Re-measured on the device just now (TLP301, 424x439, main at `52038dc`, index build stopped and jobs empty), walking every shadow root with all eleven `config-section`s expanded: | control | size | count | |---|---|---| | `column-arrow-btn` | **16x14**, 18x14 | 36 | | `column-toggle` (checkbox) | **16x16** | 29 | | `shortcut-capture` button | 80x**25** | 26 | | download client checkbox | **16x16** | 8 | | `config-field` select | 335x**30** | 7 | | `wa-input` control | 204x**20**, 271x20 | 4 | | `wa-button` | 185x**21**, 163x21 | 2 | | `config-field` colour swatch | 33x33 | 1 | | `library-filter` select | 120x**32** | 1 | | scan actions (Add Library / Scan All / Full Rescan) | 108x30, 85x30, 107x30 | 3 | | library row `overflow-btn` | 31x31 | 1 | | `btn-ghost` | 133x**23** | 1 | So the 16x14 column arrows are the **smallest controls in the app** -- smaller than autotag's 15px section toggle, and there are 36 of them. The original table's `config-field` row was the *visible* offender on a collapsed page; the density lives behind the disclosures. **The density argument, measured rather than guessed, and it is smaller than I expected.** The rows are already close to the floor: `.column-item` is **335x36** and `.shortcut-row` is 335x37 — it is the controls *inside* them that are 14-25px, not the rows. So raising a row to 44 costs 8px, and the two column lists (10 and 19 items) grow by 232px in total. That is about half a screen of extra scroll on a 439px viewport, on a page that already scrolls, which is a real cost and not one worth trading a 16x14 target for. **That reframes the approach and makes it cheaper than the header's was.** Where a row is already ~36px and its control is 16px, the fix is to grow the control *into the row it already occupies* rather than to grow the row. Three shapes: 1. **The arrows take padding.** `.column-arrow-btn` has `background: none` and a transparent border, so padding is invisible until hover — the target grows and the visual weight does not, which is this issue's own Direction. 2. **The column toggle gets a label rather than a bigger box.** A native checkbox cannot grow its hit area without growing its paint, and a 44px checkbox is not what anyone wants. Wrapping the checkbox and its text in a `<label>` makes the row's text the target, which is ~250x44 — and `config-field`'s own comment already argues for exactly this ("a real label association also makes the label text a click target for the control, which is behaviour, not annotation"). 3. **The rest is min-height**, which is free: there is no overflow fit on this page, so the header pass's "only width is contested" rule does not bind here at all. The `wa-input` and `wa-button` rows are Web Awesome's own shadow roots, so they are the one part that may need `wa-slider-label.css.ts`'s treatment — the library's API first, and only reach into the shadow root if it has none.
Author
Collaborator

Second pass landed in PR #198, and it closes this out: Settings,
then the rest of the second table.

Settings was 120 controls, not 93. Swept on the device with all
eleven config-sections expanded — the first table's seven is what a
collapsed page reports, and the density is behind the disclosures.
config-field, which the Direction names, is eight of them.

control before after count
.column-arrow-btn 16x14 44x44 36
.column-toggle 16x16 label 70x44 29
shortcut-capture button 80x25 80x44 26
download format checkbox 16x16 label 57x44 8
config-field select 335x30 335x44 7
wa-input / wa-button 204x20 base 238x44 6
library-filter select 120x32 120x44 1
.overflow-btn 31x31 44x44 1
config-field toggle 34x19 44x44 3

The density argument, since the Direction asked for one. The rows
were already near the floor — .column-item 335x36, .shortcut-row
335x37 — and it is the controls inside them that were 14–25px. So
each control grows into the row it already occupies and the row goes
36 → 44: the two column lists went 373→447 and 690→850, +234px
over the page. Half a screen of extra scroll on a page that already
scrolls, against 36 targets of 16x14. Growing each control to its own
44px row would have cost four screens.

Three things worth carrying forward.

A native checkbox is targeted through its label. It cannot grow
its hit area without growing its paint, and a 44px checkbox is not
what anyone wants. .column-label is a real <label for> now, so the
column's name is the target — which is also a behaviour improvement,
and the argument config-field already makes for its own labels.

Two controls no sweep can see, and both are absent from this
issue's tables for that reason.
config-field's toggle has an
<input> that is opacity: 0; width: 0; height: 0, so a walk of
every input skips it as a zero-sized node — what a finger hits is
the <label>, at 34x19, smaller than anything in either table.
And shortcut-capture's reset button renders only for a shortcut
somebody has already rebound, so a sweep of a fresh install never
meets it.

back-button was six controls, not one. This issue names it in
artist-details, because that is the view the sweep opened; the same
declaration is byte-identical in six components. It is one stylesheet
now and a source sweep fails on a seventh copy — the failure to guard
against is not a size changing but somebody adding a detail view and
writing .back-button out again, which no device sweep would catch,
for exactly the reason this one did not.

Both open questions from the first pass held. Grow it everywhere
rather than phone-only, and no media query no tier renders. And the
"only width is contested" rule turned out not to bind at all here:
Settings runs no fit pass, so nothing needed the negative-margin
treatment except the toggle, and there for alignment rather than for
a fit.

One new instance of the same trap, recorded because it is the third
time.
The Downloads tabs were given their height as padding, so the
underline would stay against the label — 13 + 13 + 2 + the line box.
That is 44px on Arch and 43px in ubuntu:24.04, whose font gives
13px text a line box one pixel shorter. A height computed from a
font's line box is not a height you control. It has a min-block-size
under the padding now. Caught by the new test in CI rather than by a
person, which is the half of it that worked.

Verified: device sweep 120 → 42 on Settings, every one of the 42
accounted for (37 checkboxes whose labels are 70x44 and 57x44, four
wa-input inner inputs at 204x42 — the control measured inside its
own 1px border, part=base being 238x44 — and the skip link, already
ruled out as keyboard-only). Explore, Downloads, Autotag and
artist-details each report one, and it is the skip link.
26 new tests, all failing on main with the device's own numbers.
CI green including WebKit, which is the engine #195 needed and
could not run locally.

**Second pass landed** in PR #198, and it closes this out: Settings, then the rest of the second table. **Settings was 120 controls, not 93.** Swept on the device with all eleven `config-section`s expanded — the first table's seven is what a *collapsed* page reports, and the density is behind the disclosures. `config-field`, which the Direction names, is eight of them. | control | before | after | count | |---|---|---|---| | `.column-arrow-btn` | **16x14** | 44x44 | 36 | | `.column-toggle` | 16x16 | label 70x44 | 29 | | `shortcut-capture` button | 80x**25** | 80x44 | 26 | | download format checkbox | 16x16 | label 57x44 | 8 | | `config-field` select | 335x**30** | 335x44 | 7 | | `wa-input` / `wa-button` | 204x**20** | `base` 238x44 | 6 | | `library-filter` select | 120x**32** | 120x44 | 1 | | `.overflow-btn` | 31x31 | 44x44 | 1 | | `config-field` toggle | **34x19** | 44x44 | 3 | **The density argument, since the Direction asked for one.** The rows were already near the floor — `.column-item` 335x36, `.shortcut-row` 335x37 — and it is the controls *inside* them that were 14–25px. So each control grows into the row it already occupies and the row goes 36 → 44: the two column lists went 373→447 and 690→850, **+234px** over the page. Half a screen of extra scroll on a page that already scrolls, against 36 targets of 16x14. Growing each control to its own 44px row would have cost four screens. **Three things worth carrying forward.** **A native checkbox is targeted through its label.** It cannot grow its hit area without growing its paint, and a 44px checkbox is not what anyone wants. `.column-label` is a real `<label for>` now, so the column's name is the target — which is also a behaviour improvement, and the argument `config-field` already makes for its own labels. **Two controls no sweep can see, and both are absent from this issue's tables for that reason.** `config-field`'s toggle has an `<input>` that is `opacity: 0; width: 0; height: 0`, so a walk of every `input` skips it as a zero-sized node — what a finger hits is the `<label>`, at **34x19**, smaller than anything in either table. And `shortcut-capture`'s reset button renders only for a shortcut somebody has already rebound, so a sweep of a fresh install never meets it. **`back-button` was six controls, not one.** This issue names it in `artist-details`, because that is the view the sweep opened; the same declaration is byte-identical in six components. It is one stylesheet now and a source sweep fails on a seventh copy — the failure to guard against is not a size changing but somebody adding a detail view and writing `.back-button` out again, which no device sweep would catch, for exactly the reason this one did not. **Both open questions from the first pass held.** Grow it everywhere rather than phone-only, and no media query no tier renders. And the "only width is contested" rule turned out not to bind at all here: Settings runs no fit pass, so nothing needed the negative-margin treatment except the toggle, and there for *alignment* rather than for a fit. **One new instance of the same trap, recorded because it is the third time.** The Downloads tabs were given their height as padding, so the underline would stay against the label — 13 + 13 + 2 + the line box. That is 44px on Arch and **43px in ubuntu:24.04**, whose font gives 13px text a line box one pixel shorter. A height computed from a font's line box is not a height you control. It has a `min-block-size` under the padding now. Caught by the new test in CI rather than by a person, which is the half of it that worked. **Verified**: device sweep 120 → 42 on Settings, every one of the 42 accounted for (37 checkboxes whose labels are 70x44 and 57x44, four `wa-input` inner inputs at 204x42 — the control measured *inside* its own 1px border, `part=base` being 238x44 — and the skip link, already ruled out as keyboard-only). Explore, Downloads, Autotag and artist-details each report **one**, and it is the skip link. 26 new tests, all failing on `main` with the device's own numbers. CI green including **WebKit**, which is the engine #195 needed and could not run locally.
logan closed this issue 2026-08-22 03:22:16 +00:00
gitea-actions bot removed the
Status
In Progress
label 2026-08-22 03:22:28 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: yonlu/yellowjacket#186