89 KiB
C1c System presentations: evidence log
Package C1c (PLAN §2.4): context menus, popovers, dropdown slabs, alerts, sheets, the Power menu layout and route transitions, on main (inventory shell §0.2 recipes CONFIRM, ALERT, MENU, SUBMENU, POWER, ZOO). Concept: window-nav.md §5.1–§5.4, §7 (transitions), §9.4, §9.5, §9.7 (file owned by C1a). Steam build at the time of writing: 11094443 (no device step was needed for M0).
Status
- READY: wp.c1c (2026-10-07 20:25, R2 fix pass 1, Steam build 11094443). Review R2 M1 fixed: Cancel is now 60 visible on its 60 px element (
border: 0, background to the border box), 192 wide, 14 px clear of the last row. Re-run with--flags wp.c1a,wp.c1c(scratchc1c/run4/gates5.py, 20:20-20:25): tile menu pad all 5 gates PASS; tile laser and Power laser: SIZE, TYPE, OUTLINE, MOTION PASS, AUD has 0 C1c findings (one other-owned issue: footerActionButtonLabel "SELECT"GONE, C1a's footer); Power pad all PASS. The E-MENU Cancel line now reads "fill 192 x 60 on a 192 x 60 element ... PASS". Shotsshots/p2_c1c_r2f_tile_{pad,laser}.pngmatchp2_window-nav_menu.png(compact slab beside the card, 64 px rows, centred Cancel capsule). Also: the menu title is one line with ellipsis inside the slab (C2c REQ-16).- Correction (review R2): the earlier "0 irreversible edges" for the tile menu came from a run cut to 12 of 20 nodes by the snippet's 20 s auto-close. The reviewer's full run (20 nodes,
tile_nt.js) found 10 "irreversible" edges, all re-entry of a submenu at its first item, which is stock parity (review section 3a). The "≥ 320 wide" clause is resolved by PLAN R2-5. - Open, not blocking: 11-14 item grid scroll inside the slab (coordinator R2-6 (2)); legacy
filtersnative layer rule (C2c REQ-10c); native menu/alert backing over posters (C1a FYI); Sort menu gates are C2c's route (asked to re-run).
- Correction (review R2): the earlier "0 irreversible edges" for the tile menu came from a run cut to 12 of 20 nodes by the snippet's 20 s auto-close. The reviewer's full run (20 nodes,
- READY: wp.c1c (2026-10-07 10:25, session 4, Steam build 11094443). Milestone: M3 reached, T4 fragment written and checked natively (M4 items left: filmstrips,
cmpre-run). Evidence: "M3 evidence" below. With--flags wp.c1c: gates on the tile menu, CONFIRM, the Scroll Panel sheet (both modes) and Power (laser) give 0 C1c findings in AUD, TYPE, OUTLINE, MOTION and SIZE P-08/P-80 (no GONE, HIDDEN, SHRUNK or UNCLICKABLE); the only red lines are E-MENU's "≥ 320 wide" clause on grid rows and Cancel (PLAN conflict, REQ to the coordinator, open) and the Back label's contrast under WN §5.3's .45 modal dim (by design, D16). pad-bfs: every item of the tile menu (with its submenus), Power and CONFIRM reached, 0 irreversible edges, B closes the layer; the page under a modal is unreached by design. Native session (P7 complete): sgcheck PASS for the tile menu (onec1c-menupop at 10.0 mm), CONFIRM-D (no pop) and the sheet (onec1c-sheetpop at 10.0 mm); anhvlook showed native window glass without doubled edges, but not the menu (see the evidence row). Runtime log: no warnings or errors frommenus; with the flag off no C1c markup is left in any window (C1c-7, runtime part).- Session 4 changes:
theme/layers/22-presentations.json(new, T4);22-menus.js:html.lgs-menu-open(D34), the sheet close circle's B fallback and focus keeping (C1c-3);22-presentations.css: D34 (the menu slab now really frosts the posters under it: before, C1a'swill-changebackdrop root left them sharp), sheet close row 96 → 88 px (scroll area ≥ 300 tall, AUD). All_wipcopies equal the live files. - Open, not blocking: E-MENU clause (coordinator); behind the menu's top edge the library's tab row still reads sharp (a further backdrop root in C2c/C1a's header, not found this session); an
hvframe with a menu up needs P10's help (REQ below); filmstrips (PLAN-1c-2) and thecmpre-run were not repeated (expedited session).
- Session 4 changes:
- Session 3 (2026-10-07 07:25–, Steam build 11094443): M3 in progress. P1, P2, P3 report M3/complete, so T2 is live behind
wp.c1c(off by default):device/rt/22-menus.js(modulemenus; working copydevice/rt/_wip/22-menus.js, identical) and the T2 CSS merged intotheme/22-presentations.css§9 (working copytheme/_wip/22-presentations.css, identical). Built: count classes anddata-lgs-menu,--lgs-menu-rows,data-lgs-exempt="E-MENU"; Power glyphs and group labels from Steam's own strings (#Downloads_ThisDevice,#Menu_Steam; D29); the library Sort menu's current sort checked (data-lgs-checked, from the tab'seSortByprop) and titled with Steam's#Library_SortCollectionBy(D30); source tracking (More circle, Steam's own menu anchorm_ActiveMenu.m_position.element, pointerdown /vgp_onmenu/vgp_onoptions, frame-menu tab →data-lgs-open),data-lgs-menu-source="white|glow"; anchoring bytranslateonBasicContextMenuModal(kill switchmenuAnchor=false) and the morph start--sx..--sr;html.lgs-modal; the sheet close circle (.lgs-sheet-close,data-lgs-sheet="close"= 96 px toolbar row); destructive tags anddata-lgs-plate="thick"on destructive alerts and on windowless routes (C2a REQ #3). Live checks so far: tile menu anchored 16 px right of its card in both modes (shots/p2_c1c_tile_t2_pad.png,p2_c1c_more_t2_laser.png), AT-11b run 1 (classes right; found and fixed the grid row count losing to the:is()rule's specificity). Running: AT-11 / AT-12 / C1c-2 / C1c-3 batch (s3/at11.shin C1c's scratch, copy in/tmp/lgs/c1c/). Next: AT-11b re-run, AT-13, C1c-1, C1c-4..7, evidence rows, then M3. - Milestone reached: M2 (2026-10-07 07:15, session 2, Steam build 11094443), with one PLAN conflict left to the coordinator (E-MENU's "≥ 320 wide" clause vs §1.12's 592 px two-column slab and the Cancel capsule; REQ below). Evidence: "M2 evidence" (M2-P, M2-L, M2-A, M2-H, M2-G runs 1–3, M2-F, M2-C, M2-M); decisions D18–D28 and D6b under "M2 notes".
- Live on the device (CSS-only, T1):
theme/22-presentations.css(menus by count: ≤ 5 one column, 6 compact, 7–14 two columns incl. Power, ≥ 15 scrolling column; slab inside y 108–616; title row inside the glass; rows, tones, check slot, Cancel capsule; alerts centred on the glass; sheets ≤ 960 × 488 under the toolbar; scrim .35 clipped to the glass; text prompt) andtheme/23-transitions.css(route and tab fades on P5 tokens, no scaling or sliding). - Gates (run 3, 07:04–07:11, both modes): G-AUD 0 C1c findings, G-TYPE PASS, G-OUTLINE PASS, G-MOTION PASS (tokens only, nothing at rest), G-SIZE 0 P-08/P-80 findings (E-MENU width clause only). G-FOCUS (M2-F): row focus +59 L, button focus +70 L, white-fill glow band +34 L. G-MOCK (M2-C): sizes match the mockups; positions differ only where T2 anchors (M3).
- How to edit:
theme/_wip/22-presentations.cssis the working copy (==theme/22-presentations.cssafter the last deploy). Edit it, run scratchvalidate.py(parses the bundled file in live Chrome; keep its accumulator onglobalThis, not onL, which the lab reinstalls),glass.py check-theme, copy intotheme/,glass.py sync. Never put a:has()inside another:has()(not even through:is()): inside the bundler's nesting wrapper Chrome then drops the rest of the file. Pre snippets: scratchmk.py(parameterised inventory recipes; when passing a route from Git Bash setMSYS_NO_PATHCONV=1). Real laser hover: scratchc1crun.py(copy in/tmp/lgs/c1c/, until P10 ships a hover option).
- Live on the device (CSS-only, T1):
- Next (session 3):
- M3 as soon as
wp/P2.mdreports M3 (P1 complete, P3 M3 at 06:12; P2's status still said M1 at 07:00 although its RX tests pass): movedevice/rt/_wip/22-menus.js(draft written: classification, Power glyphs and groups, source tracking and the white source, anchoring behind flagmenuAnchor,html.lgs-modal, sheet close circle, destructive tag on Power confirmations) todevice/rt/22-menus.js, mergetheme/_wip/22-presentations-t2.css(glyph masks, source looks, close circle) into the theme, then run AT-11, AT-11b, AT-12, AT-13, C1c-1..C1c-7 in both modes. Scope the draft's MutationObserver to the modal overlay before shipping. Power group labels: design still open (pseudo-elements on the container, or appended nodes with:nth-last-child(1 of item)for Cancel). - Sheets over bright pages: the sheet's blur does not visibly frost the zoo page (evidence row "M2-open"); find the backdrop root and, if needed, a denser tint under text (REQ P4 for a token). Re-run
cmpfor the sheet (map fixed) and the band pair for the red row (P-16); motion filmstrips once P10 fixes the seek (REQ); re-measure menu5 (expected 508 at y 108–616). - Watch the open requests below (coordinator: E-MENU / D28 / Cancel; P10: hover option, gate artefacts, filmstrips).
- M3 as soon as
- Milestone reached: M0 (2026-10-07, session 1).
- The six C1c mockups are conformed to PLAN §1 and re-rendered:
shots/p2_window-nav_{menu,sort,power,alert,sheet,motion}.png. Each render was viewed and measured (Evidence below). - C1c owns no concept text. C1a's revision 3 of
window-nav.mdalready carries most of PLAN §1 in C1c's sections. The remaining deltas (decisions D1–D14 below, the updated acceptance tests and the retention rows) are written out as replacement text in Appendix A and requested from C1a (REQ 1). - Mockups of other packages that draw menus, alerts or sheets have requests for the C1c recipe (REQ 7–12).
- The six C1c mockups are conformed to PLAN §1 and re-rendered:
- Open items that do not block M0 (all filed as requests): C1a to paste Appendix A into WN and to adopt the recipe in
window-nav-shared.css/.js(REQ 1–4); P4 to set the focus-glow token (REQ 5); the coordinator to rule on E-MENU for Cancel, the P-65/P-67 deviations and the P-35 box (REQ 6); P10 to allow several mockups per cmp map (REQ 13). - (Session 1 plan, M2 done in session 2.) Write
theme/22-presentations.css(menu slab, rows, tones, count classes' CSS, alert and sheet cards, scrim .35 clipped to the glass, modal-state chrome rules) andtheme/23-transitions.css(route and tab transitions on P5'slgs-page-*). Usetheme/_wip/untilglass.py check-themepasses; read P4'scontracts/tokens.md(focus token, glow token) and P5'scontracts/motion.md(keyframe names) first. Then M3:device/rt/22-menus.js(count classes, menu type, source tracking and--sx..--sr, anchoringtranslate, destructive tags, Power groups and glyphs, sheet close circle,html.lgs-modalon every popup) behindwp.c1c. Then M4:theme/layers/22-presentations.json(+10 mm crops, destructive alerts flat, superseding the legacymenu,sheet,sheet-panelrules). - Static mockup parts to replace later: the quiet legends in
window-nav-menu/-power/-alert.htmlare static markup using C1a's.wn-orn.quiet;window-nav-sort.htmladdsmode-laserafter C1a's builder. When C1a's builder supports quiet legends and laser-mode A/B (REQ 3), switch these todata-wn="ornament"and re-render.
M0 checklist
| Step (task) | State | Where |
|---|---|---|
| 1. Concept text and owned mockups updated to PLAN §1 | Mockups done. Text: C1a owns WN; deltas requested with exact text | Mockups; Appendix A; REQ 1 |
| 2. Acceptance tests updated to §1; retention table complete | Done here, requested into WN §13 and §9 | "Acceptance tests", "Function retention"; Appendix A |
3. Mockups re-rendered with tools/mockshot.py, viewed, fixed |
Done (Evidence E1–E9) | Evidence |
| 4. REQs for mockups not owned | Filed | Requests |
| Evidence log with a Status section | This file | — |
Requests
-
REQ C1c->C1a:
window-nav.md, C1c's sections (intro mockup table rows for menu/sort/power/alert/sheet/motion, §5.1.1, §5.1.2, §5.1.3, §5.2, §5.3, §5.4, the §7 storyboard line and sheet row, §9.4, §9.5, §9.7, and §13's C1c rows): please replace them with the text indocs/phase2/wp/C1c.mdAppendix A. Why: PLAN §1 conformance of C1c's area (leading check, value-menu layout by count, Power strings and measured sizes, alerts and sheets centred on the glass, scrim clipped to the glass, P-65/P-67 notes, storyboard f points, PLAN-1c-1..3, CC A13 and C1c-1..7). C1c does not own the file. C1a answer (2026-10-07, session 2): merged A.1–A.10 into WN (intro rows, §5.1.1–§5.4, §7 storyboard, §9.4/§9.5/§9.7, §13 rows with owner C1c). Two adjustments: A.3's glow row cites P4's published--lgs-white-glow(0 0 22px 8pxwhite .55, +23 L) instead of your interim value; AT-21 and AT-23 are split into C1a and C1c parts. -
REQ C1c->C1a:
window-nav-shared.css: replace the "menus" and "alerts and sheets" blocks with the C1c recipe (the<style id="c1c-recipe">block ofwindow-nav-menu.html, minus the.c1cprefix and the.c1c.laserglyph rule). Why: area mockups that use.wn-menu/.wn-alert/.wn-sheet(home-apps-library,-library-pad,settings-dropdown) still get revision 2 values (focus .30, a trailing.chkthat pushes the check right, white labels on red, Cancel without the quiet recipe). C1a answer: adopted, scoped to.wn-menu,.wn-alert,.wn-sheetso it cannot touch other areas' buttons; the white-fill glow uses P4's token value; the.c1c.laserglyph rule is dropped (the builder hides badges in laser mode); a legacy trailing.chkrule stays only untilsettings-dropdown.htmlmoves to.lead.check. -
REQ C1c->C1a:
window-nav-shared.jsbuildOrnament: withdata-mode="laser", keep A and B as quiet members (labels only) and addmode-laser; emit.wn-orn.quietwithoutlgk-glasswhen only A and B remain. Why: PLAN §1.10; today laser mode drops A/B, so C1c's mockups draw the quiet legend statically and tag laser mode after the build. C1a answer: done (A/B quiet in laser mode since session 1; quiet legend withoutlgk-glass; dim band in the margin;data-inglassforwindow-full;data-modalrecedes the page's members). Your static quiet legends can switch todata-wn="ornament". -
REQ C1c->C1a: quiet legend legibility on
windowroutes. Its labels sit at y 640–700, mostly below the 656 glass edge, over the room. White .70 Medium is unreadable over a bright room: inp2_window-nav_alert.pngandp2_window-nav_power.png"Select" sits on the curtain (background L 236) and disappears. Proposal (safe default): onwindowroutes keep a faint capsule (theliquidmaterial at reduced strength) behind a quiet legend, or use the on-room label treatment (VP P-41: white .96 Medium with the on-room shadow); keep §1.10's look onwindow-fullroutes, where the legend sits on glass. Why: VP P-39, P-41; B must stay readable. Needs a §1.10 note if adopted. C1a answer: decided: the dim band onwindowroutes, white .82 labels, flagquietBacking(WN §3.4.1, §11 O3); §1.10's look kept onwindow-full. Measured ≥ 5.1 : 1 over the curtain (L 236). -
REQ C1c->P4: focus glow on white and coloured fills. PLAN §1.4 names
0 0 18px 2pxwhite .30, but on the alert mockup's focused primary it gives a P-16 band (8–16 px outside the capsule) of only +11.7 L (needs ≥ +20).0 0 24px 6pxwhite .34 gives +23.5 L;0 0 22px 4px.34 gives +19.0. Please set one shared token (for example--lgs-focus-glow) that passes FD-5 / G-FOCUS and record it incontracts/tokens.md; C1c's mockups use0 0 24px 6pxwhite .34 meanwhile (E8). P4 (2026-10-07): done.--lgs-white-glowis now0 0 22px 8px white .55(parts--lgs-white-glow-blur/-spread/-a), used by the--lgs-ill: whitehook; recorded in contracts/tokens.md §1.6. Measured +23 L (bright) / +27 L (dim) on C3a's bar render; your alert primary sits on darker glass, so it passes with more margin. Please use the token instead of the local 24/6/.34. -
REQ C1c->Coordinator: (a) PLAN §1.12 keeps Steam's Cancel item as a 56 px quiet capsule, but E-MENU (§1.16) covers rows "≥ 60 visible" and P-80 asks ≥ 60. Please extend E-MENU to "Steam's appended Cancel item: 56 visible on a 64 px element", or raise Cancel to 60. C1c builds 56 meanwhile, because §1.12 says so explicitly. (b) Please record two VP deviations in §4.4: P-65 (an outside click keeps cancelling alerts and sheets, because that is Steam's
ModalClickToDismissand removing it would change a function; default kept, see D9) and P-67 (alerts keep Steam's default focus, S6). (c) P-35 asks alerts and sheets to be centred on the glass ± 24 px; WN said "centred in the modal box" (centre 368, 40 px off). C1c centres them on the glass and caps sheets at 488 px tall onwindowroutes (552 onwindow-full), see D7. Please confirm.- Coordinator (2026-10-07, round R2): (a) Cancel goes to 60 visible on its 60 px element, ≥ 192 wide, ≥ 4 px clear of the last row, with its own E-MENU line (not an exemption at 56: P-80 is a must and the height is free); (b) P-65 and P-67 recorded in PLAN §4.4,
modalOutsideGuardreserved off (S30); (c) confirmed, written into §1.12 with numbers. See PLAN §1.19 R2-5, R2-6; follow-up REQ Coordinator->C1c inwp/coordinator.md.
- Coordinator (2026-10-07, round R2): (a) Cancel goes to 60 visible on its 60 px element, ≥ 192 wide, ≥ 4 px clear of the last row, with its own E-MENU line (not an exemption at 56: P-80 is a must and the height is free); (b) P-65 and P-67 recorded in PLAN §4.4,
-
REQ C1c->Coordinator: (gates run 3, 07:04–07:11: the only C1c G-SIZE failures left are these two E-MENU clauses) PLAN §1.16 E-MENU says menu rows are "≥ 320 wide", but §1.12's two-column menus are "≤ 592 px wide" (also the 600 px clip-path morph limit, R9): two columns of ≥ 320 cannot fit (2 × 320 + 8 + 16 = 664). C1c builds §1.12's 592 (columns 284 wide, Steam's own row min-width is 280) and asks to amend E-MENU to "≥ 280 wide in the two-column grid, ≥ 320 otherwise". Also (D28): §1.12's "6–7 actions: compact" cannot hold 7 compact rows plus title and Cancel in the 108–616 box; C1c gives 7 actions the grid. And Steam's Cancel, which §1.12 makes a 56 px quiet capsule (192 × 60 element here), is judged by E-MENU's row clauses; please give it its own line (with REQ 6a above). Please confirm or overrule all three.
- Coordinator (2026-10-07, round R2): all three confirmed: E-MENU rows ≥ 280 in the two-column grid, ≥ 320 otherwise; 7–10 actions take the grid and 11–14 scroll inside the slab (D28); Cancel has its own E-MENU line, at 60 (PLAN §1.12, §1.16; §1.19 R2-5). P10 is asked to change the criterion (REQ Coordinator->P10 in
wp/coordinator.md).
- Coordinator (2026-10-07, round R2): all three confirmed: E-MENU rows ≥ 280 in the two-column grid, ≥ 320 otherwise; 7–10 actions take the grid and 11–14 scroll inside the slab (D28); Cancel has its own E-MENU line, at 60 (PLAN §1.12, §1.16; §1.19 R2-5). P10 is asked to change the criterion (REQ Coordinator->P10 in
-
REQ C1c->C1a: the More circle cannot be clicked with the real laser. Live run 2026-10-07 07:52 (build 11094443),
--flags wp.c1c,wp.c1a,wp.p3 --mode laser, with a test-only registration__LGS_RT.more.register('%{CSSGrid} %{LibraryItemBox}', {placement: 'card'})(removed after the step): a CDP hover on the first poster for 700 ms showed.lgs-more.lgs-more-show(80 × 80 at 140, 163 CSS px); a CDP move + press + release at its centre (180, 203) reached the poster instead: Steam opened the game page (no launch; the lab restored the route). Likely cause: the circle is a body-level node, so moving onto it firesmouseouton the host; thert.attendregistration has noleaveMs, soonLeavehides the circle before the press lands. Suggestion:leaveMs≈ 300 with the circle counted as part of its host (ignore a leave whoserelatedTargetis the circle), or keep the circle shown while:hover. A syntheticL.click('main', '.lgs-more')works (menu opens, circle white, C1c anchors to it), so only the real laser path is affected. Why: WN §3.4.4, PLAN §1.11; C6 in §9.5 (laser path of "open the menu of the thing I looked at").- C1a answer (2026-10-07 08:16, session 4): done.
20-more.js: leaving the host no longer hides the circle at once; the hide waits 220 ms and is dropped while the pointer is on the circle (pointer/mouse enter on the node) or back on the host; leaving the circle for anything but its host hides it after the same grace. Re-run of your path with the real laser (/tmp/lgs/c1a/c1amore.py: CDP hover on the first%{CSSGrid} %{LibraryItemBox}700 ms, 4 moves onto the circle at (180, 203), press + release): the circle stayed shown and:hover, the poster's menu opened from the circle (circle white), route unchanged. Evidence inwp/C1a.mdsession 4.
- C1a answer (2026-10-07 08:16, session 4): done.
-
REQ C1c->C3b:
control-center-power.htmlandcontrol-center-power-confirm.htmlstill show revision 2 values. Per PLAN §1.12, §1.7, §1.8 and S6: the Power menu is WN §5.2's two-column slab, 592 px wide (seewindow-nav-power.html), at +10 mm, with Steam's default focus, and the focused row a red whole fill with a #0d0e12 label. The Power confirmation is flat (0 mm: it holds a destructive button), its confirm capsule red with a #0d0e12 label, and focus stays where Steam puts it (not moved to Cancel). The dim is the scrim at .35 clipped to the glass (not1), and the search field has no microphone. Please align these mockups, or crop them to CC's entry point and point towindow-nav-power.html/window-nav-alert.html. -
REQ C1c->C2c:
home-apps-library.html(tile menu at +30 mm),home-apps-library-pad.html,home-apps-filter.html: menus at +10 mm (PLAN §1.7); layout by count (6 actions compact, 5 one column of 72 px); Cancel a 56 px quiet capsule (superseded by PLAN R2-5: 60); laser hover = + .08 and a spot (not the focus look); the source card at 0 with a glow unless it was the gamepad-focused card; the Filters sheet ≤ 960 wide, centred on the glass, at +10 mm. The recipe is thec1c-recipeblock inwindow-nav-menu.html.- C2c (2026-10-07, R2 fix pass): done in C2c session 1 (M0) and updated in R2: the three mockups draw menus at +10 mm, the tile menu in the compact layout (6 actions), Cancel as a 60 px quiet capsule (R2-5 supersedes 56), laser hover + .08 and a spot, the source poster at 0 with a glow (rule 6, R2-3), and the Filters sheet at 960 x 488 from y 108 (your D7) with the title centred in the close circle's row; re-rendered
shots/p2_home-apps_library.png,_library-pad.png,_filter.png.
- C2c (2026-10-07, R2 fix pass): done in C2c session 1 (M0) and updated in R2: the three mockups draw menus at +10 mm, the tile menu in the compact layout (6 actions), Cancel as a 60 px quiet capsule (R2-5 supersedes 56), laser hover + .08 and a spot, the source poster at 0 with a glow (rule 6, R2-3), and the Filters sheet at 960 x 488 from y 108 (your D7) with the title centred in the close circle's row; re-rendered
-
REQ C1c->C6a:
settings-dropdown.htmlandsettings.md§4.5–§4.6, §5: dropdown slabs pop to +10 mm (PLAN §1.7 replaces SET §5's 0 for menus, popovers and dropdown slabs; list pages stay at 0). Cancel is a 56 px quiet capsule (§1.12; SET says 60). Layout is always by count: an 8-option value menu takes the two-column grid, because 8 rows of 72 px need 624 px. The leading check is kept and C1c adopts it for every menu.settings-dialog.html: alerts at +10 unless destructive (0), centred on the glass, with #0d0e12 text on red fills. C6a (R2 fix 1, 2026-10-07): adopted in the build (C6a log D8): menus, popovers and dropdown slabs are C1c's at +10 mm, alerts +10 / destructive 0, list page 0, layout by count, leading check. C6a now tags the destructive confirms of settings dialogs (label scan on the top modal card plus the.Primaryof a dialog opened from a tagged button) and calls yourscan(), sotagDestructiveflattens them (review R2 B1). Cancel: 60, not 56 (PLAN R2-5 supersedes that point). Concept text and mockups follow at C6a's M0 re-render (open). -
REQ C1c->C4a:
controls.md§8.2 andcontrols-pickers.html: value-menu depth +10 mm (PLAN §1.7; the 2 mm material-only slab is withdrawn); the current value's check in the leading 28 px slot (C1c rule; the mockup already draws it there, the text says trailing); Cancel a 56 px quiet capsule (superseded by PLAN R2-5: 60).- C4a (2026-10-07, M0): done.
controls.mdrev 3 §8.2, C-D16, §14: menus +10 mm non-interactive over athickslab (the 2 mm slab withdrawn), the check in the leading 28 px slot, Cancel a 56 px quiet capsule (superseded by PLAN R2-5: 60);controls-pickers.html,-timezone.htmland-steamvr.htmlnow draw the leading check and the 56 px Cancel (re-rendered and viewed).
- C4a (2026-10-07, M0): done.
-
REQ C1c->C5a:
game-pages-manage.html,-manage-sub.html,-playfrom.html,-running-exit.html,-vrbind-confirm.html: menus at +10 mm; Cancel a 56 px quiet capsule (superseded by PLAN R2-5: 60) (GP §3.4 says 60); destructive rows by the count rule, with a #0d0e12 label on the red focus fill; confirmations that hold a destructive button (for example "Exit game?") stay flat at 0 mm; laser hover vs gamepad focus as PLAN §1.4. GP §3.4's placement order is adopted unchanged. — C5a: adopted (C1c slab, +10 mm, Cancel 56, flat destructive alerts; C5a-D7). -
REQ C1c->C7:
social-media-people-menu.html,social-media-people-depth.html: draw the friend menu with the C1c recipe: +10 mm, layout by count, Cancel 56 quiet, hover vs focus looks, destructive rule by count, #0d0e12 on red focus fills. -
REQ C1c->P10:
glass.py cmpreads onedocs/phase2/wp/<PKG>-cmp.jsonwith a singleroute/pre/map. C1c compares five mockups (menu, sort, power, alert, sheet), and each needs its ownpre(MENU, the Sort snippet, POWER, CONFIRM, ZOO). Please accept{"mockups": {"window-nav-menu": {surface, route, pre, map}, …}}(or a--map KEYoption) and document it incontracts/lab.md. The proposed map is under "Live selectors for cmp" below.- P10 (2026-10-07 06:00): done.
glass.py cmpaccepts{"mockups": {"<stem>": {surface, route, pre, mockOrigin, mockScale, map}}}, chosen by--nameor the mockup's file stem; top-level fields are defaults; a map value may be{sel, surface, mockOrigin, mockScale}; selectors take@text=,@last,@nth=N. A repeateddata-idkeeps its first occurrence. contracts/lab.md §3.
- P10 (2026-10-07 06:00): done.
-
REQ C1c->P10:
lab/exemptions.json: please add"E-MENU": ["%{*BasicContextMenuModal>contextMenuItem}"]and check it against PLAN §1.16's criterion (visible ≥ 60 on a contiguous pitch ≥ 64 compact or ≥ 78 regular, ≥ 320 wide; Steam's appended Cancel item 56 visible on a 64 px element until the coordinator answers REQ 6a). Why:gatesSIZE fails every compact menu row on P-08 (the 80 px box reaches the next row by design: 64 px contiguous pitch), live run 2026-10-07 on the tile menu (gates main --pre <tile> --mode pad: 6 rows "hit 81 % own, 19 % other"). C1c's T2 will also tag rowsdata-lgs-exempt="E-MENU"at M3, but M2 is CSS-only.- P10 (2026-10-07 06:35): done:
E-MENUadded; criterion checked per row: visible ≥ 60, ≥ 320 wide, pitch to the next row ≥ 64 (the last row has none). Steam's 56 px Cancel fails it until the coordinator answers your REQ 6a (then I change the criterion).
- P10 (2026-10-07 06:35): done:
-
REQ C1c->P10: a real laser hover in lab steps.
L.hoverdispatches untrusted events, so CSS:hover(and P4's--lgs-hover,.lgs-dwell:hover) never applies; C1c-1, AT-8c and every laser look need CDPInput.dispatchMouseEventon the surface's own target. P3 and C1c each wrote a private runner (C1c's:lab.Lock+lgs.Session, scratchc1crun.py, copy in/tmp/lgs/c1c/). Please add it to the lab, for example--hover SEL[,DWELL_MS]as a step option applied after--pre(and pointer back to (1400, 900) at the lock exit), orL.mouse(surface, x, y)routed through CDP. Why: G-FOCUS/G-AUD in laser mode must see the real hover look.- P10 (2026-10-07 06:35): done: real CDP hover (
Input.dispatchMouseEventon the surface's own target): step option--hover SEL[,MS](applied after the command's--pre, on its surface:js,shot,audit,gates,focus,cmp,conformance),--pre "@hover SEL[,MS]", andfocusstates"@hover SEL[,MS]"/"@unhover"; the pointer goes to (1400, 900) at the lock exit. Verified: the targetmatches(':hover')inside the step, not after it. contracts/lab.md §1.
- P10 (2026-10-07 06:35): done: real CDP hover (
-
REQ C1c->P10: three
gatesfalse positives on modal surfaces (C1c's runs 2026-10-07 06:00–06:10, JSON in C1c's scratch, summarised under Evidence M2-G). (a) SIZE while a modal is open: page controls covered by the modal are swept and fail P-08 against the modal's rows (LibraryItemBox … hit 0% own, 99% other (contextMenuItem …)); please skip controls outside the topmost.ModalOverlayContent.activewhile one is shown (they cannot be reached). (b) OUTLINE edge probes on fills: focused or coloured menu rows (translucent fill, radius ≥ 16) are probed as glass; with no edge at all their quarters are flat (dL 1.7–4.3 L) and the ratio comes out 0.7–0.9, a FAIL. Please ignore a probe whose brightest quarter is below ~8 dL (no visible edge, so no ring), or skip elements withoutbackdrop-filter. C1c paints coloured fills as image layers meanwhile, so they stop counting as glass. (d) AUD CONTRAST of text over a sibling's glass: the backdrop model composites only the text's ancestors, so a menu title that sits on the slab (its sibling's child, D21) is judged against the bare room:CONTRAST text BasicContextMenuHeader "Power" 14.7 -> 1.3(run 2, 06:25), while the pixels of the same title on the device measure 4.9 : 1 (shotp2_c1c_power_focus_pad.png, 97th/15th percentile relative luminance in the title box). Please take the backdrop fromelementsFromPointat the text's centre (the first non-ancestor painted element under it), or accept adata-lgs-backdrophint. (c) AUD SHRUNK on scroll containers: a sheet capped at PLAN §1.12's 960 px reportsSHRUNK ctl %{ScrollPanel} 1232x550 -> 960x428; please exempt scrollable containers whose result stays ≥ 300 × 300 (P-08 is about small targets), or tell me the exemption id to use.- P10 (2026-10-07 06:35): done: (a) while a
%{*ModalOverlayContent}is active, SIZE and TYPE skip what lies outside the topmost one (listed asskipped: under modal) and OUTLINE does not probe it; (b) an edge whose brightest quarter is under 8 dL isedge: "none"and passes (no visible line, no ring); (c) AUD lists a scroll container that stays ≥ 300 × 300 underexempt(scroll-container) instead of SHRUNK.
- P10 (2026-10-07 06:35): done: (a) while a
-
REQ C1c->P10:
glass.py motionfilmstrips show no intermediate state. C1c's four runs (06:36–06:45: menu morph, alert, sheet, route; the pres return as soon as the node mounts) reportseeked: 5per frame and a correct token audit, but every frame from f = .15 to 1 is the end state (the menu run wrote byte-identical PNGs for .15, .35, .5, .75 and 1), and f = 0 is the route before the pre. Likely the seek of the paused CSS animations/transitions is not rendered beforePage.captureScreenshot(produce a frame after settingcurrentTime, e.g. wait tworequestAnimationFrames, or seek over CDPAnimation.seekAnimations). Needed for PLAN-1c-2 / G-MOTION's filmstrip verdicts. Files:shots/p2_motion_c1c_*.- P10 (2026-10-07 08:15): done (review R1 M1):
motionnow pauses what the pre starts in the same evaluation, seeks, and waits two rAFs before each capture.motion main --route /library/home --selftest 300(two linear boxes, WAAPI + CSS transition): f 0/.15/.35/.5/.75/1 measured 0/.149/.349/.498/.749/1.000 on both (max error .002). Please re-run your four strips; the earlier ones lag their f by ~100 ms.
- P10 (2026-10-07 08:15): done (review R1 M1):
-
REQ C1c->P6:
theme/05-native.css§3 "menus and sheets": it zeroes the Phase 1 tokens (--lgs-thick-bg,--lgs-panel-sheen,--lgs-glass-rim) on poppedcontextMenuContentsandModalPosition > *, but C1c's22-presentations.csspaints these slabs and cards with P4's--lgs-mat-thick-bg,--lgs-mat-thick-blurand--lgs-mat-thick-shade(tokens.md §1.8 asks for exactly this). Please also set--lgs-mat-thick-bg: transparent; --lgs-mat-thick-blur: none;(and keep the shade/edge decision yours) on those[data-lgs-pop~="self"]nodes, and on[data-lgs-plate]flat modals. Why: otherwise native mode draws the CSS glass under glassd's slab (double glass, P-45). Needed for C1c M4 only. P6 (2026-10-07): done:05-native.css§4 zeroes the--lgs-mat-*-bg/-shadetokens and--lgs-edgeon acked pops and plates, and acked plates also lose fill, shadow, blur and the-blurtokens; popped menus and sheets keep their in-page blur by design (contract reporter.md §8). -
REQ C1c->C4a:
theme/10-primitives.css§8 (context menus and dropdown menus) and §9 (modals: scrim and sheet): please delete them; C1c'stheme/22-presentations.cssnow carries both (PLAN §6 migration row for10-primitives.css). Why: the.menuChecked::aftercheck mark of §8 lands on the::afterlight layer that P4's--lgs-illhook draws on menu rows (C1c works around it by keeping checked rows off the hook), and §8/§9's!importantfocus fills, 140 ms transitions (--lgs-t-fast, not a token) and the menu scrim blur are dead weight that C1c has to out-specify. Keep §1 (DialogButton) until your M2 rewrites buttons; C1c styles only buttons inside alert footers and sheets.- C4a (2026-10-07 06:33): done. Phase 2
10-primitives.css(live since 05:48) no longer has any menu, modal, scrim or.menuCheckedrule, no--lgs-t-fastand no ring; its §10 keeps only the rich pop-up label colours inside menu rows (DropDownLabelTitle/…Descriptioninherit the row colour) and.DialogSubHeader/.DialogControlsSectionHeaderoutsideModalPosition. DialogButtons are C4a's §1 (alert-footer.Primaryblue /.Destructivered with dark label inside.DialogFooter,%{ModalButtonRow},.DialogTwoColLayout); your alert rules may refine them.
- C4a (2026-10-07 06:33): done. Phase 2
-
REQ C1c->C4a: (information, no action needed unless you object) C1c's
theme/layers/22-presentations.jsonnow supersedes the legacy layerbutton(button.DialogButton.gpfocus, lift .005 = 1.84 mm) whilewp.c1cis on. Why: native sgcheck 2026-10-07 09:57 with CONFIRM-D failed R2 (1.84 mm is not in PLAN §1.7's {0, 10, 15, 25}) and R4 (it popped the red button of a destructive confirmation, PLAN-1c-1); PLAN §1.7 keeps in-window controls at 0. If C4a wants a focused-button depth outside dialogs, add it in your own fragment withmm(it then goes through the admission rules). -
REQ C1c->C1a: (information; please object if it breaks your ornament)
theme/22-presentations.css§8 now setswill-change: autoon%{MainNavMenuMainSplit}whilehtml.lgs-menu-open(C1c's T2, a context menu is open) orhtml.lgs-modal(an alert or sheet) is set (D34). Why: yourwill-change: opacitybackdrop root (20-shell.css) kept the page out of the menu slab's backdrop: the posters showed sharp through the thick slab, and the compact title failed P-39 over the white tab pill (A/B shots in session 4; gates tile laser OUTLINE 0.59 → 0.27, AUD 1 → 0 after the change). Outside modals your hint is untouched. Also: behind a menu's top edge the library tab row (%{GamepadTabbedPage>Tab}titles) still reads sharp, so something on the header/tab row still isolates it from the backdrop; if you know the property, a modal-time exception there would finish the frost.- C1a answer (2026-10-07, R2 fix pass): no objection: your modal-time
will-change: autoon%{MainNavMenuMainSplit}keeps the ornament working (the capsule frosts the page from#Footer, outside that root). Nothing else in20-shell.cssmakes a backdrop root above the library tab row:#header::before(blur + mask) is a sibling layer, not an ancestor of the row. The remaining candidate is the row's own 3D context (%{TabHeaderRowWrapper}, preserve-3d, C2c's), so please ask C2c.
- C1a answer (2026-10-07, R2 fix pass): no objection: your modal-time
-
REQ C1c->P10: an
hvstep that keeps a lab layer open for the capture (for examplehv NAME --pre JS, run underlab.lockwithkeepuntil the frame is taken, then the usual restore). Why: AT-14 / G-HV want a headset-view look with a menu or alert up; a menu opened by a separatejsstep is closed by other agents' step restores (or never seen) beforehvgetslab-vr.lock(3 tries in session 4, 09:58–10:05).- P10 (2026-10-07 session 4): done:
hv NAME --pre JS(or"@hover SEL[,MS]",--surface S), with--route Rand--settle S(default 0.8): the step takes lab.lock then lab-vr.lock, runs the route and the pre, waits, grabs (twice, REQ P7->P10), and only then gives the usual restore (what the step opened is closed, pointer to (1400, 900)); Steam step options apply. Example that worked live (11:00, CSS-only):python glass.py hv p10_s4_g2 --look --pre "<shell §0.2 CONFIRM with a 15 s self-close>": the frame showed "Glass Shell lab dialog" over Home on the window glass; looked at, deleted on both machines. contracts/lab.md §4hvstep 3.
- P10 (2026-10-07 session 4): done:
Requests to C1c, handled
None so far: grep -n "REQ [A-Za-z0-9]*->C1c:" docs/phase2/wp/*.md found nothing at the start (04:21) or the end of session 1.
Session 2 (05:03), the grep found two:
C2c.mdREQ-6 (menu anchoring and sheet frame): done, marked[x]there with the answer: T1 holds menus in y 108–616; the sheet frame moves to y 108, ≤ 960 × 488 onwindowroutes (centre within 24 px of the glass centre, P-35).C1b.mdREQ #8 (search sheet depth rules): accepted, answered there; it lands with C1c's M4 fragmenttheme/layers/22-presentations.json(next round), so it stays open.- End of session 2 (07:23), the grep found three more:
C1a.mdre-render the five mockups (done,[x]there),C1a.mdtake the app-details overlay scrim from20-shell.css§5 (done:22-presentations.css§7, scrim colour + no blur; live 07:35;[x]there),C2a.md#3 plates for menus/alerts/sheets onwindowlessroutes (accepted for the M4 fragment, answered there, open). - Related, not addressed to C1c:
C2c.mdREQ-7 to the coordinator (PLAN §1.7's "+15 source card" row contradicts admission rule 6). C1c agrees with C2c and changes D6 to the safe default (see D6b below).
Decisions taken at M0 (PLAN §1 applied to C1c; §1.17 rule where §1 is silent)
| # | Topic | Decision | Source | Changed in |
|---|---|---|---|---|
| D1 | Laser vs gamepad looks in menus | Laser: :hover under lgs-input-laser = + .08 and a .12 spot at the pointer, no arc, no lift. Gamepad: .gpfocus / %{Focused} under lgs-input-pad = + .28, a static .16 spot in the upper third, the row's arc ×1.5. WN rev 2's "hover moves Steam's focus, so hover looks the same" is withdrawn |
§1.4; IM D-7 [PROVEN] | menu, sort (laser), power, alert, sheet (gamepad) |
| D2 | Checked value | A check (24 px, stroke 3) in the row's leading 28 px slot, no fill; every row of a value menu reserves the slot. Reconciles WN/CTL text (trailing) with SET §4.5, the CTL and SET mockups and visionOS menus | §1.12 (C1c owns value-menu look, §1.1) | sort |
| D3 | Text on coloured fills | #0d0e12 label and glyph on green and red (Play row, focused destructive row, red confirm); white only on blue (Install, Primary). The row's glyph takes the label's colour | §1.12, CC §7 | menu, power, alert inset |
| D4 | Focus on a coloured or white fill | Blurred outer glow; the mockups use 0 0 24px 6px white .34 because §1.4's value fails its own P-16 band criterion (E8; REQ 5) |
§1.4, VP P-16 | power, alert |
| D5 | Cancel | Steam's item kept as a 60 px quiet capsule (R2-5; was 56): white .08, Medium 22 px white .70; grid menus drop the extra 6 px margin (the row gap separates it) | §1.12, HA-11 | all menus; REQ 6a |
| D6 | Source card while its menu is open | Laser (opened from the More circle): the hover ended, so the card is 0 mm with a CSS glow and the 60 px More circle is white. Gamepad (☰ on the focused card): the card keeps +15 | §1.7 table, §1.11 | menu |
| D7 | Alert and sheet position | Centred on the glass (VP P-35 ± 24), not on the 108–628 modal box: alert centre y 328 on window routes (360 on window-full); sheets top-aligned at 108 and ≤ 488 tall on window routes (≤ 552 on window-full), content scrolling inside. T1 pads ModalPosition's bottom (never its top/bottom position) |
VP P-35; LAB never-touch list | alert (centre 328.4), sheet (centre 344) |
| D8 | Scrim | Steam's .ModalOverlayBackground at black .35, no blur, in both modes, clipped to the route's glass shape (window: 1280 × 656 r 54; window-full: 1280 × 720; windowless: the whole quad r 54), so the ornament margin and corners never darken the room. Menus: no scrim. No t1 |
§1.8 | alert, sheet |
| D9 | Outside click on alerts and sheets | Kept as Steam's (cancel), with B. VP P-65 says an outside click should not close alerts and sheets; removing Steam's dismissal would change a function, so the safe default keeps it. A guard flag modalOutsideGuard (off, not built at M0) is reserved should the coordinator decide otherwise |
§1.17 rule; VP P-65; REQ 6b | text only |
| D10 | Default focus | Steam's everywhere (Power: Restart Steam VR, its preferred focus; ConfirmModal: the Primary). P-67 deviation recorded | S6 | power, alert |
| D11 | Layout by count also for value menus | "Up to 8 options: a slab anchored to its capsule" is placement; layout still follows the count table (≤ 5 one column, 6–7 compact, 8–14 grid, ≥ 15 scrolling column; settings routes > 8: C6a's list page). 8 rows of 72 px need 624 px > 520 | §1.12 | text only (REQ 1, 9) |
| D12 | Power strings | Steam's live labels: Sleep, Shutdown, Restart Device, Restart Steam VR, Change Account, Sign Out, Restart Steam, Cancel (inventory shell §4, social §8). Group labels "This Device" and "Steam" are new T2 strings, drawn only when the UI language starts with en; otherwise space separates the groups |
§1.15 | power |
| D13 | Menu headers | Steam's own header text is kept (Power: "Power"; tile menu: the game's name, inline in compact). Steam leaves the Sort menu's header empty; T2 copies the source's own label ("Sort By", Steam's Y legend string). Settings dropdowns copy the row's label (SET §4.5) | §1.15 | sort |
| D14 | Motion storyboard | Re-scoped to C1c's interactions (menu morph-open, alert present, sheet present, sheet dismiss, route change) and sampled at the G-MOTION points f = 0, .15, .35, .5, .75, 1. The search sheet (C1b) and the toast (C3a) left the board | §1.5, §2.3 P10 motion, D2 §11.9 |
motion |
| D15 | Morph start rect; glassd's part | clip-path cannot reach outside the slab, so T2 carries the source rect to the slab's nearest edge at the source's height (tile menu: a 60 × 60 r 30 start at the slab's left edge level with the More circle). glassd v3 has no morph (contracts/glassd.md §6): in T5 the slab materializes in place on its phase while the CSS clip-path draws the morph, and on close glassd dematerializes it (CSS close is instant, MO R4) |
MO §6.4, R9; glassd contract §6 | motion |
| D16 | Chrome while a modal is open | Toolbar contents .45 (clickable), the tab bar darkened, the ornament lit. The tab bar sits in another popup, so C1c's T2 sets html.lgs-modal on every popup while main's ModalManager holds an alert or sheet; C1c's CSS keys on it. No C1a file is touched |
WN §5.3; §1.8 | alert, sheet |
| D17 | Tile menu content on this device | An uninstalled game: Install (blue) + Add to Favorites, Add to ›, Manage ›, Developer ›, Properties... = 6 actions → compact. An installed game has no primary in Steam's menu (inventory library §7) → 5 → one column of 72 px rows. Steam's separator before Properties... becomes 6 px of space | §1.12; inventory library §7 | menu |
New strings (PLAN §1.15) for V2's list: "This Device", "Steam" (Power group labels, English only). Copied, not new: "Sort By" (Steam's legend), dropdown headers (the row's label), "Options" (C1a).
M2 notes: live DOM facts and T1 decisions (session 2, Steam build 11094443)
Live facts (outlines and computed styles of MENU, POWER, the Sort menu, CONFIRM, ZOO('Scroll Panel Test'), ZOO('Text Prompt'), 2026-10-07):
- Menus:
ModalPosition(no standard padding) >ModalClickToDismiss+BasicUIContextMenu.%{BasicContextMenuModal}(abs inset 0, flex column, centred) > header (18 px, centred,:emptyhidden) +BasicContextMenuContainer(flex row,overflow: hidden,max-width: 70%, Steam's .5 s opacity + scale entrance, fill both) >contextMenuContents(flex column,overflow-y: auto,position: relative, width 280) > items (position: relative, 16 px / 400, 280 × 48,::before/::afterfree). Steam's focus =%{Focused}+.gpfocustogether. - The Sort menu is
role=listbox/role=option, has no title and no mark on the current sort (aria-selected="false"on all; only Steam's preferred focus lands on it). A T1 check is impossible there; T2 must read the current sort (D13). - Power: 7 actions (6
%{Destructive}) + 2 separators + Cancel; no group markers in the DOM. - The tile menu (uninstalled game, developer mode): Install (
.Install, Steam's own glyph), Add to Favorites, Add to ›, Manage ›, Developer ›, Properties... = 6 actions. - Dialogs:
ModalPosition.WithStandardPadding(padding 24; top =--basicui-header-height40, bottom = footer 42 withFooterVisible) >ModalClickToDismiss, a zero-size%{FocusRingRoot}, and the card%{GamepadDialogContent}.GenericConfirmDialog(660 wide, 2 px border,margin: auto). Custom content (zoo Scroll Panel) is adiv.Panelstraight inModalPosition. - Transitions: route
TopLevelTransitionEnter/EnterActive (600 ms + 200 delay, scale .95 → 1) and Exit/ExitActive (200 ms); tab content%{GamepadTabbedPage>ContentTransition}with%{GamepadTabbedPage>Enter|EnterActive|Exit|ExitActive}underLeft/Right(slide ± 40 %, 320 ms + 80 delay; exit 80 ms ∓ 10 %). L.hovercannot produce CSS:hover(untrusted events). Laser looks were verified with C1c's runnerc1crun.py(CDPInput.dispatchMouseEventon main's target insidelab.Lock; REQ to P10 above).
T1 decisions (PLAN §1.17 rule where §1 is silent):
| # | Topic | Decision | Why |
|---|---|---|---|
| D18 | Layout by count in T1 | CSS :has(> :nth-child(N of item)) gives the count classes' layouts without the runtime (column ≤ 5, compact 6–7, grid ≥ 8, scroll ≥ 15). Rows read the slab's --lgs-c1c-l through a style query. T2 classes (lgs-menu-*, data-lgs-menu) take over at M3 |
CSS-only must already ship PLAN §1.12; no flash before T2 runs |
| D19 | Power without T2 | T1 recognises Power as ≥ 6 actions with > 2 destructive rows and gives it the grid; R = ceil(7 / 2) = 4 puts the column break exactly between Steam's two groups. Group labels and glyphs stay T2 | S24 in CSS-only mode |
| D20 | Grid placement | grid-auto-flow: column, R rows of 72 + one row for Cancel; Steam's separators are placed in Cancel's row under it (no cell, nothing drawn, no position change) |
Column-major in Steam's DOM order (WN §5.1.1) |
| D21 | Menu title row | Steam's header element is pulled into the slab's top padding (margin-bottom: -41px, position: relative; z-index: 1 without offsets, so it paints above the slab), left-aligned to the slab through the slab-width variable |
Title inside the glass (WN §5.1.1); the header holds no control |
| D22 | Container clipping | BasicContextMenuContainer: overflow: hidden → overflow: clip + overflow-clip-margin: 40px, its .5 s entrance → none (the morph plays on the slab) |
Lets the 10 mm shadow and focus glows show; the container never scrolls (its slab does); MO R1 (no opacity on a parent of glass) |
| D23 | Cancel size | 56 visible inside a 64 px element (4 px clear border), min-width 184 | G-AUD SHRUNK: Steam's Cancel is 280 × 48; the capsule must keep ≥ 85 % of that area (167 × 64 measured 79 %) |
| D24 | Title colours | Compact inline title and menu section headers white .70 (WN said .50) | G-AUD CONTRAST: .50 measured 3.5 : 1 over a bright room (P-39) |
| D25 | Checked rows and the light hook | .menuChecked rows paint hover/focus light on their own background10-primitives.css §8/§9 (REQ answered 06:33), so checked rows take P4's ::after light like every row |
— |
| D26 | Alerts vs sheets | Alert = ModalPosition holding Steam's dialog card (640 wide when GenericConfirmDialog); sheet = any other content (not the card, the click-away layer, the focus-ring root or a menu): ModalPosition padding holds it in x 160–1120, y 108–596 (window routes) |
Structure, not size, is what CSS can see |
| D27 | Route and tab transitions | Only transition-* changes: content fades on page (route, 40 ms delay) or hover-in (tabs: Steam's tab timeout is shorter), exits in 150 ms linear; Steam's transform change (route scale, tab slide) is made instant while the content is invisible |
No setting of transform/opacity on Steam's transition nodes (inventory shell §8); no scaling or full-width slides (WN §7) |
| D6b | Source card while its menu is open (amends D6) | The source card is at 0 mm with a CSS glow in both input modes; it keeps no +15 | Safe default: PLAN §1.7 admission rule 6 and P6's reporter drop every in-page pop while a modal is open, and a +15 source would stand in front of its own +10 menu (C2c REQ-7 to the coordinator) |
| D34 | Page backdrop root while a modal is open (session 4) | While a menu (html.lgs-menu-open, T2) or an alert or sheet (html.lgs-modal) is open, 22-presentations.css sets will-change: auto on %{MainNavMenuMainSplit}, lifting C1a's backdrop-root hint for that time only. Native fragment: theme/layers/22-presentations.json (menus, alerts, sheets +10 mm over a thick slab, modal: true, hole auto; destructive confirmations flat; legacy menu, sheet, sheet-panel, filters, button superseded under wp.c1c) |
A/B shots: with the hint the slab tinted the posters but did not blur them (P-39 contrast 1.3 on the title); the thick material must frost (PLAN §1.6). Modal-state chrome is C1c's (D16 precedent); C1a informed by REQ |
| D28 | The 508 px menu box | The slab stays inside y 108–616 (C2c REQ-6). Measured live, WN's sizes overflow it: a 5-action menu with a title was 522 tall, 7 compact rows 564. So: the title row is 36 px (slab padding-top 44), separators take no height (the slab's two 6 px gaps are the group space), Cancel is a 60 px element (56 visible, 2 px clear border, min-width 192 for G-AUD), and 7 actions take the two-column grid (Power's 7 included, so the separate Power rule is gone). Result: ≤ 5 → ≤ 508, 6 compact → 502, 7–10 grid → ≤ 508; 11–14 grid rows exceed the box and scroll inside the slab | WN §5.1.1's own heading ("no menu scrolls") over its 6–7 row; PLAN §1.12 lets layout follow fit |
Acceptance tests (conformed to PLAN §1; to replace C1c's rows in WN §13)
All steps use LAB's locked atomic forms with P10's options (--flags wp.c1c, --mode laser|pad, --media), FocusApplicationRoot() first in gamepad sequences, the pointer back to (1400, 900) after a hover, and never press A on Steam's nodes, confirm, launch, change a setting or pick a power item. Synthetic menus and dialogs come from inventory shell §0.2. Native steps run in glass.py native-session.
| Id | Test | How | Pass |
|---|---|---|---|
| AT-8c | Focus vs checked (menus) | MENU pre with a CheckItem (checked) and focus on the next row, --mode pad; glass.py focus pairs |
Focus ≥ checked + 15 L and ≥ rest + 40 L; the checked row has no fill; the check sits in the leading slot |
| AT-11 | Menu anchor and dismiss (gate R13) | MENU pre via showContextMenu(menu, anchorEl) with a known source; slab and source rects; a CDP click on %{*…>ModalClickToDismiss} outside the slab; then the same with wp.c1c off: L.pad order down/up through the items |
Slab edge 16 ± 2 px from a card source (P-35: gap ≤ 40); ornament sources: left edges aligned (± 2), bottom ≤ 620; m_rgModals.length restored; the D-pad visits the same items in the same order with T2 on and off. Else: centred placement ships (still morphing) |
| AT-11b | Menus fit | MENU pre with 5, 6, 7, 8, 10, 14 and 15 items; the Sort snippet on AllGames (look only, then B); Downloads Options if an item exists (look only); POWER (look only) | The class matches the count table (≤ 5 none, 6–7 lgs-menu-compact, ≥ 8 lgs-menu-grid, ≥ 15 value options lgs-menu-scroll); scrollHeight == clientHeight up to 14; Cancel inside the slab; slab ≤ 520 tall and ≤ 600 wide; 15: one scroller of two-line rows in a 560 × 520 slab with the current value in view |
| AT-12 | Grid menus' D-pad and default focus | POWER and the Sort menu (look only): contextMenuContents's nav node m_Properties.layout; L.focused() right after open, with wp.c1c on and off; L.pad down/right/up/left |
Records GEOMETRIC or column; every item reachable; Cancel last; the item focused on open is the same with T2 on and off (S6). Never press A |
| AT-13 | Alerts and sheets | CONFIRM, ALERT, ZOO('Text Prompt'), ZOO('Scroll Panel Test'), --mode pad and --mode laser; styles on the scrim, #header children, buttons, card; elementFromPoint at the Back circle's centre; a CDP click on the sheet's close circle (lab dialog: no action) |
Scrim black .35, no blur, painted only inside the glass shape (margin luma under the ornament = the no-modal shot ± 3 L); no t1 tint node; header contents .45 and Back still hit; alert 640 wide, centre within 24 px of the glass centre; sheet ≤ 960 × 488 (window routes); buttons 60 px capsules in Steam's order, DialogTwoColLayout a row; text on red and green fills #0d0e12; the close circle closes the dialog (m_rgModals.length restored) |
| AT-14 | Depth (native) | Native session: __LGS_SG.dump() and glass.py sgcheck with MENU, CONFIRM, CONFIRM-D (below), ZOO sheet, each opened from a focused poster and from a hovered one; glass.py sg_timeline-style capture of the menu's dz |
Menu, non-destructive alert and sheet crops at 10 mm ± 2 (live S × r), interactive: false; CONFIRM-D: no crop, a flat thick plate; every other in-page pop dropped while the modal is up, except a source card that was the gamepad-focused card (+15); ≤ 4 distinct dz (+1 for the modal); the menu's dz follows depth 0 → 10 within 0.5 mm; none above 15 mm unless interactivePops |
| AT-15 | Motion | glass.py motion main --pre … for: MENU open, CONFIRM open, ZOO sheet open and close, a route change (AllGames → a collection → back), a library tab change; getAnimations() after 1 s; route changes every 50 ms (CQ6) |
Durations and easings are tokens (P-58); 0 running and no lgs-* 1 s after (§1.5); filmstrips shots/p2_motion_c1c_<interaction>_<f>.png at f = 0, .15, .35, .5, .75, 1 show glass before content on entry and content before glass on exit, no text scaling, no closed outline; animated depth ≤ 20 mm; clip-path only on ≤ 600 × 600; route enter ≤ 800 ms with delay, exit ≤ 200 ms |
| AT-19 | Accessibility | --media reduce and --media contrast on MENU, CONFIRM, a sheet and a route change |
Reduce: opacity only, 150–200 ms, no scale, translate, clip-path or depth animation; glassd reduceMotion: true. Contrast: opaque glass with the 2 px edge. No Steam setting touched |
| AT-21 | Type | styles sweep over menus (all count classes), Power, dialogs, sheets |
No font-size < 18 px; no weight < 500; no uppercase, tracking or italics; red labels only at ≥ 22 px Semibold (P-40) |
| AT-23 (C1c part) | No outline on glass | shot main with MENU, POWER, CONFIRM and a sheet up; window-nav-measure.py edge on each slab's top edge |
Ratio ≤ 0.35 (mockups 0.00–0.22, E7); no border, outline or 1 px ring (P-42) |
| CC A13 | Power, look only | POWER + audit main with it; L.pad through every row in both columns (never A); --mode pad and --mode laser (CDP hover on two rows) |
0 GONE / SHRUNK; 7 items + Cancel in Steam's order; slab ≤ 520 × 600; focus visible on every row (destructive rows: red fill, #0d0e12 label, glow band ≥ +20 L); group labels present only when the language starts with en |
| PLAN-1c-1 | A destructive confirmation never pops | CONFIRM-D = CONFIRM with bDestructiveWarning: true and C1c's test hook tagging its OK button data-lgs-destructive (the tag a Power confirmation gets); CSS-only: P6's report; native: sgcheck |
No crop for the alert in either profile; native: one flat thick plate; the CSS look is the red confirm with a dark label |
| PLAN-1c-2 | G-MOTION filmstrips | = AT-15 for menu morph, alert and sheet; compared with window-nav-motion.html |
Each frame's glass/content progress within ± 10 % of the storyboard's values at the same f |
| PLAN-1c-3 | Looks like the design | glass.py cmp of live MENU (tile menu via the More circle), the Sort menu, POWER, CONFIRM (the mockup's strings) and ZOO sheet against window-nav-menu, -sort, -power, -alert, -sheet (map below) |
Named rects within ± 8 px or the difference explained here; both images viewed and a verdict recorded (G-MOCK) |
| C1c-1 | Input-mode looks in menus | MENU with --mode pad (focus on row 2), then --mode laser with a CDP hover + 80 ms dwell on row 3 while Steam's stale .gpfocus stays on row 1 |
Pad: focus ≥ rest + 40 L, first frame ≥ 60 %; laser: the hovered row + 10 to + 25 L, and no focus fill on the stale .gpfocus row (P-02) |
| C1c-2 | Focus returns to the source (P-21, G-PAD) | Focus a poster, ☰ (vgp_onmenu) → MENU; B; L.focused(). The Sort menu from the Y legend (look only); B |
Focus back on the same poster after each; B closed only the topmost layer (P-24) |
| C1c-3 | Dismissal | Menus: B, an outside click, Cancel. Alerts and sheets: B, the close circle, an outside click | Each closes the topmost layer; outside clicks on alerts and sheets cancel exactly as stock (D9) |
| C1c-4 | Source turns white | While MENU (from the More circle), the Sort menu (from slot 1) and POWER (from the tab) are open: the source's computed background | White .94 with a dark glyph while open; restored on close |
| C1c-5 | Route transitions never block input | A route change; at 300 ms a CDP click on an element of the new page; getAnimations() on TopLevelTransitionSwitch children |
The click reaches the new page's element; translate ≤ 16 px (0 in T1); nothing left at rest |
| C1c-6 | Strings | --flags wp.c1c with the UI language read from LocalizationManager; POWER |
Group labels drawn only for en*; every drawn string is listed in this log |
| C1c-7 | Removal | lgs off after MENU, CONFIRM and POWER runs; outline main; status |
No lgs-menu-*, data-lgs-*, html.lgs-modal, --sx..--sr or translate left on Steam's nodes; ModalManager untouched (G-REMOVE) |
Global gates on C1c's surfaces (§4.1, §4.2 row "CONFIRM, ALERT, MENU, SUBMENU, POWER, ZOO dialogs"): G-AUD, G-PAD, G-SIZE (E-MENU; Cancel per REQ 6a), G-TYPE, G-OUTLINE, G-FOCUS, G-MOTION, G-PERF (MENU open/close 5×, CONFIRM 5×), G-DEPTH, G-HV (hv with MENU and CONFIRM up, --offaxis), G-MOCK, G-REMOVE, G-A11Y, G-FONT, in both input modes, CSS-only and native.
Function retention (C1c rows; to replace WN §9.4, §9.5, §9.7)
Audit ids from audit/shell-nav.md §A.6–§A.8, audit/system.md, audit/library-apps.md, audit/game-pages.md, audit/social-media.md. Laser path first, gamepad path second; "same" = unchanged.
§9.4 Modals, alerts, sheets
| # | Function | New place | Laser | Gamepad | Tier | Owner | Test |
|---|---|---|---|---|---|---|---|
| M1 | Confirm / cancel | 640 px alert centred on the glass; capsules in Steam's order (Primary blue; .Destructive and Power confirmations red with a #0d0e12 label); an outside click cancels (Steam's, D9) |
Click | Left/Right + A; B (same) | T1 (+T2 tag) | C1c | AT-13 (Steam's handlers; never confirmed) |
| M2 | Single-button alert | One full-width 60 px capsule | Click | A / B | T1 | C1c | AT-13 (ALERT) |
| M3 | Text prompt | 64 px recessed field with the focus ring | Click → keyboard | Focus + A → keyboard (tests never type) | T1 | C1c | AT-13 (ZOO 'Text Prompt') |
| M4 | Scroll a long dialog | Sheet ≤ 488 tall on window routes; ModalPosition / %{ScrollPanel} scroll; content fades under the card's edge |
Wheel / drag | D-pad (same; the FocusRing as P4's light plate) | T1 | C1c | AT-13 (ZOO 'Scroll Panel Test') |
| M5 | Header and footer during a modal | Toolbar contents .45, still clickable; tab bar darkened (html.lgs-modal); the ornament lit with the dialog's legends (capsule or quiet, §3.4) |
Same | B to the dialog (same) | T1 + T2 | C1c (C1a chrome) | AT-13 |
| NEW-3 | Close a sheet with a visible control | 60 px close circle at (24, 24) in the card, dispatching Steam's click-outside cancel | Click | B | T2 | C1c | AT-13, C1c-3 |
| LA A.4 | Library Filters dialog | Sheet (content: C2c) | Click | D-pad + A; B | T1 | C1c (frame), C2c (content) | AT-13; PLAN-2c-2 |
| GP | Game-page modals (Exit game, Uninstall, …) | Alert or sheet by size; destructive ones flat | Same | Same | T1 | C1c | AT-13, PLAN-1c-1 |
| — | App-details overlay | Scrim .35, content on sheet-in |
Same | Same | T1 | C1c | AT-13 |
| CC P9 | Confirm a Power action | Flat alert, red confirm capsule with a #0d0e12 label, Steam's default focus | Click (never in tests) | Left/Right + A; B | T1 + T2 | C1c (look), C3b (CC entry) | PLAN-1c-1, CC A13 |
§9.5 Context menus, Power, dropdowns
| # | Function | New place | Laser | Gamepad | Tier | Owner | Test |
|---|---|---|---|---|---|---|---|
| C1 | Choose an item | Slab grown from its source; layout by count, no scroll up to 14 items | Click (the row under the laser lights; Steam's focus does not follow it) | D-pad + A (geometric in the grid if Steam declares no layout) | T1 + T2 | C1c | AT-11b, AT-12, C1c-1 |
| C2 | Open a submenu | Row with ›; Steam's submenu beside it; the open parent white | Click | A or Right (same) | T1 | C1c | AT-11b (SUBMENU) |
| C3 | Toggle a checked item | Row with the check in its leading slot | Click | A | T1 | C1c | AT-8c |
| C4 | Dismiss | Cancel, a 56 px quiet capsule (last); an outside click | Click | B (same) | T1 | C1c | AT-11, C1c-3 |
| C5 | Scroll a long menu | Value menus of ≥ 15 options: one scrolling column of two-line rows (560 × 520); settings routes > 8: C6a's list page | Wheel | D-pad | T1 | C1c, C6a | AT-11b |
| C6 | Open the menu of the thing I looked at | The More circle inside the card or row (C1a); the menu grows from it | Click | ☰ (same) | T2 | C1a, C1c | WN AT-26, AT-11 |
| SY A.5 | Power: Sleep, Shutdown, Restart Device, Restart Steam VR, Change Account, Sign Out, Restart Steam, Cancel | Two-group Power menu, 592 × 470; Steam's order and default focus; each item opens Steam's own confirmation or flow | Click | D-pad + A; B | T1 + T2 | C1c | CC A13, AT-11b, AT-12 (look only; never A) |
| CC P0 | Power from Control Center | The same menu, opened by CC's Power circle (CC closes first) | Click | Pad to CC, then A | T3 | C3b (entry), C1c (menu) | CC tests |
| GP A.3, A.4 | Manage menu, Play-from menu | Same slab, placed by GP §3.4's order | Click | D-pad + A | T1 + T2 | C1c, C5a | GP AT-MENU |
| SY S6 | Settings dropdown values | Same slab, right-aligned to the dropdown, the value checked; > 8 options: SET's list page | Click | A, Up/Down + A, B | T1 + T2 | C1c, C6a (list page) | SET T-MENU |
| LA sort | Sort By choices | Two-column slab grown up from the white Sort button | Click | Y → D-pad + A | T1 + T2 | C1c | AT-11b |
| SM D6 | Downloads item Options (8) | Two-column slab, Uninstall a red label at rest (≤ 2 destructive) | Click (More circle) | ☰ | T1 + T2 | C1c, C7 | AT-11b |
§9.7 Page transitions
| # | Function | New place | Laser | Gamepad | Tier | Owner | Test |
|---|---|---|---|---|---|---|---|
| A.8 | Route changes gate input for ~800 ms | Exit 150 ms linear; enter on page (662 ms) after ≤ 40 ms with ± 16 px (T2 direction; 0 in T1), inside Steam's React timeouts; nothing blocks input |
— | — | T1 (+T2) | C1c | AT-15, C1c-5 |
| LA tabs | Library and search tab content changes | ± 16 px + fade on page (replaces Steam's ± 40 % slide) |
Click a tab | LB / RB | T1 | C1c | AT-15 |
Live selectors for cmp (proposal; becomes C1c-cmp.json once REQ 13 is answered)
| Mockup | pre |
data-id → live selector |
|---|---|---|
window-nav-menu |
Tile-menu snippet (inventory library §7) on AllGames | menu → %{*BasicContextMenuModal>contextMenuContents}; menu-label → %{*BasicContextMenuModal>BasicContextMenuHeader}; row-install → first %{*…>contextMenuItem}; cancel → last %{*…>contextMenuItem}; more → .lgs-more; legend → #Footer |
window-nav-sort |
Sort snippet (inventory library §6.2) | menu, menu-header, row-checked → the %{*…>Selected} item, cancel, legend |
window-nav-power |
POWER | menu, menu-header, group-device, group-steam → .lgs-pm-group, row-focus → .gpfocus, cancel, legend |
window-nav-alert |
CONFIRM with the mockup's strings (title "Install Tidebreaker?", body as drawn, OK "Install") | alert → %{*GamepadDialogContent_InnerWidth>GamepadDialogContent}; alert-title → .DialogHeader; alert-body → .DialogBodyText; btn-ok → .DialogButton.Primary; btn-cancel → .DialogButton.Secondary; scrim → .ModalOverlayBackground; legend → #Footer |
window-nav-sheet |
ZOO('Scroll Panel Test') | sheet → the dialog card; close → .lgs-sheet-close; scrim; legend |
Evidence
All renders: python tools/mockshot.py docs/phase2/mockups/window-nav-<name>.html shots/p2_window-nav_<name>.png (1920 × 1080), viewed after each change. Rects: a scratch Playwright script reading [data-id] rects against .lgk-overlay (window px). Luma: docs/phase2/concepts/window-nav-measure.py (709) unless noted (601 = VP SHOT).
| Test | Command | Result | Files | Date | Steam build |
|---|---|---|---|---|---|
| E1 menu render | mockshot window-nav-menu.html |
Compact slab 400 × 502 at (522, 124), bottom 626 ≤ 628; 6 rows on a 64 px pitch; Cancel 158 × 56; More circle 60 at (436, 222) inside the card (inset 10); quiet legend centred (x 640) | shots/p2_window-nav_menu.png |
2026-10-07 | n/a (mockup) |
| E2 sort render | mockshot window-nav-sort.html |
Grid slab 592 × 508 at (347, 108), bottom 616; left edge 8 px left of the Sort button (rows aligned); widest label "% of Achievements" 213 px in a 214 px slot (no ellipsis); A/B kept in laser mode, no glyph badges | shots/p2_window-nav_sort.png |
2026-10-07 | n/a |
| E3 power render | mockshot window-nav-power.html |
592 × 470 at (24, 146), bottom 616; Steam's preferred focus (Restart Steam VR) red fill, #0d0e12 label; the Power tab white | shots/p2_window-nav_power.png |
2026-10-07 | n/a |
| E4 alert render | mockshot window-nav-alert.html |
640 × 261 at (320, 198): centre y 328.4 vs glass 328 (P-35); scrim 1280 × 656 inside the glass only | shots/p2_window-nav_alert.png |
2026-10-07 | n/a |
| E5 sheet render | mockshot window-nav-sheet.html |
960 × 472 at (160, 108): centre y 344, 16 px from the glass centre (P-35); close 60 at (24, 24) in the card | shots/p2_window-nav_sheet.png |
2026-10-07 | n/a |
| E6 storyboard | mockshot window-nav-motion.html |
5 rows × 6 frames (f 0, .15, .35, .5, .75, 1); glass leads content on entry, content leads glass on exit (sheet dismiss f .35: content 13 %, glass 22 %); morph overshoot 1.0 % at f .75 (b .20) | shots/p2_window-nav_motion.png |
2026-10-07 | n/a |
| E7 AT-23 edges (mockups) | window-nav-measure.py edge on each slab's top edge: menu 190 882 1202, sort 174 707 1219, power 212 384 896, alert 264 680 1240, sheet 174 520 1400 |
Ratios 0.22, 0.13, 0.12, 0.01, 0.00: all PASS (≤ 0.35) | renders above | 2026-10-07 | n/a |
| E8 G-FOCUS (mockups) | window-nav-measure.py dl; 601 luma for P-16 band (scratch script: mean of the 8–16 px band outside the capsule, focused vs unfocused button) |
Power focused row vs rest +61.8 L (709; +74.2 with 601) (P-14 ≥ 40 PASS); sheet focused chip vs rest +50.9 L (601: 115.1 vs 64.2) PASS; sort laser hover vs rest +22.4 L (601, P-03 10–25) PASS; alert P-16 band with §1.4's 0 0 18px 2px .30: +11.7 L FAIL; with 0 0 24px 6px .34: +23.5 L PASS (adopted in the mockups; REQ 5) |
shots/p2_window-nav_power.png, -sheet.png, -sort.png, -alert.png |
2026-10-07 | n/a |
| E9 quiet legend legibility | 601 luma of the room behind "Select" in the alert render | Background L 236 under white .70 labels: unreadable (REQ 4) | shots/p2_window-nav_alert.png |
2026-10-07 | n/a |
M2 evidence (session 2, CSS-only, Steam build 11094443)
Pre snippets: C1c's scratch generator mk.py (inventory shell §0.2 recipes: MENU = menustates, menuN = N plain items, POWER, CONFIRM with the alert mockup's strings, CONFIRM-D = CONFIRM + bDestructiveWarning + the data-lgs-destructive tag, ALERT, ZOO(label)) and library §0.3 (tile = vgp_onmenu on the first poster, sort = vgp_onoptions); every one only opens, looks and auto-closes (no item chosen, no dialog confirmed). Gates: python glass.py gates main --pre "<snippet>" --mode pad|laser --json. "C1c findings" = failures on menu, dialog, sheet or scrim elements; "others" = page chrome under the modal (C1a, C2c, C4a, C6a areas; Phase 1 tab row and zoo sidebar), not counted for C1c.
| Test | Command | Result | Files | Date |
|---|---|---|---|---|
| M2-P parse | scratch validate.py: the file wrapped as the bundler does, token-resolved with L.sel, parsed by Chrome's CSSStyleSheet.replaceSync in main |
81 of 81 rules kept, 0 unresolved tokens (22-presentations.css); 5 of 5 (23-transitions.css). The first deploy had a nested :has() that made Chrome drop the rest of the file; found by this check, fixed within 15 minutes |
— | 2026-10-07 05:40 |
| M2-L layouts | shot main p2_c1c_<menu>_pad --mode pad --pre <snippet> |
Tile menu (6 actions) compact 400 × 496 at y 107–603, rows 64 px contiguous, inline title; Power (7, > 2 destructive) two columns 592 wide, Sleep–Restart Steam VR in column 1 and Change Account–Restart Steam in column 2, Cancel below; Sort (10) two columns of 5, 592 wide; MENU states (8) grid, check in the leading slot, ≤ 2 destructive = red label | shots/p2_c1c_tile_pad.png, p2_c1c_power_pad.png, p2_c1c_sort_pad.png, p2_c1c_menustates_v2.png |
2026-10-07 |
| M2-A alerts/sheets | shot main p2_c1c_{confirm,zoo_scroll,zoo_text}_pad --mode pad |
CONFIRM card 638 wide (640 + rounding), buttons 60 px capsules side by side, Primary blue with the white-fill glow under focus; scrim .35 clipped at y 656; Scroll Panel sheet 958 × 487 at (161, 109); text prompt 64 px recessed capsule with the field ring | shots/p2_c1c_confirm_pad.png, p2_c1c_zoo_scroll_pad.png, p2_c1c_zoo_text_pad.png |
2026-10-07 |
| M2-H laser hover | scratch runner c1crun.py --pre tile.js --mode laser --sel <row 3> --dwell 400 --eval rows.js --shot … (CDP mouse) |
Row 3 :hover, --lgs-hover: 1, + .08 light; no row carries .gpfocus under the laser (Steam dropped it; hover did not move focus, IM D-7); no focus fill anywhere; pointer back at (1400, 900) |
shots/p2_c1c_tile_laser.png |
2026-10-07 |
| M2-G gates, run 1 | gates main × {tile, power, confirm, sort} × {pad, laser}, {alert, zoo_scroll (both), zoo_text, menustates, confirm_d, menu15} pad |
C1c findings: 0 for power, confirm, sort, alert, confirm_d (both modes). MOTION 0 running, 0 lgs-* left, no non-token timing everywhere. Open: tile compact rows P-08 (E-MENU, REQ to P10); Cancel SHRUNK 167 × 64 and compact title CONTRAST 3.5 (fixed: D23, D24); menu15 overflowed the window (fixed: container min-height: 0, D22); menustates edge probes on coloured fills (REQ to P10 (b); fills now image layers); sheet Close P-08 75 % own and ScrollPanel SHRUNK (sheet padding added; REQ (c)); zoo content 16 px text (sheet Body type added) |
scratch g_*.json |
2026-10-07 06:00–06:10 |
| M2-G gates, run 2 | the same, after the fixes (06:19–06:25) | C1c findings 0 for alert (laser), CONFIRM-D (laser), Power (pad), MENU states (pad, edge probe of a flat row only: REQ to P10 (b)). Remaining: compact rows P-08 (E-MENU); Power title CONTRAST 1.3 by the ancestor-only backdrop model vs 4.9 : 1 measured on the pixels (REQ to P10 (d)); ScrollPanel SHRUNK (REQ (c)); menu15 rows half-clipped by the slab's own scroll (P-08 25 %: scrolling lists, REQ (a)) | scratch run2/g_*.json |
2026-10-07 06:25 |
| M2-G gates, run 3 | gates main × {tile pad, tile laser, menu5 pad, menu7 pad, menu10 laser, power laser, zoo_scroll pad, confirm laser} after D28 (07:04–07:11); P10 had meanwhile added E-MENU to lab/exemptions.json and stopped sweeping controls under a modal |
G-TYPE, G-MOTION: PASS everywhere. G-AUD: 0 C1c findings everywhere (the 9 left are the library tab titles' text 17 → 14 px under the modal, C1a/C2c). G-OUTLINE: PASS (slab edge ratios 0.09–0.33; menu5 0.36 over a bright poster, re-measured after the centring fix below). G-SIZE: 0 P-08/P-80 findings; the E-MENU check fails only its "≥ 320 wide" clause: grid rows are 284 wide (PLAN §1.12's 592 px two-column slab) and Cancel is a 192 × 60 capsule (§1.12) — PLAN conflict, REQ to the coordinator. ZOO sheet: every gate PASS in pad mode | scratch run3/g_*.json |
2026-10-07 07:11 |
| M2-L2 geometry after D28 | scratch c1crun.py --pre <menu> --mode pad --eval measure.js (07:15–07:20) |
tile (6, compact) 400 × 502 at y 111–613, pitch 64, rows 60 visible; menu10 (grid) 592 × 508 at y 108–616 exactly, no scroll; Power (7, grid) 592 × 430 at y 147–577, columns 4 + 3; Sort (10, grid) 592 × 472 at y 126–598; menu7 now grid (430); menu12/14 scroll inside the slab (expected, D28); Cancel 192 × 60 (56 visible) inside every slab. (menu5 was measured before the theme reload: 510 at 101–611; expected 508 at 108–616 like menu10) | shots/p2_c1c_{power,tile,confirm,sheet}_final_pad.png |
2026-10-07 07:20 |
| M2-open sheet over a bright page | shot main p2_c1c_sheet_final_pad --mode pad --pre <zoo_scroll> |
Open for session 3: over the zoo page the sheet's in-page blur does not visibly frost the page (zoo buttons read sharp through the sheet), although the card's computed backdrop-filter is blur(30px) saturate(1.5) and over the library the alert card does blur the posters. Ancestors now carry backdrop roots (%{BasicHome} clip-path from C1a's 656 glass, %{MainNavMenuMainSplit} will-change: opacity); check which content the sheet's backdrop sees, and whether the sheet needs a denser tint over bright pages (P-39) |
shots/p2_c1c_sheet_final_pad.png |
2026-10-07 07:20 |
| M2-F focus | glass.py focus main --pre <power + L.root + gpTake> --pairs pairs_power.json --mode pad; same with CONFIRM and pairs_confirm.json |
Plain menu row focus vs rest +59.3 L (P-14 ≥ 40 PASS); secondary alert button focus vs rest +69.5 L PASS; P-16 glow band (12–24 shot px) on the focused blue primary +33.5 L PASS (≥ 20). Red destructive row filled vs rest +31.7 L by P-14's luma (the dark label lowers the mean); its criterion is P-16 (a coloured fill, glow) and the hue change; the band pair is queued for the next run. Live look: p2_c1c_power_focus_pad.png (red fill, #0d0e12 label, glow; label contrast 5.5 : 1 on the pixels) |
shots deleted by focus; shots/p2_c1c_power_focus_pad.png |
2026-10-07 06:36 |
| M2-C cmp (G-MOCK) | glass.py cmp docs/phase2/mockups/window-nav-<m>.html --id C1c --mode pad|laser with docs/phase2/wp/C1c-cmp.json |
alert: card x and width exact (dx 0, dw 0), centre on the glass (live top −15.4 with +30 height = the lab body string's extra line; centre 328), buttons dw −6, dy +14.6 (same extra line): matches. menu (tile): slab 400 wide and 502 tall exact (dw 0, dh 0); dx −82 / dy −19 = T1 centring vs T2 anchoring (M3); rows +4 tall (64 px hit box vs 60 visible); Cancel +26 wide (min-width for G-AUD). sort: slab dx −3, dy +15, dw 0; dh −30 = no "Sort By" title (Steam has none; T2 copies it). power: dw 0; dx +320 (anchored at x 24 by T2), dh −30 (group labels, T2). sheet: map hit Steam's click-away div.Panel (fixed in the map); re-run pending. Viewed both images of each: same slab material, row metrics, tones and type; the deltas are T2 work or explained here |
shots/p2_cmp_c1c_window-nav-{alert,menu,sort,power,sheet}.png |
2026-10-07 06:36 |
| M2-M motion (token audit) | glass.py motion main --pre <mo_menu|mo_alert|mo_sheet|mo_route> --name c1c_<x> --json |
Every animation and transition C1c starts uses tokens: lgs-morph 607 b0 + lgs-morph-content 607 linear (menu), lgs-mat-large-in / lgs-mat-content-in 250 linear (alert), lgs-sheet-in / lgs-sheet-content-in 735 b0 (sheet), route enter opacity 662 b0 after 40 ms, exit 150 linear with the transform change at 150 ms, 0 running and no lgs-* left 1 s after (atRest 0). The only non-token timing seen is another area's (PagedSettingsDialog_PageListItem box-shadow 140 ms). The filmstrip frames after f = 0 all show the end state (identical files for f .15–1 in the menu run), so they cannot be judged yet (REQ to P10 below); PLAN-1c-2 stays open |
shots/p2_motion_c1c_{menu,alert,sheet,route}_strip.png |
2026-10-07 06:45 |
M3 evidence (sessions 3 and 4, --flags wp.c1c, Steam build 11094443)
Runner: scratch c1crun2.py (copy in /tmp/lgs/c1c/; one lab.Lock step, trusted CDP mouse on main, flags and mode applied and undone by the lock, pointer back to (1400, 900)). Raw JSON: scratch c1c/s3/out/o_*.json. Some session-3 steps ran while another agent's native session was on (native=on in their header); the results below are DOM facts, not depth.
| Test | Steps | Result | Date |
|---|---|---|---|
| AT-11 anchor + dismiss | tile menu (☰ on the first poster), --mode pad and laser; trusted click outside at (1180, 400) and (110, 600); same with the flag off |
Compact slab 400 × 502 at (236, 114), 16 px right of its card (translate −204, +3), bottom 616; outside click closes it with T2 on and off (menus 0, modals 0, route kept). A click at (1240, 650) does not close it: that point is the bottom ornament row (legends sit above Steam's modal layer, C1a), not the click-away layer |
08:17 |
| AT-11b fit | menu5, 7, 10, 14, Sort, Power (at11b2) |
5: one column 400 × 508 at y 108–616; 7: grid 592 × 430; 10: grid 592 × 508 at 108–616; 14: grid, scrolls inside the slab (D28); Sort: grid 592 × 508, title "Sort By" (Steam's string), current sort "Alphabetical" checked; Power: grid 592 × 466, groups "This Device" / "Steam" (Steam's strings), glyphs; Cancel inside every slab; rows tagged E-MENU | 08:17 |
| AT-12 D-pad + default focus | Power, Sort, tile; dpad.js (Down × 8, Up, Right, Left …) with the flag on and off |
Identical sequences on and off for all three (every item reached, Cancel last); default focus unchanged (tile: Install; Power: Restart Steam VR per Steam). No A pressed | 08:18 |
| AT-13 alerts and sheets | CONFIRM (pad, laser), ALERT, CONFIRM-D, Power-originated confirm, text prompt, Scroll Panel sheet (pad, laser) | Scrim rgba(0,0,0,.35), no blur, clipped inset(0 0 calc(100% - 656px) round 54px); header contents .45 and Back still hit; html.lgs-modal set; alerts 640 wide, centre y 328 (glass centre); CONFIRM-D and the Power confirm get data-lgs-plate="thick" (flat, PLAN-1c-1), a plain CONFIRM none; sheet 960 × 488 at (160, 108) with the 60 px close circle at (24, 24), aria-label Close, hit-testable; buttons 60 px |
08:18 |
| C1c-2 focus return | ☰ on a poster → menu → B, flag on and off | Focus back on the same poster both ways; source glow while open, released after | 08:18 |
| C1c-3 dismissal | B on alert and sheet; Cancel on the tile menu (laser click); outside click on the sheet | B closes the topmost layer; Cancel closes the menu. The zoo Scroll Panel sheet ignores Steam's click-away in stock too (js --stock, 09:58: click on ModalClickToDismiss leaves the modal), so the outside click is kept "as stock". The close circle used only that click-away and so did nothing on such sheets: fixed (session 4) — it now falls back to B's cancel when the sheet is still the active overlay and Steam's focus is inside it |
08:18 / 09:58 |
| AT-14 / PLAN-1c-1 native (sgcheck) | native-session --flags wp.c1c,wp.c1a --mode pad with sgcheck --pre tile menu, CONFIRM-D, Scroll Panel sheet (10:00) |
PASS ×3. Tile menu: 1 pop, c1c-menu at 10.0 mm, modal, the source poster's pop dropped (rule 6); CONFIRM-D: 0 pops (flat, rule 4); sheet: 1 pop, c1c-sheet at 10.0 mm, modal. First run (09:57, wp.c1c only) failed only on legacy rules: hdr-back/footer (C1a supersedes them under wp.c1a) and legacy button popping the red button at 1.84 mm (R2, R4) → C1c now supersedes button (REQ to C4a, information) |
09:57 / 10:00 |
| hv look (native) | hv c1c_menu_native --look after a js step that opens the tile menu after the step's lock (3 tries, 09:58–10:05); each frame viewed and deleted at once on both machines |
Native window glass on /library/tab/AllGames, no doubled edge (doubling 0.38–0.41, not doubled), top-edge ratio 0.00–0.24 (≤ 0.35). The menu itself was not in any frame: on the shared device it closed (or had not opened) before the hv step got lab-vr.lock; its depth is proven by sgcheck above. Open: an hv look with a menu up needs a P10 option (an hv --pre that keeps the layer open for the capture) |
10:05 |
| Gates run 4 | scratch run4/gates4.py: gates main --pre <snippet> --flags wp.c1c --mode pad|laser × tile (both), CONFIRM (both), Scroll Panel sheet (both), Power (laser), 10:05–10:19 |
First pass: tile laser OUTLINE 0.589 and the compact title's CONTRAST 1.3 over the white tab pill — real: the slab tinted but did not blur (A/B shots: removing C1a's will-change: opacity on MainNavMenuMainSplit restores the blur) → D34; sheet AUD SHRUNK ScrollPanel 912 × 296 (< 300 exemption) → close row 88 px. After the fixes: tile pad/laser, CONFIRM laser, sheet pad/laser: 0 C1c findings in every gate; slab edge 0.27 (≤ 0.35); Power laser 0 C1c findings. Left: E-MENU "≥ 320 wide" (grid rows 284, Cancel 192; coordinator REQ) and BackButton CONTRAST under the .45 modal dim (D16, WN §5.3) |
10:19 |
| pad-bfs | scratch run4/bfs4.py: pad-bfs --pre <snippet> --start <first item> --flags wp.c1c --mode pad × tile, Power, CONFIRM |
Tile: 12 nodes (6 actions + Cancel + the Add to / Manage / Developer submenus, focus only, never A), Power: 8 (7 + Cancel), CONFIRM: 2; irreversible 0 everywhere; B closed the layer (Power, CONFIRM; the tile run's B came after the snippet's 20 s auto-close, see C1c-2 for B on the tile menu). unreached = the page under the modal (45 nodes; a modal traps focus by design). Power's grid is navigated as one column (Right/Left = edge), the same as with the flag off (AT-12) |
10:10 |
| C1c-3 close circle | Scroll Panel sheet, trusted click on .lgs-sheet-close, laser and pad |
Before: the sheet stayed open (its click-away is ignored, also in stock). Cause 2: a press on the circle moved Steam's focus to <body>. Now the circle keeps focus (preventDefault) and, when the sheet is still the active overlay 260 ms later, cancels like B: closed in both modes (modals 0, route kept) |
10:23 |
| C1c-4 source white | Sort from the ornament | Not captured (empty output, runner timing); Power tab and More circle checked in AT-11b / C1a's run | — |
Appendix A. Replacement text for window-nav.md (C1c's sections; REQ 1)
C1a: paste each block over the named part of revision 3. Values come from the M0 renders above.
A.1 Intro mockup table, the six C1c rows
| Shot | Source | Owner | Shows |
|---|---|---|---|
shots/p2_window-nav_menu.png |
window-nav-menu.html |
C1c | Laser mode: Steam's 6-action tile menu (developer mode adds Developer ›) in the compact layout, 400 × 502, grown 16 px right of its card out of the white More circle; the row under the pointer lit + .08 with the light spot; the card at 0 mm with a soft glow; Cancel a 56 px quiet capsule (superseded by PLAN R2-5: 60); the quiet legend |
shots/p2_window-nav_sort.png |
window-nav-sort.html |
C1c | Laser mode: Sort By (10 options) as a two-column menu, 592 × 508, grown up out of the white Sort button; the current sort's check in the leading slot; the hovered row + .08; A and B as quiet members without glyphs |
shots/p2_window-nav_power.png |
window-nav-power.html |
C1c | Gamepad mode: the Power menu, 592 × 470, two groups, grown from the white Power tab; Steam's default focus (Restart Steam VR) as a red whole fill with a dark label |
shots/p2_window-nav_alert.png |
window-nav-alert.html |
C1c | Gamepad mode: a 640 px alert centred on the glass at +10 mm over Steam's scrim (.35, clipped to the glass); the primary focused (outer glow); inset: the destructive variant, flat, with a red confirm and a dark label |
shots/p2_window-nav_sheet.png |
window-nav-sheet.html |
C1c | Gamepad mode: a 960 × 472 sheet (the library Filters dialog) centred on the glass at +10 mm, with its close circle; a chip with gamepad focus |
shots/p2_window-nav_motion.png |
window-nav-motion.html |
C1c | Motion storyboard at f = 0, .15, .35, .5, .75, 1: menu morph-open, alert present, sheet present, sheet dismiss, route change |
A.2 §5.1.1 — in the table, row "6–7", column Height: "6 actions: 502 (tile menu, measured)". Replace the value-menu table's first row and the shots line with:
| Options | Layout |
|---|---|
| ≤ 8 | Placement: a slab anchored to its capsule, right-aligned, below, above or over it (SET §4.5). Layout follows the count table above: ≤ 5 one column, 6–7 compact, 8 the two-column grid (8 rows of 72 px would need 624 px) |
Shots: p2_window-nav_menu.png (6 actions, compact, laser hover), p2_window-nav_sort.png (10, grid, laser hover), p2_window-nav_power.png (7 grouped, grid by S24, gamepad focus).
A.3 §5.1.2 — replace these rows:
| Property | Value |
|---|---|
Checked / selected (.menuChecked, %{*…>Selected}) |
A white check (24 px, stroke 3) in the row's leading 28 px slot, the slot action menus use for their symbols; no fill. Every row of a value menu reserves the slot, so labels align (as SET §4.5, visionOS menus and the CTL and SET mockups; revision 2's trailing check is withdrawn). AT-8c measures focus against a real checked row |
| Primary | .Play, .Launch and the primary first row: green whole fill. .Install, .Update: blue whole fill. On a coloured fill the row's label and glyph are #0d0e12 on green, orange, yellow and red, white on blue (CC §7) |
| Destructive | ≤ 2 destructive rows: red label (Semibold) and red symbol at rest. More than 2 (Power): red symbol, white label at rest. On focus always a red whole fill (rgb(255 66 69 / .92)) with a #0d0e12 Semibold label and glyph, the illumination capped at + .04, and the outer glow. Never reordered (SM-D8, S20); Steam's default focus untouched (S6) |
| Focus on a coloured or white fill | A blurred outer glow (P-16), P4's token. PLAN §1.4 names 0 0 18px 2px white .30; it measures a + 11.7 L band on the alert mockup, so the mockups use 0 0 24px 6px white .34 (+ 23.5 L) until P4 sets the token |
Mockup values (C1c log E8): Power's focused row + 61.8 L over a rest row; the sort menu's laser-hovered row + 22 L over rest (P-03: + 10 to + 25).
A.4 §5.1.3 — add after "Anchor (T2).": "Ornament sources: the slab's left edge 8 px left of the source's, so its rows line up with the button; its bottom clamped above the ornament (Sort By: y 108–616)." Add after "Morph.": "clip-path cannot reach outside the slab, so T2 carries the source rect to the slab's nearest edge at the source's height (the tile menu starts as a 60 × 60, radius 30 shape at the slab's left edge, level with the More circle). glassd v3 draws no morph (contracts/glassd.md §6): in T5 the slab's glass materializes in place on its phase while the CSS morph plays, and on close glassd dematerializes it; replace 'glassd plays morph-close (441 ms)' accordingly."
A.5 §5.2 — "592 × 464 px" → "592 × 470 px (measured)"; "bottom at 616 (top 152)" → "bottom at 616 (top 146)"; the item list uses Steam's live labels: Sleep, Shutdown, Restart Device, Restart Steam VR, Change Account, Sign Out, Restart Steam (inventory shell §4). Add: "The group labels 'This Device' and 'Steam' are new strings, drawn only when the UI language starts with en (PLAN §1.15). The mockup shows Steam's preferred focus, Restart Steam VR, as the focused red whole fill."
A.6 §5.3 — replace the Scrim and Chrome rows and add three rows:
| Property | Value |
|---|---|
| Position | Centred on the glass (VP P-35, ± 24 px): the card's centre at y 328 on window routes, 360 on window-full. T1 pads ModalPosition's bottom; it never moves its top or bottom (LAB) |
| Scrim | .ModalOverlayBackground in %{GamepadDialogOverlay}: black .35, no blur, in both modes, clipped to the route's glass shape (window: 1280 × 656, radius 54; window-full: 1280 × 720; windowless: the whole quad, radius 54), so the ornament margin and the corners never darken the room. No t1 tint (PLAN §1.8) |
| Chrome while open | Toolbar contents at opacity .45 (still clickable, as today); the tab bar darkened; the ornament stays lit with the dialog's legends. The tab bar lives in another popup, so C1c's T2 sets html.lgs-modal on every popup while main's ModalManager holds an alert or sheet |
| Dismissal | Steam's: an outside click (ModalClickToDismiss) and B cancel. VP P-65 asks that an outside click not close alerts and sheets; Steam's behaviour is kept for function retention and recorded as a deviation (PLAN §4.4) |
| Default focus | Steam's (PLAN S6). VP P-67 asks for the non-destructive choice; recorded as a deviation |
Depth row: "… 0 mm (a flat thick plate in native mode) when the alert contains a destructive button …" (unchanged).
A.7 §5.4 — Card row: "Thick glass, radius 44, max width 960 (75 % of the glass), centred on the glass (P-35): top-aligned at 108 and at most 488 px tall on window routes (552 on window-full), so its centre stays within 24 px of the glass centre; the content scrolls inside." Motion row: append "sheet-out plays in CSS only while Steam keeps the node (MO R4); otherwise the CSS close is instant and glassd dematerializes the slab in place". Add a row "Native flat modals: a destructive alert carries data-lgs-destructive (never pops, reporter rule 4) and data-lgs-plate=\"thick\" (a flat plate)" to §5.3.
A.8 §7 — replace the storyboard line: "Storyboard: p2_window-nav_motion.png, C1c's interactions (menu morph-open, alert present, sheet present, sheet dismiss, route change) sampled at the G-MOTION points f = 0, .15, .35, .5, .75, 1 (PLAN §2.3 P10 motion). The search sheet and the toast are filmed by C1b and C3a."
A.9 §9.4, §9.5, §9.7 — the three tables in "Function retention" above, as they stand.
A.10 §13 — C1c's rows: AT-8c, AT-11, AT-11b, AT-12, AT-13, AT-14, AT-15, AT-19, AT-21, AT-23 (C1c part) as in "Acceptance tests" above, plus new rows CC A13, PLAN-1c-1, PLAN-1c-2, PLAN-1c-3 and C1c-1 to C1c-7 (owner C1c).