/* 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 () 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; } }