mirror of
https://github.com/MichaelScottsman/LiquidAss-Frame.git
synced 2026-10-17 18:02:42 +02:00
- Home discs are never occluders: a plate under a pop was its shadow (glassd x.55, no light, in one frame), so the hovered disc and the neighbours its name plate or card overlaps snapped dark on every hover. The pop keeps its own contact shadow. - The frame menu's tab pitch (and place) are registered lengths that transition: VR Settings' shorter panel takes a smaller pitch, which changed the bar in one frame while glassd's shape followed a report (~120 ms) later. Now the bar resizes on the spring the reporter morphs the glass on (shrink fade, grow snappy); measured: Steam's crop moves over ~250 ms and glassd gets the morph from the first report.
1308 lines
58 KiB
CSS
1308 lines
58 KiB
CSS
/* Glass Shell, area "shell" (package C1a, Phase 2): the window and its
|
|
chrome on every main route, the tab-bar ornament (frame.menu), the
|
|
bottom ornament contract (#Footer).
|
|
Concept: docs/phase2/concepts/window-nav.md (WN) §3, §8.4; PLAN §1.2,
|
|
§1.3, §1.9-§1.11. Evidence: docs/phase2/wp/C1a.md.
|
|
Wrapped as html.lgs-on { ... } by the bundler ("&" is html.lgs-on).
|
|
|
|
T1 only here. Rules keyed on attributes or classes that C1a's runtime
|
|
(device/rt/20-shell.js, flag wp.c1a) sets are inert until it runs:
|
|
html.lgs-hdr-108 / html.lgs-hdr-40 CQ1 outcome (none = fallback)
|
|
%{BasicUiRoot}[data-lgs-glass] route glass mode (none = window)
|
|
%{BasicUiRoot}[data-lgs-route] route key
|
|
%{BasicUiRoot}[data-lgs-search] capsule | nested | circle
|
|
#Footer[data-lgs-orn="capsule"|"quiet"] ornament material by content
|
|
#Footer[data-lgs-orn-fixed] area-registered fixed slots
|
|
#Footer[data-lgs-band="off"] flag quietBacking = "off"
|
|
#Footer [data-lgs-btn="<enum>"] member tags (OK, CANCEL, ...)
|
|
[data-lgs-exempt="E-BACK"] Back shown as a circle (T2
|
|
sets aria-label = stock text)
|
|
Shared values other areas read (WN §3.2, C1a's interface table):
|
|
--lgs-hdr-pad page-root top padding: 68px fallback, 0 with lgs-hdr-108
|
|
--lgs-guard-top 124px, --lgs-guard-bottom 596px (window y, VP P-23:
|
|
16 px above the ornament capsule's top, 612)
|
|
--lgs-c1a-tint the window tint on %{BasicUiRoot}; the name is frozen
|
|
(C3b's CC-M sets it transparent, REQ C3b->C1a)
|
|
Tokens: contracts/tokens.md (P4). Private values are --lgs-c1a-*.
|
|
No outlines anywhere: edges come from P4's E3 hook and the material. */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* 0. Interface values */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
& {
|
|
--lgs-hdr-pad: 68px;
|
|
--lgs-guard-top: 124px;
|
|
--lgs-guard-bottom: 596px;
|
|
/* the tab bar's pitch (popup px) until the daemon writes the live one
|
|
(WN §3.3.2): 52 is the floor and fits the panel at every r >= 0.863 */
|
|
--lgs-c1a-tab-p: var(--lgs-tab-pitch, 52px);
|
|
/* a new frame page (VR Settings: a shorter panel) takes another pitch: the bar resizes on the spring
|
|
the reporter morphs its glass on (cover.morph: grow snappy, shrink fade; 20-shell.js picks it), not
|
|
in one frame with the glass following a report later (a flash of mismatched glass) */
|
|
transition: --lgs-tab-pitch var(--lgs-c1a-pitch-motion, var(--lgs-motion-fade)),
|
|
--lgs-tab-place var(--lgs-c1a-pitch-motion, var(--lgs-motion-fade));
|
|
}
|
|
&.lgs-hdr-108 {
|
|
--lgs-hdr-pad: 0px;
|
|
}
|
|
/* CQ1 (WN §3.2, AT-2): the runtime tries the 108 px header only behind the
|
|
flag hdr108 (html.lgs-hdr-try for two frames) and keeps it as
|
|
lgs-hdr-108 only if Steam's header box follows the variable */
|
|
&:is(.lgs-hdr-try, .lgs-hdr-108) %{BasicUiRoot} {
|
|
--basicui-header-height: 108px !important;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* 1. Window glass by route mode (PLAN §1.2, WN §3.1, §8.4) */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
/* The glass height follows the route's mode, never focus. No attribute
|
|
(runtime off) = window. --lgs-c1a-gh is read by the tint, the edge and
|
|
the content clip below. */
|
|
%{BasicUiRoot} {
|
|
--lgs-c1a-gh: var(--lgs-glass-h);
|
|
/* the bottom ornament straddles the glass edge centred, as visionOS
|
|
attaches a bottom toolbar: Steam's legend row (y 628-712) is lifted
|
|
16 px to y 612-696 (44 px on the glass, 40 below it, clear of
|
|
SteamVR's frame controls and their tooltips); page content ends 8 px
|
|
above the capsule (y 604), so nothing runs under it */
|
|
--lgs-c1a-orn-lift: 16px;
|
|
--lgs-c1a-cut: calc(var(--lgs-ornament-y, 628px) - var(--lgs-c1a-orn-lift) - 8px);
|
|
/* the smoky tint (WN §8.4) as the root's own background, sized to the
|
|
glass, so it sits under every page and the audit's contrast model
|
|
(ancestor backgrounds over the room) sees it; the margin stays clear */
|
|
/* P4's window tint: .60-.84 by the dial, .94 in High Contrast (FD-6,
|
|
G-A11Y; REQ P4->C1a) */
|
|
--lgs-c1a-tint: var(--lgs-mat-window-tint);
|
|
--lgs-c1a-r: var(--lgs-r-window);
|
|
/* the toolbar plates' edge on windowless routes (CSS-only look): E4/E5,
|
|
the lit top lip, a soft contact shadow; never a closed line */
|
|
--lgs-c1a-plate-shade: var(--lgs-mat-liquid-shade), inset 0 1.5px 1.5px -1px rgb(255 255 255 / .26), 0 4px 14px rgb(0 0 0 / .30);
|
|
/* four tiles: the body, the bottom band between the corners, and the two
|
|
rounded bottom corners at the glass edge (the root's own radius rounds
|
|
the 720 box, not the 656 glass) */
|
|
background:
|
|
linear-gradient(var(--lgs-c1a-tint), var(--lgs-c1a-tint)) 0 0 / 100% max(0px, calc(var(--lgs-c1a-gh) - var(--lgs-c1a-r))) no-repeat,
|
|
linear-gradient(var(--lgs-c1a-tint), var(--lgs-c1a-tint)) var(--lgs-c1a-r) max(0px, calc(var(--lgs-c1a-gh) - var(--lgs-c1a-r))) / calc(100% - 2 * var(--lgs-c1a-r)) min(var(--lgs-c1a-r), var(--lgs-c1a-gh)) no-repeat,
|
|
radial-gradient(circle var(--lgs-c1a-r) at 100% 0, var(--lgs-c1a-tint) calc(var(--lgs-c1a-r) - .75px), rgb(20 22 30 / 0) var(--lgs-c1a-r)) 0 max(0px, calc(var(--lgs-c1a-gh) - var(--lgs-c1a-r))) / var(--lgs-c1a-r) min(var(--lgs-c1a-r), var(--lgs-c1a-gh)) no-repeat,
|
|
radial-gradient(circle var(--lgs-c1a-r) at 0 0, var(--lgs-c1a-tint) calc(var(--lgs-c1a-r) - .75px), rgb(20 22 30 / 0) var(--lgs-c1a-r)) 100% max(0px, calc(var(--lgs-c1a-gh) - var(--lgs-c1a-r))) / var(--lgs-c1a-r) min(var(--lgs-c1a-r), var(--lgs-c1a-gh)) no-repeat;
|
|
border-radius: var(--lgs-r-window);
|
|
/* E3 arcs from P4's edge hook on ::before (z 20000, above content) */
|
|
--lgs-edge: window;
|
|
}
|
|
%{BasicUiRoot}[data-lgs-glass="window-full"] {
|
|
--lgs-c1a-gh: var(--lgs-glass-h-full);
|
|
}
|
|
%{BasicUiRoot}[data-lgs-glass="windowless"],
|
|
%{BasicUiRoot}:has(> %{MainNavMenuMainSplit} > %{BasicHome}%{PopupBody>TransparentBackground}) {
|
|
--lgs-c1a-gh: 0px;
|
|
--lgs-edge: none;
|
|
}
|
|
|
|
/* the edge hook's ring ends where the glass ends (656 or 720) */
|
|
%{BasicUiRoot}::before {
|
|
bottom: calc(100% - var(--lgs-c1a-gh));
|
|
}
|
|
|
|
/* the window's top sheen (white .08 -> 0 over 30 %) and dark inner edge,
|
|
over the tint and under every page (z -1 in the root's own stacking
|
|
context) */
|
|
%{BasicUiRoot}::after {
|
|
content: "";
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: var(--lgs-c1a-gh);
|
|
border-radius: inherit;
|
|
background: linear-gradient(180deg, rgb(255 255 255 / .08) 0, rgb(255 255 255 / 0) 30%);
|
|
box-shadow: var(--lgs-mat-window-shade);
|
|
pointer-events: none;
|
|
z-index: -1;
|
|
}
|
|
%{BasicUiRoot}[data-lgs-glass="windowless"]::after,
|
|
%{BasicUiRoot}:has(> %{MainNavMenuMainSplit} > %{BasicHome}%{PopupBody>TransparentBackground})::after {
|
|
content: none;
|
|
}
|
|
|
|
/* Backdrop root just inside the glass, so blurred controls (ornament,
|
|
sheets) frost page content, never the window tint twice. A rendering
|
|
hint only: no layout, no containing block, z-order unchanged. */
|
|
%{MainNavMenuMainSplit} {
|
|
will-change: opacity;
|
|
}
|
|
|
|
/* The page's clip: on `window` and `hero` routes content ends 8 px above
|
|
the ornament capsule (y 604, --lgs-c1a-cut), so it never runs under the
|
|
capsule's upper half or below the glass edge into the room. The band
|
|
604-656 is clear window glass the capsule straddles. Hit testing below
|
|
612 is the ornament's. */
|
|
%{BasicUiRoot}:not([data-lgs-glass="window-full"], [data-lgs-glass="windowless"]) > %{MainNavMenuMainSplit} > %{BasicHome}:not(%{PopupBody>TransparentBackground}) {
|
|
clip-path: inset(0 0 calc(100% - var(--lgs-c1a-cut)) 0);
|
|
}
|
|
|
|
/* Every layer that repaints Steam's opaque gradient (or black) over the
|
|
window goes clear, so the glass shows on every route. Page roots that
|
|
areas own are cleared by those areas (LAB). */
|
|
%{BasicHome}%{OpaqueBackground},
|
|
%{BasicHome}%{TrueBlackBackground},
|
|
%{BasicUiRoot}%{PopupBody>BlackBackground},
|
|
%{GamepadLibrary},
|
|
%{DownloadsPage},
|
|
%{OverflowHidden>GamepadPage}%{DialogBackground},
|
|
%{ContentManagement},
|
|
%{TopLevelTransitionSwitch},
|
|
%{ContentWrapper}%{TopLevelTransition},
|
|
%{AbsoluteDiv} {
|
|
background: none;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* 2. The toolbar row (#header, WN §3.2, PLAN §1.9) */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
/* Fallback (no lgs-hdr-108): the header stays 40 px in layout and its
|
|
controls overflow into a 68 px band below; page roots add
|
|
var(--lgs-hdr-pad) (each area pads its own), the scroll guard keeps
|
|
focus clear, and C1c pads modals to 108 (22-presentations.css). With
|
|
lgs-hdr-108 the header is 108 tall and the same positions hold. */
|
|
|
|
/* Steam's header band (its ::before: 50 % black + 100 px blur) becomes the
|
|
scroll edge: a 124 px band of black .30 -> 0, blurred, fading out;
|
|
its opacity stays bound to Steam's --gamepadui-header-background-opacity */
|
|
#header%{Profile>Header}::before {
|
|
bottom: auto;
|
|
height: var(--lgs-scroll-band-h);
|
|
background: var(--lgs-scroll-band-top);
|
|
backdrop-filter: blur(12px);
|
|
-webkit-mask-image: linear-gradient(180deg, #000 40%, transparent);
|
|
mask-image: linear-gradient(180deg, #000 40%, transparent);
|
|
box-shadow: none;
|
|
}
|
|
/* windowless routes (Home, folders, /invites, CC-M) have no window and no
|
|
scroller under the row, so there is no scroll edge to draw: the band
|
|
would only blur the page's own top-row plates (REQ C2a->C1a #10) */
|
|
%{BasicUiRoot}[data-lgs-glass="windowless"] #header%{Profile>Header}::before {
|
|
background: none;
|
|
backdrop-filter: none;
|
|
}
|
|
|
|
/* Back: an 80 x 80 hit box at (14, 14), its 60 px glass control at
|
|
(24, 24) (VP P-60). T1 keeps Steam's "Back" text beside the chevron
|
|
(a 60 px capsule); with T2's E-BACK tag (aria-label = the stock text)
|
|
the label collapses and the control is the 60 px circle. */
|
|
#header %{BackContainer} {
|
|
position: absolute;
|
|
left: 14px;
|
|
top: 14px;
|
|
height: var(--lgs-hit);
|
|
min-width: var(--lgs-hit);
|
|
box-sizing: border-box;
|
|
padding: 0 10px;
|
|
justify-content: center;
|
|
isolation: isolate;
|
|
color: var(--lgs-text-1);
|
|
pointer-events: auto;
|
|
}
|
|
#header %{BackContainer}::before {
|
|
content: "";
|
|
position: absolute;
|
|
inset: 10px;
|
|
z-index: -1;
|
|
border-radius: var(--lgs-r-capsule);
|
|
background: var(--lgs-raised-bg);
|
|
box-shadow: var(--lgs-raised-shadow);
|
|
pointer-events: none;
|
|
transition: background var(--lgs-d-hover-in, 294ms) var(--lgs-ease-b0, ease-out);
|
|
}
|
|
/* laser hover: + white .08 (Steam's ::after is its divider, so the light
|
|
is drawn on the control's own fill) */
|
|
&:not(.lgs-input-pad) #header %{BackContainer}:hover::before {
|
|
background: linear-gradient(rgb(255 255 255 / var(--lgs-hover-add)), rgb(255 255 255 / var(--lgs-hover-add))), var(--lgs-raised-bg);
|
|
}
|
|
#header %{BackContainer}:active::before {
|
|
background: linear-gradient(rgb(255 255 255 / calc(var(--lgs-hover-add) + var(--lgs-press-add))), rgb(255 255 255 / calc(var(--lgs-hover-add) + var(--lgs-press-add)))), var(--lgs-raised-bg);
|
|
}
|
|
/* Steam's divider between Back and search: the gap replaces it */
|
|
#header %{BackContainer}:not(:last-child)::after {
|
|
background: transparent;
|
|
}
|
|
#header %{BackContainer} %{ArrowBack} {
|
|
width: 28px;
|
|
height: 28px;
|
|
margin: 0;
|
|
flex: none;
|
|
}
|
|
#header %{BackContainer>BackButton} {
|
|
padding: 0 14px 0 8px;
|
|
font: var(--lgs-type-callout);
|
|
letter-spacing: 0;
|
|
text-transform: none;
|
|
color: inherit;
|
|
}
|
|
/* T2: the circle (E-BACK) */
|
|
#header %{BackContainer}[data-lgs-exempt="E-BACK"] {
|
|
width: var(--lgs-hit);
|
|
padding: 0;
|
|
}
|
|
#header %{BackContainer}[data-lgs-exempt="E-BACK"] %{BackContainer>BackButton} {
|
|
width: 0;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
}
|
|
/* the Back reveal (T2): after 0.6 s of attention the circle grows into a
|
|
capsule naming the page Back returns to (WN §3.2). The box takes the
|
|
text's width at once (no layout animation, LAB) and the chevron keeps
|
|
its place; the glass grows out of the circle with P5's clip morph on
|
|
`snappy`; the Large Title leaves first (150 ms) and the label comes in
|
|
after it on `fade`, so the two never overlap. Leaving: the label goes at
|
|
once and the glass slides back into the circle on `snappy` (T2, Web
|
|
Animations). Reduce Motion: lgs-morph is P5's plain fade (P-56) */
|
|
#header %{BackContainer}[data-lgs-exempt="E-BACK"] {
|
|
width: auto;
|
|
min-width: var(--lgs-hit);
|
|
}
|
|
#header %{BackContainer} > .lgs-back-reveal {
|
|
display: block;
|
|
max-width: 0;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
opacity: 0;
|
|
font: var(--lgs-type-callout);
|
|
font-weight: 600;
|
|
letter-spacing: 0;
|
|
color: var(--lgs-text-1);
|
|
transition: opacity var(--lgs-motion-fade, 441ms ease);
|
|
}
|
|
#header %{BackContainer}[data-lgs-reveal] > .lgs-back-reveal {
|
|
max-width: 320px;
|
|
padding-left: 4px;
|
|
padding-right: 26px;
|
|
opacity: 1;
|
|
transition: none;
|
|
/* an animation, not a transition: the label node is new on the first
|
|
reveal, and a new node never transitions */
|
|
animation: lgs-fade-in var(--lgs-motion-fade, 441ms ease) var(--lgs-d-page-out, 150ms) backwards;
|
|
}
|
|
#header %{BackContainer}[data-lgs-reveal]::before {
|
|
--sx: 0px;
|
|
--sy: 0px;
|
|
--sw: 60px;
|
|
--sh: 60px;
|
|
--sr: 30px;
|
|
--lgs-morph-r: 30px;
|
|
animation: lgs-morph var(--lgs-motion-snappy, 488ms ease) backwards;
|
|
}
|
|
/* the chevron stays where the circle centred it (80 - 28) / 2 = 26 */
|
|
#header %{BackContainer}[data-lgs-reveal] {
|
|
justify-content: flex-start;
|
|
padding-left: 26px;
|
|
}
|
|
/* the Large Title steps back while the reveal names the way back: out in
|
|
150 ms (before the label comes in), back on `fade` */
|
|
#header > .lgs-title {
|
|
transition: opacity var(--lgs-motion-fade, 441ms ease);
|
|
}
|
|
#header[data-lgs-reveal] > .lgs-title {
|
|
opacity: 0;
|
|
transition: opacity var(--lgs-motion-page-out, 150ms linear);
|
|
}
|
|
/* section roots (T2 route map): borderless, chevron white .70 */
|
|
%{BasicUiRoot}[data-lgs-back="root"] #header %{BackContainer}::before {
|
|
background: none;
|
|
box-shadow: none;
|
|
}
|
|
%{BasicUiRoot}[data-lgs-back="root"] #header %{BackContainer} {
|
|
color: var(--lgs-text-2);
|
|
}
|
|
%{BasicUiRoot} #header %{BackContainer}:is([data-lgs-reveal], [data-lgs-unreveal])::before {
|
|
background: var(--lgs-raised-bg);
|
|
box-shadow: var(--lgs-raised-shadow);
|
|
}
|
|
%{BasicUiRoot} #header %{BackContainer}[data-lgs-reveal] {
|
|
color: var(--lgs-text-1);
|
|
}
|
|
/* hero routes: clear glass over the art (black .32 + 10 px blur) */
|
|
%{BasicUiRoot}[data-lgs-glass="hero"] #header %{BackContainer}::before {
|
|
background: rgb(0 0 0 / .32);
|
|
backdrop-filter: blur(10px);
|
|
box-shadow: var(--lgs-mat-clear-shade);
|
|
}
|
|
/* windowless routes (Home, folders, /invites; WN §3.2): no window behind
|
|
the row, so Back is a plate over the room in CSS-only mode (P4's plate:
|
|
black .58 under white .16 -> .04, the E4/E5 dark edge, the lit top lip
|
|
and a soft contact shadow), also as a section root; glassd's liquid
|
|
plate shell-back takes its place in native mode (§4c). REQ C2a-R2->C1a */
|
|
%{BasicUiRoot}[data-lgs-glass="windowless"] #header %{BackContainer}::before,
|
|
%{BasicUiRoot}[data-lgs-glass="windowless"][data-lgs-back] #header %{BackContainer}::before {
|
|
background: var(--lgs-mat-plate-bg);
|
|
box-shadow: var(--lgs-c1a-plate-shade);
|
|
}
|
|
%{BasicUiRoot}[data-lgs-glass="windowless"] #header %{BackContainer} {
|
|
color: var(--lgs-text-1);
|
|
}
|
|
&:not(.lgs-input-pad) %{BasicUiRoot}[data-lgs-glass="windowless"] #header %{BackContainer}:hover::before {
|
|
background: linear-gradient(rgb(255 255 255 / var(--lgs-hover-add)), rgb(255 255 255 / var(--lgs-hover-add))), var(--lgs-mat-plate-bg);
|
|
}
|
|
%{BasicUiRoot}[data-lgs-glass="windowless"] #header %{BackContainer}:active::before {
|
|
background: linear-gradient(rgb(255 255 255 / calc(var(--lgs-hover-add) + var(--lgs-press-add))), rgb(255 255 255 / calc(var(--lgs-hover-add) + var(--lgs-press-add)))), var(--lgs-mat-plate-bg);
|
|
}
|
|
|
|
/* Search field: one container, three variants (PLAN §1.9). The capsule
|
|
(default, section roots): 520 x 64 centred at x 640, y 54, in a
|
|
536 x 80 hit box; recessed (black .30 + inset shadow); no microphone. */
|
|
#header %{SearchAndTitleContainer}%{ShowingSearch} {
|
|
--lgs-c1a-sw: var(--lgs-search-w);
|
|
position: absolute;
|
|
top: 14px;
|
|
left: calc(640px - var(--lgs-c1a-sw) / 2 - 8px);
|
|
width: calc(var(--lgs-c1a-sw) + 16px);
|
|
height: var(--lgs-hit);
|
|
flex: none;
|
|
box-sizing: border-box;
|
|
padding: 0;
|
|
pointer-events: auto;
|
|
}
|
|
%{BasicUiRoot}[data-lgs-search="nested"] #header %{SearchAndTitleContainer}%{ShowingSearch} {
|
|
--lgs-c1a-sw: var(--lgs-search-w-nested);
|
|
}
|
|
/* settings routes (SET §3.4 fallback, REQ C6a->C1a): the capsule centres
|
|
over the detail pane (x 840: visible 580-1100), clear of the 400 px
|
|
sidebar, until the circle variant ships (searchCircle) */
|
|
%{BasicUiRoot}[data-lgs-route="settings"][data-lgs-search="capsule"] #header %{SearchAndTitleContainer}%{ShowingSearch} {
|
|
left: calc(840px - var(--lgs-c1a-sw) / 2 - 8px);
|
|
}
|
|
#header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchFieldBackground},
|
|
#header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchFieldBackground}%{WhiteBackground} {
|
|
top: 8px;
|
|
bottom: 8px;
|
|
left: 8px;
|
|
right: 8px;
|
|
height: auto;
|
|
width: auto;
|
|
border-radius: var(--lgs-r-capsule);
|
|
background: var(--lgs-fill-thick);
|
|
box-shadow: var(--lgs-recessed-shadow);
|
|
transition: box-shadow var(--lgs-d-hover-in, 294ms) var(--lgs-ease-b0, ease-out);
|
|
}
|
|
/* laser hover: + white .08 on the well */
|
|
&:not(.lgs-input-pad) #header %{SearchAndTitleContainer}%{ShowingSearch}:hover %{SearchFieldBackground} {
|
|
background: linear-gradient(rgb(255 255 255 / var(--lgs-hover-add)), rgb(255 255 255 / var(--lgs-hover-add))), var(--lgs-fill-thick);
|
|
}
|
|
/* focus: the system's only ring (VP P-17), in both input modes, each by
|
|
its own signal (P-01/P-02: a stale .gpfocuswithin never rings under the
|
|
laser; the laser's ring is the typing caret's DOM focus) */
|
|
&:not(.lgs-input-laser) #header %{SearchAndTitleContainer}%{ShowingSearch}.gpfocuswithin %{SearchFieldBackground},
|
|
&:not(.lgs-input-pad) #header %{SearchAndTitleContainer}%{ShowingSearch}:focus-within %{SearchFieldBackground} {
|
|
box-shadow: var(--lgs-recessed-shadow), var(--lgs-field-focus);
|
|
}
|
|
/* windowless routes: the field is a plate over the room (WN §3.2; glassd's
|
|
shell-search plate in native mode, §4c), not a well over nothing */
|
|
%{BasicUiRoot}[data-lgs-glass="windowless"] #header %{SearchAndTitleContainer}%{ShowingSearch} :is(%{SearchFieldBackground}, %{SearchFieldBackground}%{WhiteBackground}) {
|
|
background: var(--lgs-mat-plate-bg);
|
|
box-shadow: var(--lgs-c1a-plate-shade);
|
|
}
|
|
&:not(.lgs-input-pad) %{BasicUiRoot}[data-lgs-glass="windowless"] #header %{SearchAndTitleContainer}%{ShowingSearch}:hover %{SearchFieldBackground} {
|
|
background: linear-gradient(rgb(255 255 255 / var(--lgs-hover-add)), rgb(255 255 255 / var(--lgs-hover-add))), var(--lgs-mat-plate-bg);
|
|
}
|
|
&:not(.lgs-input-laser) %{BasicUiRoot}[data-lgs-glass="windowless"] #header %{SearchAndTitleContainer}%{ShowingSearch}.gpfocuswithin %{SearchFieldBackground},
|
|
&:not(.lgs-input-pad) %{BasicUiRoot}[data-lgs-glass="windowless"] #header %{SearchAndTitleContainer}%{ShowingSearch}:focus-within %{SearchFieldBackground} {
|
|
box-shadow: var(--lgs-c1a-plate-shade), var(--lgs-field-focus);
|
|
}
|
|
#header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchIconLeft},
|
|
#header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchIconLeft}%{WhiteBackground} {
|
|
top: 27px;
|
|
bottom: auto;
|
|
left: 28px;
|
|
width: var(--lgs-symbol);
|
|
height: var(--lgs-symbol);
|
|
color: var(--lgs-text-2);
|
|
}
|
|
#header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchIconRight},
|
|
#header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchIconRight}%{WhiteBackground} {
|
|
top: 29px;
|
|
bottom: auto;
|
|
color: var(--lgs-text-2);
|
|
}
|
|
#header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchBox},
|
|
#header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchBox}%{WhiteBackground} {
|
|
height: 100%;
|
|
padding: 0 18px 0 62px;
|
|
font: var(--lgs-type-body);
|
|
letter-spacing: 0;
|
|
color: var(--lgs-text-1);
|
|
caret-color: var(--lgs-text-1);
|
|
text-shadow: none;
|
|
}
|
|
#header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchBox}::placeholder {
|
|
color: var(--lgs-text-2);
|
|
font-style: normal;
|
|
}
|
|
/* the clear button: a 44 px mini circle (E-MINI) */
|
|
#header %{SearchAndTitleContainer} %{SearchBox}::-webkit-search-cancel-button {
|
|
-webkit-appearance: none;
|
|
width: var(--lgs-btn-sm);
|
|
height: var(--lgs-btn-sm);
|
|
border-radius: 50%;
|
|
background-color: rgb(255 255 255 / .16);
|
|
box-shadow: none;
|
|
}
|
|
&:not(.lgs-input-pad) #header %{SearchAndTitleContainer} %{SearchBox}::-webkit-search-cancel-button:hover {
|
|
background-color: rgb(255 255 255 / calc(.16 + var(--lgs-hover-add)));
|
|
}
|
|
/* the circle variant (Home, hero routes, Settings, /account, ...): a
|
|
60 px magnifier circle in an 80 x 80 box at (1186, 14) */
|
|
%{BasicUiRoot}[data-lgs-search="circle"] #header %{SearchAndTitleContainer}%{ShowingSearch} {
|
|
left: auto;
|
|
right: 14px;
|
|
width: var(--lgs-hit);
|
|
padding: 0;
|
|
}
|
|
%{BasicUiRoot}[data-lgs-search="circle"] #header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchFieldBackground} {
|
|
inset: 10px;
|
|
background: var(--lgs-raised-bg);
|
|
box-shadow: var(--lgs-raised-shadow);
|
|
}
|
|
%{BasicUiRoot}[data-lgs-search="circle"] #header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchIconLeft} {
|
|
left: 27px;
|
|
}
|
|
%{BasicUiRoot}[data-lgs-search="circle"][data-lgs-glass="hero"] #header %{SearchAndTitleContainer}%{ShowingSearch} %{SearchFieldBackground} {
|
|
background: rgb(0 0 0 / .32);
|
|
backdrop-filter: blur(10px);
|
|
box-shadow: var(--lgs-mat-clear-shade);
|
|
}
|
|
|
|
/* Title mode (calibration, device support, ...): Title 2 centred on the
|
|
toolbar row, as Steam replaces search with it (H5) */
|
|
#header %{SearchAndTitleContainer}%{ShowingTitle} {
|
|
position: absolute;
|
|
top: 14px;
|
|
left: 120px;
|
|
right: 120px;
|
|
width: auto;
|
|
height: var(--lgs-hit);
|
|
padding: 0;
|
|
justify-content: center;
|
|
}
|
|
#header %{SearchAndTitleContainer}%{ShowingTitle} > div {
|
|
font: var(--lgs-type-title2);
|
|
letter-spacing: 0;
|
|
color: var(--lgs-text-1);
|
|
text-shadow: none;
|
|
}
|
|
|
|
/* Large Title (T2 node, aria-hidden): x 100, centred on the row */
|
|
#header > .lgs-title {
|
|
position: absolute;
|
|
left: 100px;
|
|
top: 14px;
|
|
height: var(--lgs-hit);
|
|
display: flex;
|
|
align-items: center;
|
|
font: var(--lgs-type-large);
|
|
letter-spacing: var(--lgs-track-large);
|
|
color: var(--lgs-text-1);
|
|
white-space: nowrap;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Account alert (#header_profile, only with active support alerts):
|
|
a 60 px circle top right, 24 px inset */
|
|
#header %{HeaderItem} {
|
|
position: absolute;
|
|
right: 14px;
|
|
top: 14px;
|
|
width: var(--lgs-hit);
|
|
height: var(--lgs-hit);
|
|
border-radius: 50%;
|
|
justify-content: center;
|
|
color: var(--lgs-text-1);
|
|
pointer-events: auto;
|
|
}
|
|
|
|
/* The header's own box takes no clicks in the fallback band; its
|
|
controls do (inventory shell §3). Steam's header is already
|
|
pointer-events none except its children; nothing changes here. */
|
|
|
|
/* High contrast: a solid band again */
|
|
@media (prefers-contrast: more) {
|
|
#header%{Profile>Header}::before {
|
|
background: var(--lgs-mat-thick-bg);
|
|
backdrop-filter: none;
|
|
-webkit-mask-image: none;
|
|
mask-image: none;
|
|
}
|
|
}
|
|
|
|
/* Scroll guard (VP P-23, WN §3.2): focused items stay below the toolbar
|
|
row. Steam's generic vertical scrollers start at the header's bottom,
|
|
so their top padding is the guard minus the header. Areas apply the
|
|
same variables to their own scrollers (and the bottom bound). */
|
|
%{ScrollPanel}%{ScrollY} {
|
|
scroll-padding-top: calc(var(--lgs-guard-top) - var(--basicui-header-height, 40px));
|
|
/* and they end at the footer's top (628), so 16 px keeps focus above 612 */
|
|
scroll-padding-bottom: calc(720px - var(--gamepadui-current-footer-height, 92px) - var(--lgs-guard-bottom));
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* 3. The bottom ornament (#Footer, WN §3.4, PLAN §1.10) */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
/* Only the main window's footer (the floating footer and the Quick
|
|
Access footer reuse #Footer; C3a styles the floating one). */
|
|
|
|
/* The strip dissolves; 8 px under the capsule makes Steam's measured
|
|
footer 92 px, so pages and modals end at y 628 by Steam's own layout. */
|
|
%{BasicUiRoot} #Footer%{BasicFooter}:not(%{FloatingVRFooter}, %{QuickAccessFooter}) {
|
|
background: none;
|
|
backdrop-filter: none;
|
|
border-image: none;
|
|
border-top: 0;
|
|
padding-bottom: 8px;
|
|
/* the capsule's E3 edge (P4's hook on ::before, placed below) */
|
|
--lgs-edge: liquid;
|
|
/* the capsule's glass: liquid over the page (y 628-656), tinted over the
|
|
room below (also its leaving ghost, below) */
|
|
--lgs-c1a-orn-bg:
|
|
linear-gradient(180deg, rgb(255 255 255 / .12), rgb(255 255 255 / .03) 55%),
|
|
linear-gradient(180deg, rgb(28 30 40 / .30) 0, rgb(28 30 40 / .30) 22px,
|
|
rgb(28 30 40 / calc(.58 + var(--lgs-dial) * .24)) 40px);
|
|
--lgs-c1a-orn-shade: var(--lgs-mat-liquid-shade), 0 7px 22px rgb(0 0 0 / .28);
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter}:not(%{FloatingVRFooter}, %{QuickAccessFooter}) %{FooterLegend} {
|
|
height: var(--lgs-ornament);
|
|
padding: 0;
|
|
justify-content: center;
|
|
align-items: center;
|
|
/* no gap: the members' hit boxes abut (VP P-07); the 4 px between their
|
|
visible pills is a 2 px share of each member's own box */
|
|
gap: 0;
|
|
/* the lift (section 1): the row moves up, Steam's measured footer stays
|
|
92 px (the margins cancel), so pages still end where Steam puts them */
|
|
margin-top: calc(-1 * var(--lgs-c1a-orn-lift, 0px));
|
|
margin-bottom: var(--lgs-c1a-orn-lift, 0px);
|
|
}
|
|
/* Steam's flex spacer would push the legends right; the capsule is
|
|
centred (it is empty and takes no clicks) */
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{FooterLegend} > %{PopupBody>Spacer} {
|
|
flex: 0 0 0px;
|
|
margin: 0;
|
|
}
|
|
|
|
/* Members: 60 px capsules inside an 84 px hit row whose boxes abut along
|
|
the row (VP P-07: the light is inset 12 px top and bottom and 2 px at
|
|
each side, so neighbouring pills stay 4 px apart), label first (22
|
|
Semibold, mixed case), the glyph badge trailing like a menu's keyboard
|
|
shortcut. */
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{ActionButtonLegend} {
|
|
height: var(--lgs-ornament);
|
|
box-sizing: border-box;
|
|
padding: 0 calc(var(--lgs-btn-pad) + 2px);
|
|
border-radius: var(--lgs-r-capsule);
|
|
background: none !important;
|
|
isolation: isolate;
|
|
color: var(--lgs-text-1);
|
|
--lgs-ill: raised;
|
|
--lgs-ill-inset: 12px 2px;
|
|
--lgs-ill-r: var(--lgs-r-capsule);
|
|
--lgs-ill-z: -1;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{ActionButtonLegend} %{ActionButtonLabel},
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{ActionButtonLegend} %{CompatFooterDescription} {
|
|
margin: 0;
|
|
font-family: var(--lgs-font);
|
|
font-size: var(--lgs-fs-callout);
|
|
font-weight: 600;
|
|
line-height: 1.3;
|
|
letter-spacing: 0;
|
|
text-transform: none;
|
|
color: inherit;
|
|
text-shadow: none;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{ActionButtonLegend} %{ActionButtonLegend>ActionButtonGlyph} {
|
|
order: 1;
|
|
margin-left: 10px;
|
|
width: var(--lgs-glyph);
|
|
height: var(--lgs-glyph);
|
|
flex: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
/* Steam's own glyph image as the 30 px badge (VP P-26, P-27): a white
|
|
.16 disc with the letter at white .70, behind the label in weight.
|
|
The image is a light disc with a dark letter: inverted and screened,
|
|
its disc vanishes and its letter turns light over the badge's disc. */
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{ActionButtonLegend} %{ActionButtonLegend>ActionButtonGlyph} {
|
|
border-radius: 50%;
|
|
background: rgb(255 255 255 / .16);
|
|
/* Steam's wide glyphs (the ≡ pill) stay inside the disc (review R2 m8) */
|
|
overflow: hidden;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{ActionButtonLegend} %{FooterGlyphSize} {
|
|
width: var(--lgs-glyph);
|
|
height: var(--lgs-glyph);
|
|
object-fit: contain;
|
|
filter: invert(1);
|
|
mix-blend-mode: screen;
|
|
opacity: .70;
|
|
}
|
|
/* T2 (data-lgs-glyph, --lgs-c1a-glyph = the image's own URL): Steam's glyph
|
|
is a white disc (the menu glyph a white pill) with the letter cut out,
|
|
so the letter is drawn as the image's own background (white .70) seen
|
|
through a mask of those holes: the full box minus the glyph, cut to a
|
|
circle inside the disc's edge. No blend mode: an inverted opaque disc
|
|
screened over the translucent capsule came out as an opaque dark disc
|
|
with a light ring (review R2 m8); now only the letter lands on the .16
|
|
badge, as WN draws it, for whatever glyph set Steam shows */
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{ActionButtonLegend} %{FooterGlyphSize}[data-lgs-glyph] {
|
|
filter: none;
|
|
mix-blend-mode: normal;
|
|
opacity: 1;
|
|
background: rgb(255 255 255 / .70);
|
|
-webkit-mask-image: radial-gradient(circle closest-side, #000 84%, transparent 90%), linear-gradient(#000 0 0), var(--lgs-c1a-glyph);
|
|
mask-image: radial-gradient(circle closest-side, #000 84%, transparent 90%), linear-gradient(#000 0 0), var(--lgs-c1a-glyph);
|
|
-webkit-mask-size: 100% 100%;
|
|
mask-size: 100% 100%;
|
|
-webkit-mask-position: center;
|
|
mask-position: center;
|
|
-webkit-mask-repeat: no-repeat;
|
|
mask-repeat: no-repeat;
|
|
-webkit-mask-composite: source-in, xor;
|
|
mask-composite: intersect, exclude;
|
|
}
|
|
/* the menu glyph: keep only the middle of its pill (the bars), drawn 1.5x
|
|
so the bars read at the letters' size inside the 30 px badge */
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{ActionButtonLegend} %{FooterGlyphSize}%{*PillShapedIcon}[data-lgs-glyph] {
|
|
-webkit-mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0), var(--lgs-c1a-glyph);
|
|
mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0), var(--lgs-c1a-glyph);
|
|
-webkit-mask-size: 50% 34%, 100% 100%, 100% 100%;
|
|
mask-size: 50% 34%, 100% 100%, 100% 100%;
|
|
scale: 1.5;
|
|
}
|
|
/* laser mode: glyph badges collapse (no width, no paint); the legend, its
|
|
label and its click target stay (no function hidden) */
|
|
&[data-lgs-vr-mode="laser"] %{BasicUiRoot} #Footer%{BasicFooter} %{ActionButtonLegend} %{ActionButtonLegend>ActionButtonGlyph} {
|
|
width: 0;
|
|
margin: 0;
|
|
overflow: hidden;
|
|
background: none;
|
|
}
|
|
/* A and B: quiet trailing members (T2 tags the button enum) */
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{ActionButtonLegend}:is([data-lgs-btn="OK"], [data-lgs-btn="CANCEL"]) {
|
|
color: var(--lgs-text-2);
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{ActionButtonLegend}:is([data-lgs-btn="OK"], [data-lgs-btn="CANCEL"]) :is(%{ActionButtonLabel}, %{CompatFooterDescription}) {
|
|
font-weight: 500;
|
|
}
|
|
/* the Options member (T2, WN §3.4.2 slot 2): Steam's legend look; the
|
|
target's name trails as a quieter decorative suffix; disabled = .38,
|
|
no hover or press (P4 keys them off aria-disabled), no dispatch */
|
|
%{BasicUiRoot} #Footer%{BasicFooter} .lgs-opt[data-lgs-t2] {
|
|
cursor: default;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter} .lgs-opt[data-lgs-t2][aria-disabled="true"] {
|
|
opacity: .55;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter} .lgs-opt[data-lgs-t2] .lgs-opt-glyph {
|
|
flex: none;
|
|
width: 22px;
|
|
height: 22px;
|
|
margin-right: 10px;
|
|
fill: currentColor;
|
|
opacity: .70;
|
|
}
|
|
&:not([data-lgs-vr-mode="laser"]) %{BasicUiRoot} #Footer%{BasicFooter} .lgs-opt[data-lgs-t2] .lgs-opt-glyph {
|
|
display: none;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter} .lgs-opt[data-lgs-t2] .lgs-opt-name {
|
|
margin-left: .3em;
|
|
display: inline-block;
|
|
max-width: 260px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
vertical-align: bottom;
|
|
font-weight: 500;
|
|
color: var(--lgs-text-2);
|
|
}
|
|
/* 14 px between the member groups' pills, inside the first quiet member's
|
|
own box (its light starts 12 px in), so the hit boxes still abut; an
|
|
area's fixed slots place their members themselves */
|
|
%{BasicUiRoot} #Footer%{BasicFooter}:not([data-lgs-orn-fixed]) %{ActionButtonLegend}:not([data-lgs-btn="OK"], [data-lgs-btn="CANCEL"]) + %{ActionButtonLegend}:is([data-lgs-btn="OK"], [data-lgs-btn="CANCEL"]) {
|
|
padding-left: calc(var(--lgs-btn-pad) + 12px);
|
|
--lgs-ill-inset: 12px 2px 12px 12px;
|
|
}
|
|
/* compact members (T2 sets it when the members would pass 960 px) */
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn-compact] %{ActionButtonLegend} {
|
|
padding: 0 18px;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn-compact] %{ActionButtonLegend} :is(%{ActionButtonLabel}, %{CompatFooterDescription}) {
|
|
font-size: var(--lgs-fs-subhead);
|
|
}
|
|
/* while an alert or sheet is open (C1c's html.lgs-modal), the members
|
|
that act on the page beneath recede under black .35 (still clickable) */
|
|
&.lgs-modal %{BasicUiRoot} #Footer%{BasicFooter} [data-lgs-t2] {
|
|
filter: brightness(.65);
|
|
}
|
|
|
|
/* The capsule: anchored to the first and last member, so it hugs them in
|
|
any language and mode (without T2), or at the rect T2 writes
|
|
(--lgs-orn-x / --lgs-orn-w: measured union or an area's fixed slots).
|
|
y 628-712, radius 42, padding 0 12; liquid glass that frosts the page
|
|
above the glass edge and is tinted over the room below it (WN §8.4). */
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{FooterLegend} > :nth-child(1 of %{ActionButtonLegend}) {
|
|
anchor-name: --lgs-orn-first;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{FooterLegend} > :nth-last-child(1 of %{ActionButtonLegend}) {
|
|
anchor-name: --lgs-orn-last;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter} %{FooterLegend} > :nth-child(1 of %{ActionButtonLegend}):nth-last-child(1 of %{ActionButtonLegend}) {
|
|
anchor-name: --lgs-orn-first, --lgs-orn-last;
|
|
}
|
|
/* 12 px of capsule padding outside the first and last pill (their boxes
|
|
reach 2 px past their pills) */
|
|
%{BasicUiRoot} #Footer%{BasicFooter}:not(%{FloatingVRFooter}, %{QuickAccessFooter})::before,
|
|
%{BasicUiRoot} #Footer%{BasicFooter}:not(%{FloatingVRFooter}, %{QuickAccessFooter})::after {
|
|
top: anchor(--lgs-orn-first top, 0px);
|
|
bottom: anchor(--lgs-orn-first bottom, 8px);
|
|
left: calc(anchor(--lgs-orn-first left, 100%) - 10px);
|
|
right: calc(anchor(--lgs-orn-last right, 0px) - 10px);
|
|
border-radius: var(--lgs-r-capsule);
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter}:not(%{FloatingVRFooter}, %{QuickAccessFooter})::after {
|
|
content: "";
|
|
position: absolute;
|
|
z-index: -1;
|
|
pointer-events: none;
|
|
/* liquid over the page (y 628-656), tinted over the room below */
|
|
background: var(--lgs-c1a-orn-bg);
|
|
backdrop-filter: var(--lgs-mat-liquid-blur);
|
|
box-shadow: var(--lgs-c1a-orn-shade);
|
|
}
|
|
/* Motion (WN §7, PLAN §1.5; P5's keyframes and tokens). The capsule's
|
|
glass materializes in (lgs-mat-glass-in, 250 ms) whenever the legend
|
|
becomes a capsule; when it becomes quiet, the capsule's glass
|
|
dematerializes at its old rect (lgs-mat-glass-out, 350 ms, the ghost
|
|
on ::before below) while the quiet legend's dim band fades in over the
|
|
same 350 ms. A member Steam adds fades its label in on `fade`; the
|
|
labels already there never move by animation. A width change of the
|
|
capsule slides its ends on `snappy` (T2: Web Animations on ::before and
|
|
::after, device/rt/20-shell.js). Reduce Motion: P5's keyframes are
|
|
opacity only and the ends do not slide. */
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn="capsule"]:not(%{FloatingVRFooter}, %{QuickAccessFooter})::after {
|
|
--lgs-maxside: 960; /* the widest ornament: a swell of 12 px or less, under P-53's 1.5 % */
|
|
animation: lgs-mat-glass-in var(--lgs-motion-mat-in, 250ms linear) backwards;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn="quiet"]:not(%{FloatingVRFooter}, %{QuickAccessFooter})::after {
|
|
animation: lgs-fade-in var(--lgs-d-mat-out, 350ms) var(--lgs-ease-fade, ease-out) backwards;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter}:not(%{FloatingVRFooter}, %{QuickAccessFooter}) %{ActionButtonLegend} :is(%{ActionButtonLabel}, %{CompatFooterDescription}) {
|
|
animation: lgs-fade-in var(--lgs-motion-fade, 441ms ease-out) backwards;
|
|
}
|
|
/* T2's measured or fixed rect */
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn-fixed]:not(%{FloatingVRFooter})::before,
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn-fixed]:not(%{FloatingVRFooter})::after,
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn-measured]:not(%{FloatingVRFooter})::before,
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn-measured]:not(%{FloatingVRFooter})::after {
|
|
left: var(--lgs-orn-x);
|
|
right: auto;
|
|
width: var(--lgs-orn-w);
|
|
top: calc(-1 * var(--lgs-c1a-orn-lift, 0px));
|
|
bottom: calc(8px + var(--lgs-c1a-orn-lift, 0px));
|
|
}
|
|
/* Native glass (T2 node .lgs-orn-plate, device/rt/20-shell.js): the
|
|
capsule's rect for P6's reporter, the liquid plate shell-ornament and
|
|
the data-lgs-nopop box (PLAN §1.7 rule 1). It paints nothing. */
|
|
%{BasicUiRoot} #Footer%{BasicFooter} > .lgs-orn-plate {
|
|
position: absolute;
|
|
top: anchor(--lgs-orn-first top, 0px);
|
|
bottom: anchor(--lgs-orn-first bottom, 8px);
|
|
left: calc(anchor(--lgs-orn-first left, 100%) - 10px);
|
|
right: calc(anchor(--lgs-orn-last right, 0px) - 10px);
|
|
border-radius: var(--lgs-r-capsule);
|
|
pointer-events: none;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter}:is([data-lgs-orn-fixed], [data-lgs-orn-measured]) > .lgs-orn-plate {
|
|
left: var(--lgs-orn-x);
|
|
right: auto;
|
|
width: var(--lgs-orn-w);
|
|
top: calc(-1 * var(--lgs-c1a-orn-lift, 0px));
|
|
bottom: calc(8px + var(--lgs-c1a-orn-lift, 0px));
|
|
}
|
|
|
|
/* Quiet legend (only A and B, T2's data-lgs-orn="quiet"): no capsule
|
|
material, the members keep 60 px and their place */
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn="quiet"] {
|
|
--lgs-edge: none;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn="quiet"]::after {
|
|
background: none;
|
|
backdrop-filter: none;
|
|
box-shadow: none;
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn="quiet"] %{ActionButtonLegend} {
|
|
color: var(--lgs-text-2);
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn="quiet"] %{ActionButtonLegend} :is(%{ActionButtonLabel}, %{CompatFooterDescription}) {
|
|
font-weight: 500;
|
|
}
|
|
/* ... and on `window` routes, where it sits in the margin over the room,
|
|
one dim band behind it (flag quietBacking, WN §3.4.1, O3): black .62,
|
|
60 px, blurred edges, not glass (no blur of the room, no rim, no
|
|
slab); labels white .82 with the on-room shadow (VP P-39, P-41) */
|
|
%{BasicUiRoot}:not([data-lgs-glass="window-full"]) #Footer%{BasicFooter}[data-lgs-orn="quiet"]:not([data-lgs-band="off"])::after {
|
|
top: calc(anchor(--lgs-orn-first top, 0px) + 12px);
|
|
bottom: calc(anchor(--lgs-orn-first bottom, 8px) + 12px);
|
|
left: calc(anchor(--lgs-orn-first left, 100%) - 8px);
|
|
right: calc(anchor(--lgs-orn-last right, 0px) - 8px);
|
|
background: rgb(0 0 0 / .62);
|
|
filter: blur(7px);
|
|
}
|
|
%{BasicUiRoot}:not([data-lgs-glass="window-full"]) #Footer%{BasicFooter}[data-lgs-orn="quiet"]:not([data-lgs-band="off"]) %{ActionButtonLegend} {
|
|
color: rgb(255 255 255 / .82);
|
|
text-shadow: var(--lgs-text-room-shadow);
|
|
}
|
|
/* capsule -> quiet (T2 sets data-lgs-orn-leave for 600 ms with the old
|
|
rect in --lgs-orn-gl / --lgs-orn-gr): the capsule's glass leaves as P5's
|
|
dematerialize (held while nothing else moves, then dissolved, 350 ms);
|
|
at rest it is opacity 0. ::before is free in the quiet legend (no E3
|
|
hook there). Native mode: glassd fades its own plate, so no ghost. */
|
|
&:not(.lgs-native) %{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn="quiet"][data-lgs-orn-leave]:not(%{FloatingVRFooter}, %{QuickAccessFooter})::before {
|
|
content: "";
|
|
position: absolute;
|
|
z-index: -1;
|
|
top: calc(-1 * var(--lgs-c1a-orn-lift, 0px));
|
|
bottom: calc(8px + var(--lgs-c1a-orn-lift, 0px));
|
|
left: var(--lgs-orn-gl, 50%);
|
|
right: var(--lgs-orn-gr, 50%);
|
|
width: auto;
|
|
border-radius: var(--lgs-r-capsule);
|
|
background: var(--lgs-c1a-orn-bg);
|
|
backdrop-filter: var(--lgs-mat-liquid-blur);
|
|
box-shadow: var(--lgs-c1a-orn-shade);
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
--lgs-maxside: 960; /* the widest ornament: a swell of 12 px or less, under P-53's 1.5 % */
|
|
animation: lgs-mat-glass-out var(--lgs-motion-mat-out, 350ms ease-out);
|
|
}
|
|
|
|
/* Native glass: once glassd draws the ornament plate (acked), the plate
|
|
is the capsule's glass on both sides of the window edge. The CSS tint's
|
|
two tones (light over the page, dark over the room) would split it in
|
|
half at the edge, so the capsule keeps one even scrim (white labels
|
|
stay legible), no drop shadow of its own (the plate's contact shadow)
|
|
and no in-page frost (nothing runs under it any more). */
|
|
&.lgs-native %{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn="capsule"]:has(> .lgs-orn-plate:is([data-lgs-plate-ack], :root[data-lgs-plates] [data-lgs-plate]:not([data-lgs-plate-css]))):not(%{FloatingVRFooter}, %{QuickAccessFooter}) {
|
|
--lgs-c1a-orn-bg: linear-gradient(var(--lgs-scrim), var(--lgs-scrim));
|
|
--lgs-c1a-orn-shade: 0 0 0 0 transparent;
|
|
}
|
|
&.lgs-native %{BasicUiRoot} #Footer%{BasicFooter}[data-lgs-orn="capsule"]:has(> .lgs-orn-plate:is([data-lgs-plate-ack], :root[data-lgs-plates] [data-lgs-plate]:not([data-lgs-plate-css]))):not(%{FloatingVRFooter}, %{QuickAccessFooter})::after {
|
|
backdrop-filter: none;
|
|
}
|
|
|
|
@media (prefers-contrast: more) {
|
|
%{BasicUiRoot} #Footer%{BasicFooter}:not(%{FloatingVRFooter}, %{QuickAccessFooter}) {
|
|
--lgs-c1a-orn-bg: var(--lgs-mat-liquid-bg);
|
|
}
|
|
%{BasicUiRoot} #Footer%{BasicFooter}:not(%{FloatingVRFooter}, %{QuickAccessFooter})::after {
|
|
backdrop-filter: none;
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* 4. The tab-bar ornament (frame.menu, WN §3.3) */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
/* Steam's frame menu, restyled as two glass capsules of circles: the six
|
|
sections, then the system (Console, Settings, [Help], VR Settings, a
|
|
10 px gap, Power). Built from Steam's component variables and the
|
|
rows' backgrounds; the width only as below (measured, so it animates). Specific to
|
|
%{Variant_FrameMenu}, so the bar's tab menus (C3a) are untouched. */
|
|
%{DashboardMenu}%{Variant_FrameMenu} {
|
|
--lgs-c1a-tab-d: calc(var(--lgs-c1a-tab-p) - 8px);
|
|
--lgs-c1a-tab-fill: rgb(28 30 40 / calc(.67 + var(--lgs-dial) * .22));
|
|
--menu-background: transparent;
|
|
--menu-item-height: calc(var(--lgs-c1a-tab-p) - 6px);
|
|
--menu-icon-size: calc(var(--lgs-c1a-tab-d) * .52);
|
|
--menu-font-size: var(--lgs-fs-callout);
|
|
/* the capsules' corner radius: collapsed, half the column (a capsule of
|
|
circles); expanded, a 30 px rounded rectangle (a capsule radius on the
|
|
wide panel made it an oval blob). The native cover reads the same
|
|
radius from .lgs-tabcap (theme/layers/20-shell.json) */
|
|
--lgs-c1a-tab-r: 30px;
|
|
background: none;
|
|
box-shadow: none;
|
|
border-radius: 0;
|
|
/* rule 1 of WN §3.3.2 (T2): a transparent band under the bar centres
|
|
its capsules on the glass instead of the panel */
|
|
padding-bottom: var(--lgs-tab-place, 0px);
|
|
}
|
|
/* collapsed, the capsule is the circle plus 12 px at each side (WN
|
|
§3.3.1): only the value of Steam's collapsed width (54) changes. Steam's
|
|
width transition (300 ms ease) is retimed, timing properties only (WN
|
|
§7): out to the labels on `snappy`, back to the circles on `fade`.
|
|
Expanded, Steam leaves the width `auto`, which Chromium 126 cannot
|
|
interpolate: the menu jumped open in one frame (and the native glass
|
|
followed a report later). The runtime measures the expanded width the
|
|
labels need (--lgs-c1a-tab-wx on the frame-menu root, device/rt/
|
|
20-shell.js) and it is set here, so the width really animates; the
|
|
content is the same as at `auto` (overflow stays Steam's hidden). */
|
|
%{DashboardMenu}%{Variant_FrameMenu} {
|
|
width: var(--lgs-c1a-tab-wx, auto);
|
|
transition-duration: var(--lgs-d-snappy, 488ms);
|
|
transition-timing-function: var(--lgs-ease-snappy, ease);
|
|
}
|
|
/* A label keeps its own width while the bar slides open (the bar's edge
|
|
clips it meanwhile): squeezed by the animating width, Steam's marquee
|
|
started on "Steam Settings" and "Friends & Chat" mid-open and stayed on,
|
|
their ends scrolling and faded out in the open bar. Steam's 160 px cap
|
|
goes too; the open bar is as wide as its labels need (the measure above) */
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>ItemLabel} {
|
|
max-width: none;
|
|
flex-shrink: 0;
|
|
}
|
|
/* native: the motion starts a moment after Steam's toggle, so glassd (told
|
|
the end shape and the start time by the reporter, cover.morph in
|
|
theme/layers/20-shell.json) moves the capsules' glass on the same spring
|
|
from the first frame instead of catching up. Invisible next to Steam's
|
|
own 500 ms hover delay */
|
|
&.lgs-native %{DashboardMenu}%{Variant_FrameMenu} {
|
|
transition-delay: var(--lgs-native-lead, 70ms);
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu}%{DashboardMenu>Collapsed} {
|
|
--lgs-c1a-tab-r: calc(var(--lgs-c1a-tab-d) / 2 + 12px);
|
|
width: calc(var(--lgs-c1a-tab-d) + 24px);
|
|
transition-duration: var(--lgs-d-fade, 441ms);
|
|
transition-timing-function: var(--lgs-ease-fade, ease);
|
|
}
|
|
/* each row paints its slice of its capsule (rows are contiguous) */
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>ItemOuter},
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{SectionGap} {
|
|
background: var(--lgs-c1a-tab-fill);
|
|
border-color: transparent !important;
|
|
/* Steam rounds its group ends by 6 px; the capsule ends below decide */
|
|
border-radius: 0 !important;
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{SectionGap} {
|
|
height: 10px;
|
|
margin: 0;
|
|
width: 100%;
|
|
}
|
|
/* capsule ends: the first row of each group, the last row of each group
|
|
(radius = half the collapsed width, so the circles sit concentric in
|
|
the ends; the 6 px padding is the row's) */
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>ItemOuter}:nth-child(1 of %{DashboardMenu>ItemOuter}),
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>ItemOuter}:nth-child(7 of %{DashboardMenu>ItemOuter}) {
|
|
padding-top: 6px;
|
|
border-top-left-radius: var(--lgs-c1a-tab-r) !important;
|
|
border-top-right-radius: var(--lgs-c1a-tab-r) !important;
|
|
background: linear-gradient(180deg, rgb(255 255 255 / .08), rgb(255 255 255 / 0) 60%), var(--lgs-c1a-tab-fill);
|
|
box-shadow: var(--lgs-raised-shadow);
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>ItemOuter}:nth-child(6 of %{DashboardMenu>ItemOuter}),
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>ItemOuter}:nth-last-child(1 of %{DashboardMenu>ItemOuter}) {
|
|
padding-bottom: 6px;
|
|
border-bottom-left-radius: var(--lgs-c1a-tab-r) !important;
|
|
border-bottom-right-radius: var(--lgs-c1a-tab-r) !important;
|
|
}
|
|
/* 10 popup px between the two capsules */
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>ItemOuter}:nth-child(7 of %{DashboardMenu>ItemOuter}) {
|
|
margin-top: 10px;
|
|
}
|
|
/* Native glass (T2 nodes .lgs-tabcap, device/rt/20-shell.js): the two
|
|
capsules' rects, the frame.menu cover elements of
|
|
theme/layers/20-shell.json (liquid, PLAN §1.6). They paint nothing.
|
|
Rows: the first and last of a group are p + 6, the others p; 10 px
|
|
between the groups; the band under the bar is the root's padding. */
|
|
%{DashboardMenu}%{Variant_FrameMenu} > .lgs-tabcap {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
border-radius: var(--lgs-c1a-tab-r);
|
|
pointer-events: none;
|
|
/* each capsule's E3 edge (WN §8.1: arc + lobe; P4's hook on ::before),
|
|
whole-capsule, so the rows' slices never draw a ring of their own.
|
|
The hook's conic light is centred on the box: on an 82 px wide, 400 px
|
|
tall capsule most of the upper sides fall in the key light's bright
|
|
sector (measured dL 164 down the left side, twice the window's top
|
|
arc), which reads as a line; .45 of dimming brings the brightest part
|
|
to the window rim's level */
|
|
--lgs-edge: liquid;
|
|
--lgs-edge-dim: .45;
|
|
}
|
|
&.lgs-native %{DashboardMenu}%{Variant_FrameMenu} > .lgs-tabcap[data-lgs-cover] {
|
|
--lgs-edge: none;
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} > .lgs-tabcap[data-lgs-tabcap="1"] {
|
|
top: 0;
|
|
height: calc(6 * var(--lgs-c1a-tab-p) + 12px);
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} > .lgs-tabcap[data-lgs-tabcap="2"] {
|
|
top: calc(6 * var(--lgs-c1a-tab-p) + 22px);
|
|
bottom: var(--lgs-tab-place, 0px);
|
|
}
|
|
|
|
/* rows: the item never paints a fill of its own (Steam: hover 20 %
|
|
white, focus keyframes); light comes from P4's nav hook on the item */
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item} {
|
|
background: transparent !important;
|
|
--lgs-ill: nav;
|
|
/* expanded: the pill ends 10 px inside the 30 px panel (the end rows'
|
|
6 px padding + 4 px), so its 20 px corners are concentric */
|
|
--lgs-ill-inset: 4px 10px;
|
|
--lgs-ill-r: calc(var(--lgs-c1a-tab-r) - 10px);
|
|
}
|
|
/* collapsed: the pill ends 12 px inside the capsule (concentric with its
|
|
ends) */
|
|
%{DashboardMenu}%{Variant_FrameMenu}%{DashboardMenu>Collapsed} %{DashboardMenu>Item} {
|
|
--lgs-ill-inset: 4px 12px;
|
|
--lgs-ill-r: var(--lgs-r-capsule);
|
|
}
|
|
/* without C1a's runtime (no .lgs-tabcap) the native cover is the menu's
|
|
own box: give it the panel's corners so it is never a square slab
|
|
(REQ P7->C1a) */
|
|
%{DashboardMenu}%{Variant_FrameMenu}:not(:has(> .lgs-tabcap)) {
|
|
border-radius: var(--lgs-c1a-tab-r);
|
|
}
|
|
/* tabs never scale on focus or selection (VP P-05, PLAN §1.4). Steam
|
|
zooms the focused and the current item 1.1x with its own transform;
|
|
that value stays Steam's, the independent `scale` (LAB) takes it back
|
|
to 1, and Steam's transform transition is set to 0 s (timing only) so
|
|
the two never drift apart mid-way */
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item} {
|
|
transition-duration: 0s;
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item}%{DashboardMenu>Active},
|
|
&:not(.lgs-input-laser) %{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item}.gpfocus {
|
|
scale: calc(1 / 1.1);
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>ItemOuter}::before {
|
|
content: none;
|
|
}
|
|
/* glyphs white .70 at rest, labels 22 Medium white .96 (expanded) */
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item} %{DashboardMenu>ItemIcon} {
|
|
position: relative;
|
|
color: var(--lgs-text-2) !important;
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item} %{DashboardMenu>ItemLabel} {
|
|
font-weight: 500;
|
|
letter-spacing: 0;
|
|
color: var(--lgs-text-1) !important;
|
|
text-shadow: none;
|
|
}
|
|
/* the current route: the navigation selection drawn as a circle behind
|
|
the glyph (white .18 + its specular arc), glyph white, label Semibold;
|
|
never a pill, so it never shares a shape with focus. Every item carries
|
|
the circle, clear at rest, so a selection change cross-fades (the old
|
|
circle out, the new one in) on `fade` (WN §7, T1) */
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item} %{DashboardMenu>ItemIcon} {
|
|
isolation: isolate;
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item} %{DashboardMenu>ItemIcon}::before {
|
|
content: "";
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: var(--lgs-c1a-tab-d);
|
|
height: var(--lgs-c1a-tab-d);
|
|
translate: -50% -50%;
|
|
border-radius: 50%;
|
|
background-color: rgb(255 255 255 / 0);
|
|
box-shadow: inset 0 1.5px 1.5px -1px rgb(255 255 255 / 0);
|
|
z-index: -1;
|
|
pointer-events: none;
|
|
transition: background-color var(--lgs-motion-fade, 441ms ease), box-shadow var(--lgs-motion-fade, 441ms ease);
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item}%{DashboardMenu>Active} %{DashboardMenu>ItemIcon}::before {
|
|
background-color: var(--lgs-fill-nav);
|
|
box-shadow: var(--lgs-sel-arc);
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item}%{DashboardMenu>Active} %{DashboardMenu>ItemIcon} {
|
|
color: var(--lgs-text-1) !important;
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item}%{DashboardMenu>Active} %{DashboardMenu>ItemLabel} {
|
|
font-weight: var(--lgs-nav-weight);
|
|
color: var(--lgs-text-1) !important;
|
|
background: none;
|
|
-webkit-background-clip: border-box;
|
|
background-clip: border-box;
|
|
}
|
|
/* gamepad focus: the pill across icon and label (P4's nav hook adds the
|
|
uniform light, the spot and the arc); glyph and label at full white */
|
|
&:not(.lgs-input-laser) %{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item}.gpfocus :is(%{DashboardMenu>ItemIcon}, %{DashboardMenu>ItemLabel}) {
|
|
color: var(--lgs-text-1) !important;
|
|
}
|
|
&:not(.lgs-input-laser) %{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item}.gpfocus %{DashboardMenu>ItemLabel} {
|
|
font-weight: var(--lgs-nav-weight);
|
|
}
|
|
/* blocked items stay dim */
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Blocked} :is(%{DashboardMenu>ItemIcon}, %{DashboardMenu>ItemLabel}) {
|
|
color: var(--lgs-text-disabled) !important;
|
|
}
|
|
/* Steam's blue route dot: the circle replaces it */
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>ActiveDot} {
|
|
background: transparent;
|
|
}
|
|
/* the source of an open menu (Power while it is open, T2): white */
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item}[data-lgs-open] %{DashboardMenu>ItemIcon}::before {
|
|
background-color: var(--lgs-selected-fill);
|
|
box-shadow: none;
|
|
}
|
|
%{DashboardMenu}%{Variant_FrameMenu} %{DashboardMenu>Item}[data-lgs-open] %{DashboardMenu>ItemIcon} {
|
|
color: var(--lgs-text-on-selected) !important;
|
|
}
|
|
/* during a modal (T2 class on the frame-menu document): black .35 */
|
|
&.lgs-modal %{DashboardMenu}%{Variant_FrameMenu} {
|
|
filter: brightness(.65);
|
|
}
|
|
|
|
@media (prefers-contrast: more) {
|
|
%{DashboardMenu}%{Variant_FrameMenu} {
|
|
--lgs-c1a-tab-fill: rgb(11 13 16 / .94);
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* 4a. The More circle (T2 node from device/rt/20-more.js; WN §3.4.4, */
|
|
/* PLAN §1.11): 60 px visible in an 80 px hit, clear material over */
|
|
/* content (black .38 + 10 px blur), white while its menu is open */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
.lgs-more {
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
width: var(--lgs-more-hit);
|
|
height: var(--lgs-more-hit);
|
|
display: grid;
|
|
place-items: center;
|
|
z-index: 6900;
|
|
isolation: isolate;
|
|
visibility: hidden;
|
|
pointer-events: none;
|
|
/* hidden only once materialize-out has run */
|
|
transition: visibility 0s linear var(--lgs-d-mat-out, 350ms);
|
|
}
|
|
.lgs-more.lgs-more-show {
|
|
visibility: visible;
|
|
pointer-events: auto;
|
|
transition: none;
|
|
}
|
|
.lgs-more::before {
|
|
content: "";
|
|
position: absolute;
|
|
inset: calc((var(--lgs-more-hit) - var(--lgs-more)) / 2);
|
|
z-index: -1;
|
|
border-radius: 50%;
|
|
background: rgb(0 0 0 / .38);
|
|
backdrop-filter: blur(10px);
|
|
box-shadow: var(--lgs-mat-clear-shade);
|
|
transition: background-color var(--lgs-d-hover-in, 294ms) var(--lgs-ease-b0, ease-out);
|
|
--lgs-maxside: 60;
|
|
}
|
|
/* materialize (WN §7, PLAN §1.5): P5's glass channel on the circle and
|
|
the content channel on the glyph; in 250 ms, out 350 ms (the glass held
|
|
while the glyph goes). The rest state of a hidden circle is opacity 0,
|
|
so the exit needs no fill and nothing stays applied (MO R11) */
|
|
.lgs-more.lgs-more-show::before {
|
|
animation: lgs-mat-glass-in var(--lgs-motion-mat-in, 250ms linear) backwards;
|
|
}
|
|
.lgs-more.lgs-more-show svg {
|
|
animation: lgs-mat-content-in var(--lgs-motion-mat-in, 250ms linear) backwards;
|
|
}
|
|
.lgs-more:not(.lgs-more-show)::before {
|
|
opacity: 0;
|
|
animation: lgs-mat-glass-out var(--lgs-motion-mat-out, 350ms ease-out);
|
|
}
|
|
.lgs-more:not(.lgs-more-show) svg {
|
|
opacity: 0;
|
|
animation: lgs-mat-content-out var(--lgs-d-mat-out, 350ms) linear;
|
|
}
|
|
.lgs-more[data-lgs-inglass]::before {
|
|
backdrop-filter: none;
|
|
}
|
|
&:not(.lgs-input-pad) .lgs-more:hover::before {
|
|
background-color: rgb(40 40 40 / .46);
|
|
}
|
|
.lgs-more svg {
|
|
width: var(--lgs-symbol);
|
|
height: var(--lgs-symbol);
|
|
fill: var(--lgs-text-1);
|
|
}
|
|
.lgs-more.lgs-more-open::before {
|
|
background: var(--lgs-selected-fill);
|
|
backdrop-filter: none;
|
|
}
|
|
.lgs-more.lgs-more-open svg {
|
|
fill: var(--lgs-text-on-selected);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* 4b. The pointer proxy (T2 node from device/rt/20-pointer.js, native */
|
|
/* mode only; WN §3.6, PLAN §1.11, S16) */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
/* a 16 px ring (2.5 px white .95) with a 6 px white core, a soft dark
|
|
halo (blurred, never a hard line: P-43, review R2 m12) and a soft glow:
|
|
readable on bright art and dark glass. Not glass and not a control; it
|
|
never takes the pointer. */
|
|
.lgs-pointer {
|
|
position: fixed;
|
|
left: -8px;
|
|
top: -8px;
|
|
width: 16px;
|
|
height: 16px;
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
contain: strict;
|
|
z-index: 2147483647;
|
|
opacity: 0;
|
|
background: radial-gradient(circle, rgb(255 255 255 / .95) 0 3px, rgb(255 255 255 / 0) 3.5px);
|
|
box-shadow: inset 0 0 0 2.5px rgb(255 255 255 / .95), 0 0 3px 1px rgb(0 0 0 / .50), 0 0 8px 2px rgb(255 255 255 / .35);
|
|
}
|
|
.lgs-pointer.lgs-pointer-on {
|
|
opacity: 1;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* 4c. Native mode (html.lgs-native; P6's acks, PLAN §1.6): where */
|
|
/* glassd draws the shell's glass, the CSS stops painting it. */
|
|
/* Anything not acknowledged keeps its CSS glass. */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
/* the ornament: glassd's liquid plate is the capsule (tint, frost and
|
|
crescent), so the CSS capsule and its E3 hook go; labels, badges and
|
|
the members' hover and focus light stay */
|
|
&.lgs-native %{BasicUiRoot} #Footer%{BasicFooter}:has(> .lgs-orn-plate:is([data-lgs-plate-ack], :root[data-lgs-plates] [data-lgs-plate]:not([data-lgs-plate-css]))) {
|
|
--lgs-edge: none;
|
|
}
|
|
&.lgs-native %{BasicUiRoot} #Footer%{BasicFooter}:has(> .lgs-orn-plate:is([data-lgs-plate-ack], :root[data-lgs-plates] [data-lgs-plate]:not([data-lgs-plate-css])))::after {
|
|
background: none;
|
|
backdrop-filter: none;
|
|
box-shadow: none;
|
|
}
|
|
/* toolbar plates on windowless routes: the plate is the control's glass.
|
|
P6's ack rule clears --lgs-mat-plate-bg, so the CSS plate fill goes in
|
|
every state and only the hover and press adds (and the field's focus
|
|
ring) stay over glassd's plate (review R2 m6); the edge and shadow go */
|
|
&.lgs-native %{BasicUiRoot} #header :is([data-lgs-plate-ack], :root[data-lgs-plates] [data-lgs-plate]:not([data-lgs-plate-css])) {
|
|
--lgs-c1a-plate-shade: 0 0 0 0 transparent;
|
|
}
|
|
/* the tab bar: glassd's liquid cover is the two capsules; the rows'
|
|
slices stop painting, the selection circle, focus pill and labels stay */
|
|
&.lgs-native %{DashboardMenu}%{Variant_FrameMenu}:has(> .lgs-tabcap[data-lgs-cover]) {
|
|
--lgs-c1a-tab-fill: transparent;
|
|
}
|
|
&.lgs-native %{DashboardMenu}%{Variant_FrameMenu}:has(> .lgs-tabcap[data-lgs-cover]) :is(%{DashboardMenu>ItemOuter}, %{SectionGap}) {
|
|
background: none;
|
|
box-shadow: none;
|
|
}
|
|
|
|
/* 5. (the app-details overlay scrim moved to C1c's 22-presentations.css
|
|
§7 on 2026-10-07, PLAN §6 two-step move) */
|
|
|
|
/* 6. (the search route moved to C1b's 21-search.css on 2026-10-07, PLAN §6
|
|
two-step move, REQ C1b->C1a #9) */
|