Files
yellowjacket/frontend/index.css
T
logan 4efd17d477
Build & publish Arch package / arch-package (push) Successful in 2m1s
CI / check (push) Successful in 2m33s
Search index maintenance / maintain-index (push) Successful in 6s
CI / e2e (push) Canceled after 2m3s
fix(a11y): let the shell scroll sideways when it does not fit
a11y.21 (WCAG 1.4.10), measured rather than taken as filed. The
finding's mechanism is vertical — "the 4em bars grow while the viewport
does not, and anything that no longer fits is clipped with no
scrollbar" — and that is not what happens. The middle row is `1fr` and
absorbs the growth exactly: at 200% text on 800x600 the bars go 64px to
128px and the panel 472px to 344px, with the footer still landing on
600. Nothing is clipped vertically, and Settings stays reachable
because the sidebar scrolls (007 phase 5).

What is real is the axis the finding does not mention. At 200% text the
shell is 1014px wide in an 800px viewport, and at 320px — 400% page
zoom of 1280, the width 1.4.10 names — it is 784px, so 464px of the
app including the job indicator and the queue button sat behind
`overflow: hidden` with no way to reach it.

So the horizontal axis scrolls and the vertical one stays fixed, which
also keeps the transport where a desktop player's transport belongs. At
every size this app promises there is no overflow on either axis and no
scrollbar appears, which the three viewport cases assert.

The first version of the spec passed on the broken build: `overflow:
hidden` still permits programmatic scrolling, so `scrollLeft = 9999`
proves nothing. It is a wheel gesture now.
2026-08-13 02:22:49 -04:00

244 lines
6.4 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
*,
*::before,
*::after {
-webkit-user-select: none;
user-select: none;
}
html {
height: 100%;
}
body {
background-color: var(--yj-bg-base, black);
color: var(--yj-text-primary, white);
margin: 0;
height: 100vh;
display: grid;
grid-template: "top-bar top-bar" 4em "sidebar main-panel" 1fr "bottom-bar bottom-bar" 4em / auto 1fr;
/* a11y.21 (WCAG 1.4.10), measured rather than taken as filed.
The finding's mechanism is vertical — "the 4em bars grow while
the viewport does not, and anything that no longer fits is
clipped with no scrollbar" — and that is not what happens. The
middle row is `1fr`, so it absorbs the bars exactly: at 200%
text on an 800×600 window the bars go 64px → 128px and the main
panel goes 472px → 344px, with the footer's bottom still landing
on 600. Nothing is clipped, and Settings stays reachable because
the sidebar scrolls (007 phase 5).
What is real is the other axis, which the finding does not
mention: at 200% text the shell is 1014px wide in an 800px
viewport, and at 320px (400% page zoom of 1280) it is 611px —
291px of the app unreachable behind `overflow: hidden`. So the
horizontal axis scrolls and the vertical one stays fixed, which
is also what keeps the transport bar where a desktop player's
transport bar belongs. At every size this app promises
(800×600 and up, default text) there is no overflow on either
axis and no scrollbar appears. */
overflow-x: auto;
overflow-y: hidden;
}
p {
margin: 0;
/* I want to set paragraph margins myself */
}
/* a11y.30. Out of flow in both states, because `body` is a grid with
named areas and an in-flow extra child is auto-placed into one of
them — the link would silently take a row from the shell. It is not
`display: none`: a skip link that is not focusable is not a skip
link. */
.skip-link {
position: absolute;
left: -9999px;
top: 0;
z-index: 100;
padding: 0.5em 1em;
background-color: var(--yj-accent);
color: var(--yj-accent-fg);
font-weight: 600;
text-decoration: none;
border-radius: 0 0 4px 0;
}
.skip-link:focus {
left: 0;
}
/* The target of that link, so it can take focus at all. `main` is not
focusable by default, and a fragment link to an unfocusable element
moves the scroll and leaves the tab sequence exactly where it was —
which is the whole thing the link exists to change. */
.main-panel:focus {
outline: none;
}
.top-bar {
grid-area: top-bar;
height: 100%;
padding-left: 2em;
padding-right: 2em;
display: flex;
justify-content: space-between;
align-items: center;
background-color: var(--yj-bg-elevated, #343a40);
gap: 1em;
}
.top-bar search-bar {
flex: 0 1 320px;
}
ul {
list-style-type: none;
}
.title {
font-size: 1.5em;
/* Both margins, not just the bottom one. The pair is flex-centred
in a 4em bar and the UA gives an h1 a 0.67em top margin, so the
hgroup measured 67px inside 64 and the subtitle's descenders were
clipped by the bar. That was pre-existing; a11y.29 made it
visible by taking the h3's bottom margin away with it, which
shortened the block and moved the whole pair down into the clip.
This is the state that fix landed in. */
margin-block: 0;
}
.subtitle {
font-size: 0.8em;
margin-top: 0;
}
/* The same breakpoint the sidebar collapses at (AUTO_COLLAPSE_VIEWPORT
in app-sidebar.ts). The subtitle wrapped to two lines below ~780 px,
which made the title block 98 px tall inside a 4em bar and pushed it
down into the nav (H-11). */
@media (max-width: 899px) {
.subtitle {
display: none;
}
}
body div.sidebar {
grid-area: sidebar;
background-color: var(--yj-bg-surface, #212529);
overflow: hidden;
contain: layout style paint;
}
.bottom-bar {
grid-area: bottom-bar;
padding: 0.25em;
background-color: var(--yj-bg-elevated, #343a40);
display: grid;
grid-template-columns: var(--now-playing-width, 320px) 1fr auto;
align-items: center;
contain: layout style;
#now-playing-info {
justify-self: start;
display: flex;
min-width: 0;
overflow: hidden;
#album-art {
width: 3.5em;
min-width: 3.5em;
height: 3.5em;
min-height: 3.5em;
border-radius: 0.25em;
background-color: var(--yj-accent, #ffd43b);
}
#track-info {
display: flex;
margin-left: 1em;
flex-direction: column;
font-size: 0.75em;
justify-content: center;
text-wrap-mode: nowrap;
overflow: hidden;
p {
overflow: hidden;
text-overflow: ellipsis;
}
}
}
now-playing {
overflow: hidden;
}
audio-player {
margin: 0.5em 1em;
}
#queue-button {
justify-self: end;
background: none;
border: none;
color: inherit;
cursor: pointer;
padding: 8px;
display: flex;
align-items: center;
}
#queue-button:hover {
color: var(--yj-accent, #ffd43b);
}
#queue-button.drag-over {
color: var(--yj-accent, #ffd43b);
outline: 2px dashed var(--yj-accent, #ffd43b);
outline-offset: -2px;
border-radius: 4px;
}
}
.content-area {
grid-area: main-panel;
display: flex;
overflow: hidden;
contain: layout style;
}
.main-panel {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
background-color: var(--yj-bg-surface, #212529);
overflow: hidden;
contain: layout style paint;
}
.main-panel > * {
flex: 1;
min-height: 0;
box-sizing: border-box;
contain: layout style paint;
}
/* Hidden cached views: use visibility+size collapse instead of
display:none so scroll containers preserve their scrollTop.
display:none discards scroll state in WebKitGTK. */
.main-panel > .view-hidden {
visibility: hidden !important;
flex: 0 0 0px !important;
min-height: 0 !important;
max-height: 0 !important;
height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
pointer-events: none !important;
contain: strict !important;
}