Files
MichaelScottsman--LiquidAss…/theme/05-native.css
T
MichaelScottsman 8862d7174a Native plates are glassd's from their first frame; Settings tick reads no layout
- reporter: <html data-lgs-plates> on managed native windows; a plate glassd has not drawn for 1.5 s gets
  data-lgs-plate-css (CSS plate glass back). The theme drops CSS plate glass on every other plate at once,
  instead of after the ack: no CSS-then-native swap, no fill/shadow transition on each Home disc.
- settings: scrolled state from the scroll listener, the hero title measured in rAF (the 300 ms tick
  forced the page's layout mid-transition)
2026-10-09 01:29:34 -04:00

316 lines
17 KiB
CSS

/* Glass Shell, native mode: html.lgs-on.lgs-native (docs/NATIVE.md).
The daemon sets lgs-native on a window once glassd draws glass for it.
Then glassd paints the room-refracting glass behind Steam's texture, so
the CSS stops painting that glass itself. Nothing else changes: content,
states, focus and colours stay exactly as the theme defines them.
Scope is per element, never per window. device/lgs_layers.js marks
[data-lgs-cover] an element whose rounded box glassd fills with the
surface's glass (main window root, each bar segment,
each popup card, frame menu, floating footer), and
[data-lgs-pop] an element that pops out in depth over its own
glassd slab ("self", or "before"/"after" when the
capsule is that pseudo-element),
[data-lgs-plate-ack] a [data-lgs-plate] element glassd draws as a plate
(Phase 2); in a window the reporter manages
(<html data-lgs-plates>) every plate is glassd's from
its first frame, and only [data-lgs-plate-css] (glassd
has not drawn it within 1.5 s) paints CSS plate glass,
and
[data-lgs-noslab] the popped parts whose slab is "none" (glass in-page),
only while the daemon acknowledges that the compositor shows that cover
or slab (__LGS_LAYERS.ack), and removes the mark as soon as it does not.
So an element whose glass is not (or not yet) on screen keeps its CSS
glass: a menu that just opened is thick CSS glass until its slab shows.
- Covers drop their glass background and rim. glassd draws both, from the
real room. The scroll-edge bands under tab rows were tuned to blend into
the CSS window tint; over glassd's glass they use a neutral scrim.
- Popped glass drops its tint (the light glass layer and the sheen) and its
rim; the slab supplies them. It keeps its backdrop-filter, which refracts
the in-page content behind it, and its outer shadow, which now falls on
the window below. Header, tab, footer and arrow capsules keep Apple's
dimming layer (--lgs-scrim) so white labels stay legible over bright art
scrolling under them.
- Tinted controls (Play), fills and focus rings are content: unchanged.
Done with tokens wherever the rule paints through one. Custom properties
resolve where they are used, so they are overridden on the element (or
the ::before/::after) that paints.
High Contrast keeps the CSS glass, so the tokens can keep it opaque.
Wrapped as html.lgs-on { ... } by the injector. */
@media not (prefers-contrast: more) {
/* ------------------------------------------------------------------ */
/* 1. Covers: the surface's own glass */
/* ------------------------------------------------------------------ */
/* main window: window glass and its rim (20-shell.css). The ::after is
the window's top sheen (white .08 -> 0) and dark inner edge, painted
with literal colours (C1a): glassd's window glass has its own */
&.lgs-native %{BasicUiRoot}[data-lgs-cover] {
background: transparent;
}
&.lgs-native %{BasicUiRoot}[data-lgs-cover]::after {
background: none;
box-shadow: none;
}
/* scroll-edge bands under the tab rows (search, library, home, game
page, achievements: 20-shell.css, 40-library.css, 50-appdetails.css)
and the sticky sort-section band: their gradient starts at the CSS
window tint, which over glassd's room glass reads as a second, darker
window. A neutral scrim keeps the fade; mask and blur are unchanged. */
&.lgs-native %{BasicUiRoot}[data-lgs-cover] %{TabHeaderRowWrapper}::before,
&.lgs-native %{BasicUiRoot}[data-lgs-cover] %{AppGridSectionHeader}::after {
--lgs-window-bg: var(--lgs-scrim);
}
/* bar segments (each is its own cover shape), bar popup cards (+ list,
Playspace, Streaming; two stacked cards are two shapes), Quick Access,
tab menus, the frame menu and the floating footer: panel glass
(30-bar.css, 35-hud.css) */
&.lgs-native %{BarSurface}[data-lgs-cover],
&.lgs-native :is(%{DashboardBarPopupContents}, %{QuickAccessMenu}, %{DashboardMenu})[data-lgs-cover],
&.lgs-native #Footer%{BasicFooter}%{FloatingVRFooter}[data-lgs-cover] {
--lgs-panel-sheen: linear-gradient(transparent, transparent);
--lgs-panel-bg: transparent;
--lgs-panel-rim: 0 0 0 0 transparent;
}
/* ------------------------------------------------------------------ */
/* 2. Popped capsules drawn by a ::before / ::after */
/* ------------------------------------------------------------------ */
/* header Back (::before) and search (#header::after): their faces are
defined on #header (20-shell.css), so they are redefined on the
pseudo-element that paints them */
&.lgs-native %{BackContainer}[data-lgs-pop~="before"]::before,
&.lgs-native #header%{Profile>Header}[data-lgs-pop~="after"]::after {
/* Phase 2 (C1a): the Back capsule is a raised control (P4's raised
fill: white .10 + a .06 sheen, and an inset top highlight). Popped,
glassd's slab is its glass: the scrim stays, the light and the
highlight (a second edge over the slab's crescent) go */
--lgs-raised-bg: linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
--lgs-raised-shadow: 0 0 0 0 transparent;
--lgs-capsule-face: linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
--lgs-capsule-hover: linear-gradient(var(--lgs-hover-fill), var(--lgs-hover-fill)),
linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
--lgs-capsule-filled: linear-gradient(var(--lgs-fill-2), var(--lgs-fill-2)),
linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
--lgs-capsule-focus: linear-gradient(var(--lgs-focus-fill), var(--lgs-focus-fill)),
linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
--lgs-capsule-pressed: linear-gradient(var(--lgs-pressed-fill), var(--lgs-pressed-fill)),
linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
--lgs-glass-rim: 0 0 0 0 transparent;
}
/* footer legend (#Footer::after, 20-shell.css) and the segmented tab
rows (TabHeaderRowWrapper::after: library and home in 40-library.css,
search in 20-shell.css, game pages in 50-appdetails.css) */
&.lgs-native #Footer%{BasicFooter}[data-lgs-pop~="after"]::after,
&.lgs-native %{TabHeaderRowWrapper}[data-lgs-pop~="after"]::after {
--lgs-panel-sheen: linear-gradient(transparent, transparent);
--lgs-glass-bg: transparent;
--lgs-glass-rim: 0 0 0 0 transparent;
--lgs-lib-glass-face: linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
}
/* Phase 2 (C1a, 20-shell.css §3): the ornament capsule paints its liquid
tint with literal colours (a white .12 -> .03 sheen over a dark tint
that deepens below the glass edge). Popped, the slab supplies tint and
sheen: the scrim stays, so the labels keep Apple's dimming layer. Its
inner shade goes through --lgs-mat-liquid-shade (section 4), its drop
shadow and blur stay. The quiet legend (not glass) keeps its own band:
C1a's quiet rule is more specific. */
&.lgs-native %{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-pop~="after"]:not([data-lgs-noslab~="after"])::after {
background: linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
}
/* ... and its E3 arc: C1a sets --lgs-edge: liquid on #Footer with an id
selector, which outweighs section 4's generic host rule */
&.lgs-native %{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-pop~="after"]:not([data-lgs-noslab~="after"]) {
--lgs-edge: none;
}
/* ------------------------------------------------------------------ */
/* 3. Popped elements that paint their own glass */
/* ------------------------------------------------------------------ */
/* round tab-row arrows and the laser Sort & Filter capsule
(40-library.css): light glass face over the scrim */
&.lgs-native %{TabHeaderRowWrapper} %{Arrows}[data-lgs-pop~="self"],
&.lgs-native %{SortAndFilterContainer}[data-lgs-pop~="self"] {
/* Phase 2 (C2c, C2a): the arrows are raised controls (P4's raised fill
with its .06 sheen and inset highlight): popped, the scrim stays */
--lgs-raised-bg: linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
--lgs-raised-shadow: 0 0 0 0 transparent;
--lgs-panel-sheen: linear-gradient(transparent, transparent);
--lgs-glass-rim: 0 0 0 0 transparent;
--lgs-lib-glass-face: linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
--lgs-lib-glass-hover: linear-gradient(var(--lgs-hover-fill), var(--lgs-hover-fill)),
linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
--lgs-lib-glass-focus: linear-gradient(var(--lgs-focus-fill), var(--lgs-focus-fill)),
linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
}
/* Home's arrows (C2a, 41-home.css) draw their top highlight with a literal
inset shadow, also !important under hover and focus: popped, it would
be a second edge inside the slab's crescent (one more attribute keeps
this rule above C2a's state rules) */
&.lgs-native %{RecentSection} ~ %{TabbedContent} %{TabHeaderRowWrapper} %{Arrows}[data-lgs-pop~="self"]:not([data-lgs-noslab~="self"]) {
box-shadow: none !important;
}
/* game page Play capsule and its menu button (50-appdetails.css): the
tint is content and stays; the control rim (a white .18 inset line at
the top) and the segments' sheen would draw a second edge and light
inside the slab's own crescent, so they go */
&.lgs-native %{PlayButtonContainer}[data-lgs-pop~="self"],
&.lgs-native %{PartnerEventOverlayContainer>AppDetailsMain} %{Container>MenuButton}[data-lgs-pop~="self"] {
--lgs-control-rim: 0 0 0 0 transparent;
--lgs-panel-sheen: linear-gradient(transparent, transparent);
}
/* menus and sheets: thick glass (10-primitives.css, 40-library.css).
The thick slab supplies tint and frost. */
&.lgs-native %{*BasicContextMenuModal>contextMenuContents}[data-lgs-pop~="self"],
&.lgs-native %{*GamepadDialogContent>ModalPosition} > [data-lgs-pop~="self"],
&.lgs-native %{DialogWrapper>CompatFilterDialog}[data-lgs-pop~="self"] {
--lgs-panel-sheen: linear-gradient(transparent, transparent);
--lgs-thick-bg: transparent;
--lgs-glass-rim: 0 0 0 0 transparent;
}
/* ------------------------------------------------------------------ */
/* 4. Phase 2 materials (contracts/reporter.md 7-8, tokens.md 1.7) */
/* ------------------------------------------------------------------ */
/* Phase 2 code paints glass through the --lgs-mat-* tokens and draws
its E3 edge through the --lgs-edge hook (03-material.css). Where the
daemon acknowledged glassd's glass, those tokens are zeroed on the
element that is glass, so whichever element or pseudo-element of it
paints the material gets transparent, and the CSS edge goes (glassd
draws GM v2's crescent). In-page refraction (--lgs-mat-*-blur) stays.
Areas key anything more specific on the same attributes. */
/* main window cover (window, window-full, hero): the window material */
&.lgs-native %{BasicUiRoot}[data-lgs-cover] {
--lgs-mat-window-bg: transparent;
--lgs-mat-window-shade: 0 0 0 0 transparent;
--lgs-edge: none;
}
/* every other cover is the glass card of its quad: bar segments, popup
cards, Quick Access, tab and frame menus, the floating footer, toasts,
the volume HUD, tooltips. Nothing inside a card is glass (VP P-45),
so zeroing the card's material tokens reaches only the card. */
&.lgs-native :not(%{BasicUiRoot})[data-lgs-cover] {
--lgs-mat-panel-bg: transparent;
--lgs-mat-panel-shade: 0 0 0 0 transparent;
--lgs-mat-liquid-bg: transparent;
--lgs-mat-liquid-room-bg: transparent;
--lgs-mat-liquid-shade: 0 0 0 0 transparent;
--lgs-mat-thick-bg: transparent;
--lgs-mat-thick-shade: 0 0 0 0 transparent;
--lgs-panel-bg: transparent;
--lgs-panel-sheen: linear-gradient(transparent, transparent);
--lgs-panel-rim: 0 0 0 0 transparent;
--lgs-edge: none;
}
/* plates (data-lgs-plate): glassd draws the plate itself, opaque, at the
cover's depth, and the base mosaic shows Steam's content in front of
it. The plate element drops its fill, shading and blur; its content,
labels and focus (areas mark focus glows !important, as Steam's focus
animations already require) stay. --lgs-plate-bg is the variable areas
paint a plate through. */
&.lgs-native [data-lgs-plate]:is([data-lgs-plate-ack], :root[data-lgs-plates] [data-lgs-plate]:not([data-lgs-plate-css])) {
background: transparent;
box-shadow: none;
backdrop-filter: none;
--lgs-plate-bg: transparent;
--lgs-mat-plate-bg: transparent;
/* a plate painted with a material token (C1c's flat thick modals):
the plate is opaque glassd glass, so no in-page frost either (a blur
in Steam's texture would cover the plate through the base mosaic) */
--lgs-mat-window-bg: transparent;
--lgs-mat-panel-bg: transparent;
--lgs-mat-liquid-bg: transparent;
--lgs-mat-liquid-room-bg: transparent;
--lgs-mat-thick-bg: transparent;
--lgs-mat-window-shade: 0 0 0 0 transparent;
--lgs-mat-panel-shade: 0 0 0 0 transparent;
--lgs-mat-liquid-shade: 0 0 0 0 transparent;
--lgs-mat-thick-shade: 0 0 0 0 transparent;
--lgs-mat-liquid-blur: none;
--lgs-mat-thick-blur: none;
--lgs-edge: none;
}
/* pops: glassd's slab under the crop supplies tint, frost and edge; the
part keeps its backdrop-filter (refraction of the page behind it). A
part whose slab is "none" (data-lgs-noslab: glassd draws only the hole,
the glass stays in-page, GP's cluster over art) keeps its CSS glass. */
&.lgs-native [data-lgs-pop~="self"]:not([data-lgs-noslab~="self"]),
&.lgs-native [data-lgs-pop~="before"]:not([data-lgs-noslab~="before"])::before,
&.lgs-native [data-lgs-pop~="after"]:not([data-lgs-noslab~="after"])::after {
--lgs-mat-liquid-bg: transparent;
--lgs-mat-liquid-room-bg: transparent;
--lgs-mat-liquid-shade: 0 0 0 0 transparent;
--lgs-mat-panel-bg: transparent;
--lgs-mat-panel-shade: 0 0 0 0 transparent;
--lgs-mat-thick-bg: transparent;
--lgs-mat-thick-shade: 0 0 0 0 transparent;
}
&.lgs-native [data-lgs-pop~="self"]:not([data-lgs-noslab~="self"]) {
--lgs-edge: none;
}
/* a popped ::before / ::after capsule: P4's E3 arc of that capsule is
drawn on its host's ::before by the host's --lgs-edge (the bottom
ornament: #Footer --lgs-edge: liquid, capsule on ::after). The slab
draws the crescent, so the host's hook goes too. --lgs-edge is not
inherited: only the host's own ::before changes. */
&.lgs-native [data-lgs-pop~="before"]:not([data-lgs-pop~="self"], [data-lgs-noslab~="before"]),
&.lgs-native [data-lgs-pop~="after"]:not([data-lgs-pop~="self"], [data-lgs-noslab~="after"]) {
--lgs-edge: none;
}
/* ------------------------------------------------------------------ */
/* 5. Menus, alerts and sheets keep their in-page frosted backing */
/* ------------------------------------------------------------------ */
/* Steam draws a menu into the same texture as the page under it, so its
popped crop (and, on windowless routes, the base inside its plate) is
whatever lies in that rect. With the tint and blur zeroed above, that
was the page at full contrast lifted 10 mm: its labels collided with
the menu's and ghosted against the page outside (headset shots
2026-10-08). These keep the thick tint and the blur of the page behind
them in Steam's texture: the glass over a window refracts the window.
glassd's slab or plate still draws the edge, the shadow and the depth;
the CSS drop shadow stays off (it would be cut by the crop). The tokens
are taken back from the root (`inherit`), so the dial still applies.
Only until the runtime cuts the page out under it (html.lgs-page-hole,
rt/22-menus.js): then the slab is transparent glass over glassd's. */
&.lgs-native:not(.lgs-page-hole) :is(%{*BasicContextMenuModal>contextMenuContents}, %{*GamepadDialogContent>ModalPosition} > :not(%{*GamepadDialogContent>ModalClickToDismiss}), %{DialogWrapper>CompatFilterDialog}):is([data-lgs-pop], :is([data-lgs-plate-ack], :root[data-lgs-plates] [data-lgs-plate]:not([data-lgs-plate-css]))) {
--lgs-mat-thick-bg: inherit;
--lgs-mat-thick-blur: inherit;
--lgs-thick-bg: inherit;
--lgs-panel-sheen: inherit;
background: var(--lgs-mat-thick-bg);
backdrop-filter: var(--lgs-mat-thick-blur);
box-shadow: none;
}
/* with the page cut out under it (lgs-page-hole), the slab is glassd's
from the moment it opens: no CSS tint first and a swap when the lift is
acknowledged; the glass behind is the window's until glassd's slab
materializes and lifts it */
&.lgs-native.lgs-page-hole :is(%{*BasicContextMenuModal>contextMenuContents}, %{*GamepadDialogContent>ModalPosition} > :not(%{*GamepadDialogContent>ModalClickToDismiss}), %{DialogWrapper>CompatFilterDialog}) {
--lgs-mat-thick-bg: transparent;
--lgs-mat-thick-shade: 0 0 0 0 transparent;
--lgs-thick-bg: transparent;
--lgs-panel-sheen: linear-gradient(transparent, transparent);
--lgs-glass-rim: 0 0 0 0 transparent;
backdrop-filter: none;
box-shadow: none;
--lgs-edge: none;
}
}