Files

89 KiB
Raw Permalink Blame History

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 (scratch c1c/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: footer ActionButtonLabel "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". Shots shots/p2_c1c_r2f_tile_{pad,laser}.png match p2_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 filters native layer rule (C2c REQ-10c); native menu/alert backing over posters (C1a FYI); Sort menu gates are C2c's route (asked to re-run).
  • 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, cmp re-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 (one c1c-menu pop at 10.0 mm), CONFIRM-D (no pop) and the sheet (one c1c-sheet pop at 10.0 mm); an hv look showed native window glass without doubled edges, but not the menu (see the evidence row). Runtime log: no warnings or errors from menus; 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's will-change backdrop root left them sharp), sheet close row 96 → 88 px (scroll area ≥ 300 tall, AUD). All _wip copies 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 hv frame with a menu up needs P10's help (REQ below); filmstrips (PLAN-1c-2) and the cmp re-run were not repeated (expedited session).
  • 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 (module menus; working copy device/rt/_wip/22-menus.js, identical) and the T2 CSS merged into theme/22-presentations.css §9 (working copy theme/_wip/22-presentations.css, identical). Built: count classes and data-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's eSortBy prop) and titled with Steam's #Library_SortCollectionBy (D30); source tracking (More circle, Steam's own menu anchor m_ActiveMenu.m_position.element, pointerdown / vgp_onmenu / vgp_onoptions, frame-menu tab → data-lgs-open), data-lgs-menu-source="white|glow"; anchoring by translate on BasicContextMenuModal (kill switch menuAnchor=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 and data-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.sh in 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) and theme/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.css is the working copy (== theme/22-presentations.css after the last deploy). Edit it, run scratch validate.py (parses the bundled file in live Chrome; keep its accumulator on globalThis, not on L, which the lab reinstalls), glass.py check-theme, copy into theme/, 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: scratch mk.py (parameterised inventory recipes; when passing a route from Git Bash set MSYS_NO_PATHCONV=1). Real laser hover: scratch c1crun.py (copy in /tmp/lgs/c1c/, until P10 ships a hover option).
  • Next (session 3):
    1. M3 as soon as wp/P2.md reports M3 (P1 complete, P3 M3 at 06:12; P2's status still said M1 at 07:00 although its RX tests pass): move device/rt/_wip/22-menus.js (draft written: classification, Power glyphs and groups, source tracking and the white source, anchoring behind flag menuAnchor, html.lgs-modal, sheet close circle, destructive tag on Power confirmations) to device/rt/22-menus.js, merge theme/_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).
    2. 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 cmp for 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).
    3. Watch the open requests below (coordinator: E-MENU / D28 / Cancel; P10: hover option, gate artefacts, filmstrips).
  • 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.md already 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).
  • 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) and theme/23-transitions.css (route and tab transitions on P5's lgs-page-*). Use theme/_wip/ until glass.py check-theme passes; read P4's contracts/tokens.md (focus token, glow token) and P5's contracts/motion.md (keyframe names) first. Then M3: device/rt/22-menus.js (count classes, menu type, source tracking and --sx..--sr, anchoring translate, destructive tags, Power groups and glyphs, sheet close circle, html.lgs-modal on every popup) behind wp.c1c. Then M4: theme/layers/22-presentations.json (+10 mm crops, destructive alerts flat, superseding the legacy menu, sheet, sheet-panel rules).
  • Static mockup parts to replace later: the quiet legends in window-nav-menu/-power/-alert.html are static markup using C1a's .wn-orn.quiet; window-nav-sort.html adds mode-laser after C1a's builder. When C1a's builder supports quiet legends and laser-mode A/B (REQ 3), switch these to data-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 in docs/phase2/wp/C1c.md Appendix 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 8px white .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 of window-nav-menu.html, minus the .c1c prefix and the .c1c.laser glyph 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 .chk that pushes the check right, white labels on red, Cancel without the quiet recipe). C1a answer: adopted, scoped to .wn-menu, .wn-alert, .wn-sheet so it cannot touch other areas' buttons; the white-fill glow uses P4's token value; the .c1c.laser glyph rule is dropped (the builder hides badges in laser mode); a legacy trailing .chk rule stays only until settings-dropdown.html moves to .lead.check.

  • REQ C1c->C1a: window-nav-shared.js buildOrnament: with data-mode="laser", keep A and B as quiet members (labels only) and add mode-laser; emit .wn-orn.quiet without lgk-glass when 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 without lgk-glass; dim band in the margin; data-inglass for window-full; data-modal recedes the page's members). Your static quiet legends can switch to data-wn="ornament".

  • REQ C1c->C1a: quiet legend legibility on window routes. 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: in p2_window-nav_alert.png and p2_window-nav_power.png "Select" sits on the curtain (background L 236) and disappears. Proposal (safe default): on window routes keep a faint capsule (the liquid material 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 on window-full routes, 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 on window routes, white .82 labels, flag quietBacking (WN §3.4.1, §11 O3); §1.10's look kept on window-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 2px white .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 6px white .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 in contracts/tokens.md; C1c's mockups use 0 0 24px 6px white .34 meanwhile (E8). P4 (2026-10-07): done. --lgs-white-glow is now 0 0 22px 8px white .55 (parts --lgs-white-glow-blur/-spread/-a), used by the --lgs-ill: white hook; 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 ModalClickToDismiss and 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 on window routes (552 on window-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, modalOutsideGuard reserved off (S30); (c) confirmed, written into §1.12 with numbers. See PLAN §1.19 R2-5, R2-6; follow-up REQ Coordinator->C1c in wp/coordinator.md.
  • 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).
  • 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 fires mouseout on the host; the rt.attend registration has no leaveMs, so onLeave hides the circle before the press lands. Suggestion: leaveMs ≈ 300 with the circle counted as part of its host (ignore a leave whose relatedTarget is the circle), or keep the circle shown while :hover. A synthetic L.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 in wp/C1a.md session 4.
  • REQ C1c->C3b: control-center-power.html and control-center-power-confirm.html still 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 (see window-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 (no t1), and the search field has no microphone. Please align these mockups, or crop them to CC's entry point and point to window-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 the c1c-recipe block in window-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.
  • REQ C1c->C6a: settings-dropdown.html and settings.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 .Primary of a dialog opened from a tagged button) and calls your scan(), so tagDestructive flattens 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 and controls-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.md rev 3 §8.2, C-D16, §14: menus +10 mm non-interactive over a thick slab (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.html and -steamvr.html now draw the leading check and the 56 px Cancel (re-rendered and viewed).
  • 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 cmp reads one docs/phase2/wp/<PKG>-cmp.json with a single route/pre/map. C1c compares five mockups (menu, sort, power, alert, sheet), and each needs its own pre (MENU, the Sort snippet, POWER, CONFIRM, ZOO). Please accept {"mockups": {"window-nav-menu": {surface, route, pre, map}, …}} (or a --map KEY option) and document it in contracts/lab.md. The proposed map is under "Live selectors for cmp" below.

    • P10 (2026-10-07 06:00): done. glass.py cmp accepts {"mockups": {"<stem>": {surface, route, pre, mockOrigin, mockScale, map}}}, chosen by --name or 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 repeated data-id keeps its first occurrence. contracts/lab.md §3.
  • 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: gates SIZE 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 rows data-lgs-exempt="E-MENU" at M3, but M2 is CSS-only.

    • P10 (2026-10-07 06:35): done: E-MENU added; 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).
  • REQ C1c->P10: a real laser hover in lab steps. L.hover dispatches untrusted events, so CSS :hover (and P4's --lgs-hover, .lgs-dwell:hover) never applies; C1c-1, AT-8c and every laser look need CDP Input.dispatchMouseEvent on the surface's own target. P3 and C1c each wrote a private runner (C1c's: lab.Lock + lgs.Session, scratch c1crun.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), or L.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.dispatchMouseEvent on 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]", and focus states "@hover SEL[,MS]" / "@unhover"; the pointer goes to (1400, 900) at the lock exit. Verified: the target matches(':hover') inside the step, not after it. contracts/lab.md §1.
  • REQ C1c->P10: three gates false 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.active while 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 without backdrop-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 (shot p2_c1c_power_focus_pad.png, 97th/15th percentile relative luminance in the title box). Please take the backdrop from elementsFromPoint at the text's centre (the first non-ancestor painted element under it), or accept a data-lgs-backdrop hint. (c) AUD SHRUNK on scroll containers: a sheet capped at PLAN §1.12's 960 px reports SHRUNK 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 as skipped: under modal) and OUTLINE does not probe it; (b) an edge whose brightest quarter is under 8 dL is edge: "none" and passes (no visible line, no ring); (c) AUD lists a scroll container that stays ≥ 300 × 300 under exempt (scroll-container) instead of SHRUNK.
  • REQ C1c->P10: glass.py motion filmstrips 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) report seeked: 5 per 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 before Page.captureScreenshot (produce a frame after setting currentTime, e.g. wait two requestAnimationFrames, or seek over CDP Animation.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): motion now 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.
  • 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 popped contextMenuContents and ModalPosition > *, but C1c's 22-presentations.css paints these slabs and cards with P4's --lgs-mat-thick-bg, --lgs-mat-thick-blur and --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/-shade tokens and --lgs-edge on acked pops and plates, and acked plates also lose fill, shadow, blur and the -blur tokens; 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's theme/22-presentations.css now carries both (PLAN §6 migration row for 10-primitives.css). Why: the .menuChecked::after check mark of §8 lands on the ::after light layer that P4's --lgs-ill hook draws on menu rows (C1c works around it by keeping checked rows off the hook), and §8/§9's !important focus 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 .menuChecked rule, no --lgs-t-fast and no ring; its §10 keeps only the rich pop-up label colours inside menu rows (DropDownLabelTitle / …Description inherit the row colour) and .DialogSubHeader / .DialogControlsSectionHeader outside ModalPosition. DialogButtons are C4a's §1 (alert-footer .Primary blue / .Destructive red with dark label inside .DialogFooter, %{ModalButtonRow}, .DialogTwoColLayout); your alert rules may refine them.
  • REQ C1c->C4a: (information, no action needed unless you object) C1c's theme/layers/22-presentations.json now supersedes the legacy layer button (button.DialogButton.gpfocus, lift .005 = 1.84 mm) while wp.c1c is 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 with mm (it then goes through the admission rules).

  • REQ C1c->C1a: (information; please object if it breaks your ornament) theme/22-presentations.css §8 now sets will-change: auto on %{MainNavMenuMainSplit} while html.lgs-menu-open (C1c's T2, a context menu is open) or html.lgs-modal (an alert or sheet) is set (D34). Why: your will-change: opacity backdrop 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: auto on %{MainNavMenuMainSplit} keeps the ornament working (the capsule frosts the page from #Footer, outside that root). Nothing else in 20-shell.css makes 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.
  • REQ C1c->P10: an hv step that keeps a lab layer open for the capture (for example hv NAME --pre JS, run under lab.lock with keep until 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 separate js step is closed by other agents' step restores (or never seen) before hv gets lab-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 R and --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 §4 hv step 3.

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.md REQ-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 on window routes (centre within 24 px of the glass centre, P-35).
  • C1b.md REQ #8 (search sheet depth rules): accepted, answered there; it lands with C1c's M4 fragment theme/layers/22-presentations.json (next round), so it stays open.
  • End of session 2 (07:23), the grep found three more: C1a.md re-render the five mockups (done, [x] there), C1a.md take the app-details overlay scrim from 20-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 on windowless routes (accepted for the M4 fragment, answered there, open).
  • Related, not addressed to C1c: C2c.md REQ-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, :empty hidden) + 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/::after free). Steam's focus = %{Focused} + .gpfocus together.
  • 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-height 40, bottom = footer 42 with FooterVisible) > ModalClickToDismiss, a zero-size %{FocusRingRoot}, and the card %{GamepadDialogContent}.GenericConfirmDialog (660 wide, 2 px border, margin: auto). Custom content (zoo Scroll Panel) is a div.Panel straight in ModalPosition.
  • Transitions: route TopLevelTransition Enter/EnterActive (600 ms + 200 delay, scale .95 → 1) and Exit/ExitActive (200 ms); tab content %{GamepadTabbedPage>ContentTransition} with %{GamepadTabbedPage>Enter|EnterActive|Exit|ExitActive} under Left/Right (slide ± 40 %, 320 ms + 80 delay; exit 80 ms ∓ 10 %).
  • L.hover cannot produce CSS :hover (untrusted events). Laser looks were verified with C1c's runner c1crun.py (CDP Input.dispatchMouseEvent on main's target inside lab.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 background Retired 06:40: C4a removed 10-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).