Files
MichaelScottsman--LiquidAss…/theme/32-launcher.css
T
MichaelScottsman dc3071aac0 Smooth transitions: sidebar width morph, window glass materialize, launcher plate exit
- Frame menu: measured expanded width so Steam's width transition animates;
  reporter sends cover.morph end shape + start time, glassd morphs the glass
  on the same spring (70 ms native lead).
- Main window: glass-mode change reported from the mutation callback and the
  cover marked data-lgs-cover="pending" (no opaque CSS window); glassd springs
  covers in/out; daemon keeps lgs-native 1.5 s between modes.
- Launcher: the name plate dissolves in place, then the label fades back.
2026-10-08 23:04:35 -04:00

826 lines
37 KiB
CSS

/* Glass Shell, area "launcher" (C2b): the bar's "+" popup (surface barpopup).
PLAN 2.4 C2b, HA 4 and 5, 12.7. Wrapped as html.lgs-on { ... } by the bundler.
T1 (this file, CSS only): Steam's own "Launch Program" list (and the
"Add Desktop Window" list when SteamVR reports windows) becomes a grid of
4 columns of 72 x 96 popup px with no flow-children, so Steam infers grid
navigation from the computed style (D2 12). Steam's scan order is kept
(T1 cannot reorder focusable siblings). Each cell: a 52 px disc (white .11
and a top sheen) with the program icon at 34 px, and a 15 px Medium label.
The whole cell is the control: it carries the laser hover (::before) and the
gamepad focus (::after), never a scale (P-05). The full name shows as a plate
over the label on gamepad focus and on laser attention. Steam's own Liquid
Glass row stays a normal cell with a 14 px green "on" pip.
Labels (HA 4, PLAN 1.16 E-GRID (labels)): never a cut glyph. CSS alone cannot
tell a single word that is wider than the label from a name that needs a
third line, and Chromium draws no ellipsis across inside a line clamp, so the
CSS-only floor draws every label on one line ending in "...". With the
runtime (32-launcher.js, flag wp.c2b) each cell carries data-lgs-c2b-fit:
"whole" names wrap to two lines; T3 draws a longer name as two explicit
lines (the second in its own box), the second ending in "..." ("split");
"word" and "lines" stay one line. No -webkit-line-clamp: its own "..." overflows the label
when the last word and the "..." do not fit.
The "+" popup is the only list card with a header: Playspace has none, Quick
Access and tab menus use other components. So every rule is scoped with
LIST = %{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}).
T3 (device/rt/32-launcher.js, flag wp.c2b): .lgs-c2b-panel wraps Steam's
list (sorted A-Z; while the toggle row is on, the switch taken out of the
grid) and pins Steam's own Liquid Glass row below it, in .lgs-c2b-pin,
drawn as the toggle row.
ATT, the attended cell whose name plate shows (keyed on the input mode,
P-01, P-02): .gpfocus in gamepad mode; under the laser :hover after P3's
0.4 s attention step (.lgs-attend-400, cells tagged data-lgs-c2b-step) or,
without that, P3's 80 ms dwell; plain :hover with no input mode. Never on a
cell whose name shows whole (data-lgs-c2b-fit="whole"). The runtime
(32-launcher.js) tags it [data-lgs-c2b-att], its covered row-mates
[data-lgs-c2b-dim], each cell's column [data-lgs-c2b-col] and each label
box [data-lgs-c2b-lbl], so the plate rules are plain attribute selectors:
no previous-sibling :has(), no column pseudo-classes, no :root in :is() (perf.md
2.2 1: those made the popup open in ~1 s). Without the runtime no plate
shows (each label stays one line ending in "...").
Material: panel (PLAN 1.6), E3 edge from P4's hook, no border, no ring.
Sizes are popup px (m .83): 72 x 96 cells = 87 x 116 main px. */
/* the label's type, shared by the labels and the runtime's measuring probe */
& {
--lgs-c2b-label-font: 500 15px/18px var(--lgs-font);
}
/* ---------------------------------------------------------------------- */
/* 1. The card */
/* ---------------------------------------------------------------------- */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) {
width: 300px;
max-width: 300px;
max-height: 760px;
box-sizing: border-box;
padding: 12px 6px;
border: 0;
border-color: transparent;
border-radius: 40px;
background: var(--lgs-mat-panel-bg);
box-shadow: var(--lgs-mat-panel-shade);
--lgs-edge: panel;
/* a tall narrow slab: the key light sits further left so its top edge
shows the arc's fall-off (an arc with a gap, never a closed line:
WN 8.2 ratio <= .35) */
--lgs-light: 305deg;
color: var(--lgs-text-1);
/* materialize in place from the bar (HA 4): large glass (> 600 px), scale
from 1 + 12 / long side at the bottom centre, 250 ms. The long side is
the card's height (652-760), so its top edge starts 12 px out (P5's
swell, P-54 <= 16 px); HA's 1 + 12/300 moved the header 24.6 px */
--lgs-maxside: 680;
transform-origin: 50% 100%;
animation: lgs-mat-large-in var(--lgs-motion-mat-in, 250ms linear) backwards;
}
/* the content channel (HA 4: glass 0-92 %, content 35-100 %; motion.md
lgs-mat-content-in): the header and the grid sharpen in after the glass.
In T3 the panel is the glass and its children carry the channel (5.) */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) > * {
animation: lgs-mat-content-in var(--lgs-motion-mat-in, 250ms linear) backwards;
}
/* two lists (windows, then programs): Steam stacks two cards and lets them
share the 1024 px host; keep them one glass apart */
%{DashboardBarPopupSectionStack}:has(> %{DashboardBarPopupList} > %{DashboardBarPopupListHeader}) {
gap: 10px;
}
/* header: Steam's own node and string ("Launch Program"), 22 px Bold */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) > %{DashboardBarPopupListHeader} {
flex: none;
height: 52px;
box-sizing: border-box;
padding: 0 18px;
font: 700 22px/52px var(--lgs-font);
letter-spacing: var(--lgs-track-title, -.01em);
text-transform: none;
color: var(--lgs-text-1);
text-shadow: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* the scroll region: Steam's opaque fade bands become a 56 px mask fade */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListScrollRegion}::before,
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListScrollRegion}::after {
box-shadow: none;
background: transparent;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListScrollRegion}%{FadeTop} {
-webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 56px);
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListScrollRegion}%{FadeBottom} {
-webkit-mask-image: linear-gradient(to top, transparent 0, #000 56px);
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListScrollRegion}%{FadeTop}%{FadeBottom} {
-webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 56px, #000 calc(100% - 56px), transparent 100%);
}
/* ---------------------------------------------------------------------- */
/* 2. The grid: 4 columns of 72 x 96, no flow-children */
/* ---------------------------------------------------------------------- */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListScrollPanel} {
display: grid;
grid-template-columns: repeat(4, 72px);
grid-auto-rows: 96px;
justify-content: center;
gap: 0;
padding: 0;
--field-negative-horizontal-margin: 0px;
}
/* the cell: the whole 72 x 96 is the hit region and the control. Disc at
3-55, label from 60 (two 18 px lines end at 96, inside the cell) */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} {
width: 72px;
height: 96px;
min-width: 0;
box-sizing: border-box;
margin: 0 !important;
padding: 3px 1px 0 !important;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
border-radius: 22px;
background: transparent !important;
color: var(--lgs-text-1) !important;
animation: none !important;
/* the cell's light layers (z -1) paint above the glass, under the disc
and the label */
isolation: isolate;
/* the first frame of focus (P5's lgs-focus-in on the cell's light, the
disc's arc and the plate) starts at 75 %, not P4's 60 %: the focus look
here also moves the label into the plate, whose text lags; at 60 % the
whole cell measured 50-60 % of its final contrast (P-18 needs >= 60) */
--lgs-focus-first: .75;
}
/* the attended cell's own label is legible at once (no fade back from .22
when it was under the previous plate) */
&:not(.lgs-input-laser) %{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}.gpfocus [data-lgs-c2b-lbl],
&:not(.lgs-input-pad) %{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:hover [data-lgs-c2b-lbl] {
transition-duration: 0s;
}
/* Steam's active dot (::before, at left -6 px) and separator (::after, .5 px
under the row) become the cell's two light layers (HA 4, the mockup's
.hp-cell.is-hover / .is-focus; PLAN 1.4). Both lie inside the cell (the
dot no longer takes the neighbour's hits, the separator no longer makes the
last row scroll by 1 px) and take no pointer. */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}::before,
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}::after {
content: "" !important;
/* Steam hides its separator on the focused row (display: none) */
display: block !important;
position: absolute !important;
inset: 0 !important;
width: auto !important;
height: auto !important;
margin: 0 !important;
transform: none !important;
border: 0 !important;
border-radius: 22px !important;
z-index: -1;
opacity: 0;
pointer-events: none !important;
}
/* ::before, laser hover: P4's hover tokens, + white .08 and P3's light
spot at the pointer (.12; High Contrast zeroes it). Measured settled on
the cells that never show a plate, P-03 +10..+25 L (the plate after
0.4 s is attention, not the hover look). In on hover-in, out on fade */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}::before {
background:
radial-gradient(circle at var(--hx, 50%) var(--hy, 30%), rgb(255 255 255 / var(--lgs-hover-spot, .12)), transparent 60%),
rgb(255 255 255 / var(--lgs-hover-add, .08)) !important;
box-shadow: none !important;
transition: opacity var(--lgs-motion-fade, 441ms ease);
}
&:not(.lgs-input-pad) %{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:hover::before {
opacity: 1;
transition-duration: var(--lgs-d-hover-in, 294ms);
}
/* ::after, gamepad focus (PLAN 1.4): + white .32 uniform, a spot of .16 in
the upper third and the arc; on at once, entering through P5's
lgs-focus-in so the first frame shows --lgs-focus-first (60 %, P-18); out
on fade */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}::after {
background:
radial-gradient(ellipse 70% 45% at 50% 30%, rgb(255 255 255 / var(--lgs-focus-spot, .16)), transparent),
rgb(255 255 255 / var(--lgs-focus-add, .32)) !important;
box-shadow: inset 0 1.5px 1.5px -1px rgb(255 255 255 / var(--lgs-focus-arc, .55)) !important;
transition: opacity var(--lgs-motion-fade, 441ms ease);
}
&:not(.lgs-input-laser) %{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}.gpfocus::after {
opacity: 1;
transition-duration: 0s;
animation: lgs-focus-in var(--lgs-motion-hover-in, 294ms ease) backwards;
}
/* press: the laser's :active brightens the hover layer and spreads its spot;
the gamepad's A (P3's .lgs-pressed) adds .06 to the focus layer */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:active::before {
opacity: 1;
background:
radial-gradient(circle at var(--hx, 50%) var(--hy, 30%), rgb(255 255 255 / var(--lgs-press-spot, .22)), transparent 85%),
rgb(255 255 255 / calc(var(--lgs-hover-add, .08) + var(--lgs-press-add, .06))) !important;
transition-duration: var(--lgs-d-interactive, 210ms);
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}.lgs-pressed::after {
opacity: 1;
background:
radial-gradient(ellipse 80% 60% at 50% 40%, rgb(255 255 255 / var(--lgs-press-spot, .22)), transparent),
rgb(255 255 255 / calc(var(--lgs-focus-add, .32) + var(--lgs-press-add, .06))) !important;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{*GamepadDialogContent>FieldLeftColumn},
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{*GamepadDialogContent>FieldLabelRow} {
width: 100%;
min-width: 0;
margin: 0;
padding: 0;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{*GamepadDialogContent>FieldLabel} {
width: 100%;
min-width: 0;
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
margin: 0;
padding: 0;
color: var(--lgs-text-1);
text-shadow: none;
}
/* the disc (Steam's icon column): raised rest look, white .11 and a top
sheen (PLAN 1.4 rest, the mockup's .hp-disc) */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{*GamepadDialogContent>FieldIcon} {
position: relative;
flex: none;
width: 52px;
height: 52px;
box-sizing: border-box;
margin: 0;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background:
radial-gradient(90% 60% at 40% 0%, rgb(255 255 255 / .16), transparent 60%),
rgb(255 255 255 / .11);
box-shadow: inset 0 1.5px 1.5px -1px rgb(255 255 255 / .22);
color: var(--lgs-text-1);
isolation: isolate;
}
/* the disc's share of the focus (3.): its arc x 1.5 and a blurred glow, no
fill of its own (the cell carries the +.32); under the icon */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{*GamepadDialogContent>FieldIcon}::before {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
z-index: -1;
background: transparent;
box-shadow: inset 0 1.5px 1.5px -1px rgb(255 255 255 / var(--lgs-focus-arc, .55)),
0 0 calc(var(--lgs-white-glow-blur, 22px) * .6) 0 rgb(255 255 255 / .22);
opacity: 0;
pointer-events: none;
transition: opacity var(--lgs-motion-fade, 441ms ease);
}
&:not(.lgs-input-laser) %{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}.gpfocus %{*GamepadDialogContent>FieldIcon}::before {
opacity: 1;
transition-duration: 0s;
animation: lgs-focus-in var(--lgs-motion-hover-in, 294ms ease) backwards;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{PopupBody>Icon} {
width: 34px;
height: 34px;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{PopupBody>Icon} > :is(img, svg) {
width: 34px;
height: 34px;
object-fit: contain;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{PopupBody>Icon} > svg {
width: 28px;
height: 28px;
}
/* a program without an icon: a glyph (decorative; the label names it). The
runtime's data-lgs-c2b-glyph picks one by the name (HA 0.3); the CSS-only floor
draws a window */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{PopupBody>Icon}:empty::before {
content: "";
width: 26px;
height: 26px;
background: var(--lgs-text-2);
-webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26'><path fill='black' d='M5 4h16a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V7a3 3 0 0 1 3-3zm0 2.4a.6.6 0 0 0-.6.6v2h17.2V7a.6.6 0 0 0-.6-.6zm-.6 5v7.6c0 .33.27.6.6.6h16a.6.6 0 0 0 .6-.6v-7.6z'/></svg>") center / contain no-repeat;
pointer-events: none;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}[data-lgs-c2b-glyph="terminal"] %{PopupBody>Icon}:empty::before {
-webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26'><path fill='black' fill-rule='evenodd' d='M5 3h16a3 3 0 0 1 3 3v14a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3zm0 2.4a.6.6 0 0 0-.6.6v14c0 .33.27.6.6.6h16a.6.6 0 0 0 .6-.6V6a.6.6 0 0 0-.6-.6zm2.2 4.1 1.6-1.6 4.6 4.6-4.6 4.6-1.6-1.6 3-3zm6 6.1h5.6v2.2h-5.6z'/></svg>");
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}[data-lgs-c2b-glyph="gear"] %{PopupBody>Icon}:empty::before {
-webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26'><path fill='black' fill-rule='evenodd' d='M11.3 2h3.4l.6 2.9 1.9.8 2.5-1.6 2.4 2.4-1.6 2.5.8 1.9 2.9.6v3.4l-2.9.6-.8 1.9 1.6 2.5-2.4 2.4-2.5-1.6-1.9.8-.6 2.9h-3.4l-.6-2.9-1.9-.8-2.5 1.6-2.4-2.4 1.6-2.5-.8-1.9L2 14.7v-3.4l2.9-.6.8-1.9-1.6-2.5 2.4-2.4 2.5 1.6 1.9-.8zM13 9a4 4 0 1 0 0 8 4 4 0 0 0 0-8z'/></svg>");
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}[data-lgs-c2b-glyph="remote"] %{PopupBody>Icon}:empty::before {
-webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26'><path fill='black' fill-rule='evenodd' d='M4 4h13a2.5 2.5 0 0 1 2.5 2.5V9h-2.2V6.5a.3.3 0 0 0-.3-.3H4a.3.3 0 0 0-.3.3v9c0 .17.13.3.3.3h8.5V18H9.6v1.8H12V22H5.8v-2.2h1.6V18H4a2.5 2.5 0 0 1-2.5-2.5v-9A2.5 2.5 0 0 1 4 4zm12.6 9.6a1.3 1.3 0 1 1 0 2.6 1.3 1.3 0 0 1 0-2.6zm0-3.6a4.9 4.9 0 0 1 4.9 4.9h-2.1a2.8 2.8 0 0 0-2.8-2.8zm0-3.6a8.5 8.5 0 0 1 8.5 8.5h-2.1a6.4 6.4 0 0 0-6.4-6.4z'/></svg>");
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}[data-lgs-c2b-glyph="screens"] %{PopupBody>Icon}:empty::before {
-webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26'><path fill='black' fill-rule='evenodd' d='M3.5 3h12A2.5 2.5 0 0 1 18 5.5V7h-2.2V5.5a.3.3 0 0 0-.3-.3h-12a.3.3 0 0 0-.3.3v7c0 .17.13.3.3.3H6V15H3.5A2.5 2.5 0 0 1 1 12.5v-7A2.5 2.5 0 0 1 3.5 3zm7 6h12a2.5 2.5 0 0 1 2.5 2.5v7a2.5 2.5 0 0 1-2.5 2.5h-12A2.5 2.5 0 0 1 8 18.5v-7A2.5 2.5 0 0 1 10.5 9zm0 2.2a.3.3 0 0 0-.3.3v7c0 .17.13.3.3.3h12a.3.3 0 0 0 .3-.3v-7a.3.3 0 0 0-.3-.3z'/></svg>");
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}[data-lgs-c2b-glyph="display"] %{PopupBody>Icon}:empty::before {
-webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26'><path fill='black' fill-rule='evenodd' d='M4.5 3h17A2.5 2.5 0 0 1 24 5.5v11a2.5 2.5 0 0 1-2.5 2.5H14.2v2h3.3v2.2h-9V21h3.3v-2H4.5A2.5 2.5 0 0 1 2 16.5v-11A2.5 2.5 0 0 1 4.5 3zm0 2.2a.3.3 0 0 0-.3.3v11c0 .17.13.3.3.3h17a.3.3 0 0 0 .3-.3v-11a.3.3 0 0 0-.3-.3z'/></svg>");
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}[data-lgs-c2b-glyph="camera"] %{PopupBody>Icon}:empty::before {
-webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26'><path fill='black' fill-rule='evenodd' d='M9.6 4h6.8l1.6 2.4h3.5A2.5 2.5 0 0 1 24 8.9v10.6a2.5 2.5 0 0 1-2.5 2.5h-17A2.5 2.5 0 0 1 2 19.5V8.9a2.5 2.5 0 0 1 2.5-2.5H8zM13 9.4a4.6 4.6 0 1 0 0 9.2 4.6 4.6 0 0 0 0-9.2zm0 2.2a2.4 2.4 0 1 1 0 4.8 2.4 2.4 0 0 1 0-4.8z'/></svg>");
}
/* the label: 15 px Medium in 70 px, never a marquee, never a cut glyph.
It fades to .22 while a neighbour's plate lies over it (below), on fade */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{*GamepadDialogContent>FieldLabel} > :not(%{*GamepadDialogContent>FieldIcon}) {
width: 70px;
max-width: 70px;
min-width: 0;
max-height: 36px;
overflow: hidden;
font: var(--lgs-c2b-label-font);
letter-spacing: -.01em;
text-align: center;
color: var(--lgs-text-1);
text-shadow: none;
transition: opacity var(--lgs-motion-fade, 441ms ease);
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{Marquee>Container} {
width: 100%;
justify-content: center;
overflow: hidden;
-webkit-mask-image: none;
mask-image: none;
}
/* the CSS-only floor (and data-lgs-c2b-fit="word"): one line, "..." at its end */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{Marquee>Content} {
display: block;
-webkit-line-clamp: none;
width: 100%;
max-height: 36px;
overflow: hidden;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
hyphens: manual;
text-overflow: ellipsis;
text-align: center;
padding: 0;
animation: none !important;
}
/* measured by the runtime (32-launcher.js): a name that fits two lines by
wrapping wraps (breaking only between words). T3's two explicit lines: the
first line's words, then the second line in its own one-line box, which
wraps below them and ends in "..." when it does not fit; T3 narrows that
box where Chromium's cut would land just after a space */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}[data-lgs-c2b-fit="whole"] %{Marquee>Content},
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{Marquee>Content}:has(> .lgs-c2b-l2) {
white-space: normal;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{Marquee>Content} > .lgs-c2b-l2 {
display: inline-block;
max-width: var(--lgs-c2b-l2w, 70px);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
vertical-align: top;
}
/* the runtime's measuring probe (32-launcher.js): the label's font and
width, off screen, present only while it measures */
.lgs-c2b-probe {
position: fixed;
left: -4000px;
top: 0;
width: 70px;
box-sizing: content-box;
margin: 0;
padding: 0;
border: 0;
font: var(--lgs-c2b-label-font);
letter-spacing: -.01em;
text-transform: none;
white-space: normal;
overflow-wrap: normal;
word-break: normal;
hyphens: manual;
overflow: visible;
visibility: hidden;
pointer-events: none;
}
.lgs-c2b-probe.lgs-c2b-probe-w {
width: auto;
white-space: nowrap;
}
.lgs-c2b-probe.lgs-c2b-probe-plate {
font-weight: 600;
}
/* ---------------------------------------------------------------------- */
/* 3. High Contrast: focus is white .30 + the one allowed 2 px stroke */
/* (tokens.md); no spot, no glow */
/* ---------------------------------------------------------------------- */
@media (prefers-contrast: more) {
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}::after {
background: rgb(255 255 255 / .30) !important;
box-shadow: inset 0 0 0 2px rgb(255 255 255 / .70) !important;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem} %{*GamepadDialogContent>FieldIcon}::before {
box-shadow: none;
}
}
/* Steam's gamepad FocusRing: the cell carries the focus (one focused look) */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{FocusRingHint} {
opacity: 0;
}
/* ---------------------------------------------------------------------- */
/* 4. The full-name plate (HA 4): the attended cell's own label, lifted */
/* over its label row. It takes no pointer (the laser passes through to */
/* the cell under it), materializes in 250 ms, and stays inside the */
/* popup: left-aligned in column 1, right-aligned in column 4, centred */
/* in columns 2 and 3 unless that would cross x 6 or x 294 */
/* ---------------------------------------------------------------------- */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:is([data-lgs-c2b-att], [data-lgs-c2b-out]) [data-lgs-c2b-lbl] {
position: absolute;
z-index: 3;
top: 60px;
left: 36px;
translate: -50% 0;
width: max-content;
max-width: 288px;
height: 34px;
max-height: 34px;
box-sizing: border-box;
padding: 0 14px;
border-radius: 17px;
/* mid grey, not HA's 66/68/76: the plate lies over a third of the
attended cell, and P-14 (focus >= +40 L) and P-03 (hover +10..+25 L)
are judged on the whole cell; white on it stays 4.8:1 */
background: rgb(112 114 122 / .94);
box-shadow: inset 0 1.5px 1.5px -1px rgb(255 255 255 / .22), 0 6px 16px rgb(0 0 0 / .32);
font: 600 15px/34px var(--lgs-font);
white-space: nowrap;
pointer-events: none;
opacity: 1;
transition: none;
--lgs-maxside: 200;
/* under the laser it appears after 0.4 s of attention and materializes
(HA 11, materialize-in 250 ms) */
animation: lgs-mat-glass-in var(--lgs-motion-mat-in, 250ms linear) backwards;
}
/* on gamepad focus it is part of the focus look: on at once, entering
through lgs-focus-in like the cell's light, so the first frame shows 60 %
(P-18) */
&:not(.lgs-input-laser) %{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}.gpfocus[data-lgs-c2b-att] [data-lgs-c2b-lbl] {
animation: lgs-focus-in var(--lgs-motion-hover-in, 294ms ease) backwards;
}
/* the plate's text: the whole name on one line */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:is([data-lgs-c2b-att], [data-lgs-c2b-out]) %{Marquee>Content} {
display: block !important;
max-height: none;
white-space: nowrap;
-webkit-line-clamp: none;
text-overflow: ellipsis;
animation: none !important;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:is([data-lgs-c2b-att], [data-lgs-c2b-out]) %{Marquee>Content} > .lgs-c2b-l2 {
display: inline;
max-width: none;
overflow: visible;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:is([data-lgs-c2b-att], [data-lgs-c2b-out])[data-lgs-c2b-col="0"] [data-lgs-c2b-lbl] {
left: 0;
translate: none;
transform-origin: 0 50%;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:is([data-lgs-c2b-att], [data-lgs-c2b-out])[data-lgs-c2b-col="1"] [data-lgs-c2b-lbl] {
/* centred, but its left edge never before the grid's x 6 (the cell starts
at 78: 36 + 78 - 108 = 6) */
translate: max(-50%, -108px) 0;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:is([data-lgs-c2b-att], [data-lgs-c2b-out])[data-lgs-c2b-col="2"] [data-lgs-c2b-lbl] {
/* centred, but its right edge never past the grid's x 294 (the cell starts
at 150: 150 + 36 + 108 = 294) */
translate: min(-50%, calc(108px - 100%)) 0;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:is([data-lgs-c2b-att], [data-lgs-c2b-out])[data-lgs-c2b-col="3"] [data-lgs-c2b-lbl] {
left: auto;
right: 0;
translate: none;
transform-origin: 100% 50%;
}
/* the cell whose plate shows paints above its neighbours (z-index works on
grid items) */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:is([data-lgs-c2b-att], [data-lgs-c2b-out]) {
z-index: 2;
}
/* leaving (data-lgs-c2b-out, the runtime's OUT_MS after attention moves
on): the plate keeps its place and dissolves (opacity and its swell back,
on fade's curve) while the labels under it fade back in, instead of
vanishing in one frame. Then the cell's own label returns in place
(data-lgs-c2b-back, BACK_MS) with a short fade, so it never pops in */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}[data-lgs-c2b-out]:not([data-lgs-c2b-att]) [data-lgs-c2b-lbl] {
animation: lgs-plate-out var(--lgs-d-mat-in, 250ms) var(--lgs-ease-fade, ease) forwards;
}
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}[data-lgs-c2b-back]:not([data-lgs-c2b-att], [data-lgs-c2b-out]) [data-lgs-c2b-lbl] {
animation: lgs-fade-in var(--lgs-d-mat-in, 250ms) var(--lgs-ease-fade, ease) backwards;
}
/* the labels the plate lies over fade to .22 (HA 4, PLAN-2b-4; the
mockup's .is-under), on fade both ways. The runtime measures each plate
(data-lgs-c2b-under: l1-l3 to its left, r1-r3 to its right) and tags the
row-mates it covers while it shows (data-lgs-c2b-dim; every row-mate when
the plate was not measured) */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}[data-lgs-c2b-dim] [data-lgs-c2b-lbl] {
opacity: .22;
/* in with the plate's materialize (250 ms, done by 650 ms under the
laser: PLAN-2b-4's 800 ms), back on fade (441 ms, the label's own rule) */
transition: opacity var(--lgs-motion-mat-in, 250ms linear);
}
/* ---------------------------------------------------------------------- */
/* 5. Liquid Glass: Steam's own row, a normal cell with a green "on" pip */
/* ---------------------------------------------------------------------- */
%{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) %{DashboardBarPopupListItem}:is([data-lgs-row="liquid-glass"], :has(img[src*="zP9VZWZ7917z2Fx78vM6qqe7pHEinkTt9+rzKys9"])) %{*GamepadDialogContent>FieldIcon}::after {
content: "";
position: absolute;
top: 1px;
right: 1px;
width: 14px;
height: 14px;
border-radius: 50%;
background: var(--lgs-green);
pointer-events: none;
}
/* ---------------------------------------------------------------------- */
/* 6. T3 (flag wp.c2b): the panel and the pinned Liquid Glass toggle row */
/* ---------------------------------------------------------------------- */
/* the panel wraps Steam's list: it carries the glass; the list inside is
transparent and keeps its header and grid. (It also carries Steam's
DashboardBarPopupContents class for P6's cover; [data-lgs-c2b] keeps it
above 30-bar.css's "+"-card reset at equal specificity.) */
div.lgs-c2b-panel[data-lgs-c2b] {
position: relative;
display: flex;
flex-direction: column;
width: 300px;
max-height: 1000px;
box-sizing: border-box;
padding: 12px 6px;
border: 0;
border-radius: 40px;
overflow: hidden;
background: var(--lgs-mat-panel-bg);
box-shadow: var(--lgs-mat-panel-shade);
--lgs-edge: panel;
--lgs-light: 305deg;
color: var(--lgs-text-1);
--lgs-maxside: 726;
transform-origin: 50% 100%;
animation: lgs-mat-large-in var(--lgs-motion-mat-in, 250ms linear) backwards;
}
.lgs-c2b-panel %{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) {
flex: 0 1 auto;
/* the panel's 288 px content box, not the T1 card's 300 (the header was
300 wide, clipped by the panel: PLAN-2b-2, 20:24) */
width: auto;
max-width: none;
min-height: 0;
max-height: 760px;
padding: 0;
border-radius: 0;
background: transparent;
box-shadow: none;
--lgs-edge: none;
animation: none;
}
.lgs-c2b-panel %{DashboardBarPopupSectionStack} {
flex: 0 1 auto;
min-height: 0;
max-height: none;
}
/* the content channel in T3: the panel is the glass, its children (Steam's
list or stack, the toggle row) sharpen in after it; the list's own
children ride their parent (no second channel) */
div.lgs-c2b-panel[data-lgs-c2b] > *,
div.lgs-c2b-panel[data-lgs-c2b] > %{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) {
animation: lgs-mat-content-in var(--lgs-motion-mat-in, 250ms linear) backwards;
}
.lgs-c2b-panel %{DashboardBarPopupList}:has(> %{DashboardBarPopupListHeader}) > * {
animation: none;
}
/* the pinned Liquid Glass row (HA 4): Steam's own row, in .lgs-c2b-pin, drawn
as a 64 tall recessed platter outside the grid's focus group: its 44 disc
with the real icon, "Liquid Glass" 19 Semibold, "Glass Shell is on" 15
(the wrapper's data-lgs-sub, English only, PLAN 1.15) and a switch shown
on (decorative: the whole row is the control). A single-control row, so
the row carries the light. Radius 32: P-83's capsule (>= .45 x 64) over
HA's 28 */
div.lgs-c2b-panel[data-lgs-c2b] > .lgs-c2b-pin {
position: relative;
flex: none;
margin-top: 10px;
}
.lgs-c2b-pin > %{DashboardBarPopupListItem} {
position: relative;
display: flex;
align-items: center;
width: auto;
height: 64px !important;
min-height: 0 !important;
max-height: 64px;
box-sizing: border-box;
margin: 0 !important;
padding: 0 82px 0 10px !important;
border-radius: 32px;
background: rgb(0 0 0 / .22) !important;
box-shadow: inset 0 2px 5px rgb(0 0 0 / .22) !important;
color: var(--lgs-text-1) !important;
cursor: pointer;
isolation: isolate;
animation: none !important;
transition: background-color var(--lgs-motion-fade, 441ms ease), box-shadow var(--lgs-motion-fade, 441ms ease);
}
.lgs-c2b-pin > %{DashboardBarPopupListItem} :is(%{*GamepadDialogContent>FieldLabelRow}, %{*GamepadDialogContent>FieldLeftColumn}) {
width: 100%;
min-width: 0;
margin: 0;
padding: 0;
}
.lgs-c2b-pin > %{DashboardBarPopupListItem} %{*GamepadDialogContent>FieldLabel} {
display: flex;
flex-direction: row;
align-items: center;
gap: 12px;
min-width: 0;
margin: 0;
padding: 0;
color: var(--lgs-text-1);
text-shadow: none;
}
.lgs-c2b-pin > %{DashboardBarPopupListItem} %{*GamepadDialogContent>FieldIcon} {
flex: none;
width: 44px;
height: 44px;
margin: 0;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: rgb(255 255 255 / .11);
}
.lgs-c2b-pin > %{DashboardBarPopupListItem} %{PopupBody>Icon},
.lgs-c2b-pin > %{DashboardBarPopupListItem} %{PopupBody>Icon} > :is(img, svg) {
width: 30px;
height: 30px;
margin: 0;
object-fit: contain;
}
/* the title: Steam's own label, lifted to the upper half of the row */
.lgs-c2b-pin > %{DashboardBarPopupListItem} %{*GamepadDialogContent>FieldLabel} > :not(%{*GamepadDialogContent>FieldIcon}) {
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
font: 600 19px/22px var(--lgs-font);
color: var(--lgs-text-1);
text-align: start;
}
.lgs-c2b-pin[data-lgs-sub] > %{DashboardBarPopupListItem} %{*GamepadDialogContent>FieldLabel} > :not(%{*GamepadDialogContent>FieldIcon}) {
translate: 0 -10px;
}
.lgs-c2b-pin > %{DashboardBarPopupListItem} %{Marquee>Container} {
overflow: hidden;
-webkit-mask-image: none;
mask-image: none;
}
.lgs-c2b-pin > %{DashboardBarPopupListItem} %{Marquee>Content} {
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
animation: none !important;
}
/* the subtitle, drawn by the wrapper under the title (no text in Steam's row) */
.lgs-c2b-pin[data-lgs-sub]::after {
content: attr(data-lgs-sub);
position: absolute;
left: 66px;
right: 82px;
top: 34px;
font: 500 15px/18px var(--lgs-font);
color: var(--lgs-text-2);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
pointer-events: none;
}
/* the switch, shown on: a 55 x 33 green capsule and its white knob, one
decorative layer over the row's right end; after a live press runs the
switch (data-lgs-busy) it shows off */
.lgs-c2b-pin::before {
content: "";
position: absolute;
z-index: 1;
right: 14px;
top: 15.5px;
width: 55px;
height: 33px;
border-radius: 999px;
background:
radial-gradient(circle at 38.5px 50%, #fff 13.5px, rgb(0 0 0 / .18) 14px, transparent 16px),
var(--lgs-toggle-on, rgb(48 209 88));
pointer-events: none;
transition: background-color var(--lgs-motion-fade, 441ms ease);
}
.lgs-c2b-pin[data-lgs-busy]::before {
background:
radial-gradient(circle at 16.5px 50%, #fff 13.5px, rgb(0 0 0 / .18) 14px, transparent 16px),
rgb(255 255 255 / .22);
}
/* Steam's separator and active dot are not drawn on the pinned row; its
::before is the row's focus layer: + white .32, the spot and the arc, on at
once through lgs-focus-in (first frame 60 %, P-18), out on fade */
.lgs-c2b-pin > %{DashboardBarPopupListItem}::after {
content: none !important;
}
.lgs-c2b-pin > %{DashboardBarPopupListItem}::before {
content: "" !important;
display: block !important;
position: absolute !important;
inset: 0 !important;
width: auto !important;
height: auto !important;
margin: 0 !important;
transform: none !important;
border: 0 !important;
border-radius: inherit !important;
z-index: -1;
background:
radial-gradient(ellipse 60% 70% at 50% 30%, rgb(255 255 255 / var(--lgs-focus-spot, .16)), transparent),
rgb(255 255 255 / var(--lgs-focus-add, .32)) !important;
box-shadow: inset 0 1.5px 1.5px -1px rgb(255 255 255 / var(--lgs-focus-arc, .55)) !important;
opacity: 0;
pointer-events: none !important;
transition: opacity var(--lgs-motion-fade, 441ms ease);
}
.lgs-c2b-pin %{FocusRingHint} {
opacity: 0;
}
/* row states: laser hover warms it, gamepad focus lights it (the recess
clears at once), press adds .06 */
&:not(.lgs-input-pad) .lgs-c2b-pin > %{DashboardBarPopupListItem}:hover {
background: rgb(255 255 255 / var(--lgs-hover-add, .08)) !important;
box-shadow: none !important;
transition-duration: var(--lgs-d-hover-in, 294ms);
}
&:not(.lgs-input-laser) .lgs-c2b-pin > %{DashboardBarPopupListItem}.gpfocus {
background: transparent !important;
box-shadow: none !important;
transition-duration: 0s;
}
&:not(.lgs-input-laser) .lgs-c2b-pin > %{DashboardBarPopupListItem}.gpfocus::before,
.lgs-c2b-pin > %{DashboardBarPopupListItem}.lgs-pressed::before {
opacity: 1;
transition-duration: 0s;
}
&:not(.lgs-input-laser) .lgs-c2b-pin > %{DashboardBarPopupListItem}.gpfocus::before {
animation: lgs-focus-in var(--lgs-motion-hover-in, 294ms ease) backwards;
}
.lgs-c2b-pin > %{DashboardBarPopupListItem}:active {
background: rgb(255 255 255 / calc(var(--lgs-hover-add, .08) + var(--lgs-press-add, .06))) !important;
box-shadow: none !important;
transition-duration: var(--lgs-d-interactive, 210ms);
}
@media (prefers-contrast: more) {
.lgs-c2b-pin > %{DashboardBarPopupListItem}::before {
background: rgb(255 255 255 / .30) !important;
box-shadow: inset 0 0 0 2px rgb(255 255 255 / .70) !important;
}
}