mirror of
https://github.com/MichaelScottsman/LiquidAss-Frame.git
synced 2026-10-17 23:01:00 +02:00
- 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)
316 lines
17 KiB
CSS
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;
|
|
}
|
|
}
|