Context
The 13.2 notes frame D2 (dock-d2-rail.png in neomjs/pages resources_pub/website/release-notes/v13.2.0/) shows a light-blue ring around the System Metrics overlay, which is revealed from the right edge rail. The operator (2026-10-10) saw no ring in the film takes or when using the rail by hand. Sampled pixels of the frame show the ring is #99C8FF with a #101010 edge. That is Chrome's default dark-scheme focus ring, not the overlay's designed border (--dock-reveal-border: --workstation-signal at 46% over --workstation-line, a teal-grey).
The Problem
Whether the ring paints depends on what held focus before the reveal, not on the reveal itself. A real mouse click never paints it: Chrome's last-input heuristic says pointer. The film driver's rail step (apps/workstation/tour/GestureDriver.mjs:673-704, #19127) clicks with synthetic events (detail 0) and then calls button.focus() with no modality. That programmatic focus is focus-visible, and the overlay's programmatic focus inherits it. The frame is embedded in the 13.2 notes, and every scripted capture of a reveal can repeat it.
The Architectural Reality
Rail#onRevealStateChange (src/dashboard/dock/interaction/Rail.mjs:740-741) calls RevealOverlay#focusReveal() when a tab click opens a reveal (revealed-focused). Rail#onTabClick (:777) receives the click payload, which carries detail (src/main/DomEvents.mjs:329). detail is ≥ 1 for a pointer click and 0 for a keyboard- or AT-activated one.
focusReveal() (src/dashboard/dock/interaction/RevealOverlay.mjs:390-396) calls this.focus(this.id, true) with no modality. The root is tabIndex: -1. DomUtils.isFocusable (src/main/DomUtils.mjs:128-131) accepts a negative tab index, so the root itself takes focus.
DomAccess#focus (src/main/DomAccess.mjs:358-400) stamps neo-focus-pointer for 'pointer' and says it "suppresses the accidental ring", but no stylesheet keys on that class. Only the Grid view styles its own focus (#18968, resources/scss/src/grid/View.scss:9-19). The contract is unbacked for all three callers that state 'pointer': RevealOverlay.mjs:538, src/draggable/container/SortZone.mjs:681 and src/grid/Body.mjs:1277.
- Deliberate outlines share the property: the locked pane (
resources/scss/src/dashboard/Container.scss:916) and the arrival pulse (:372). A suppression rule must lose to every author rule and beat only the user agent's.
Design authority: DomAccess#focus (src/main/DomAccess.mjs:358-360): "explicit input-modality contract. :focus-visible cannot tie an async worker→main programmatic focus back to the originating pointer gesture, so the caller states it." The same method's comment says "'pointer' suppresses the accidental ring".
The Fix
resources/scss/src/Global.scss: :where(.neo-focus-pointer:focus-visible) {outline: none}. With zero specificity it beats only the user-agent ring, and any component outline still wins. The DomAccess#focus comment names this rule.
Rail#onTabClick records the opening gesture's modality ('pointer' when detail >= 1), and focusReveal(modality) passes it to focus(). A keyboard-opened reveal passes none, so the user agent's keyboard ring stays.
- The film driver's synthetic click carries
detail: 1, as a real click does.
- D2 is reshot at the fixed head, with the same path and caption, so the notes embed is unchanged.
Acceptance Criteria
Out of Scope
Component keyboard rings keyed on :focus-visible instead of neo-focus-keyboard, and the look of the keyboard ring around the overlay root (it stays the user agent's).
Related
#18968, #17317, #19339, #19127, #19506, #14800.
Sweeps: live latest-open sweep checked the latest 20 open issues at 13:33Z, no equivalent · A2A in-flight sweep: 30 messages, no overlapping claim · MC sweep: "rail reveal overlay focus ring, focusReveal modality" (5 results; #18968 and #19339 are the precedents, no decision that the overlay should carry the user-agent ring) · Own-assignment sweep: 2 open (#14800, #15000), none overlapping.
Origin Session ID: dbd862d7-9868-430b-8150-7a1fe23827c0
Retrieval Hint: "rail reveal overlay focus ring focusReveal modality tabindex -1 user agent outline"
Context
The 13.2 notes frame D2 (
dock-d2-rail.pngin neomjs/pagesresources_pub/website/release-notes/v13.2.0/) shows a light-blue ring around the System Metrics overlay, which is revealed from the right edge rail. The operator (2026-10-10) saw no ring in the film takes or when using the rail by hand. Sampled pixels of the frame show the ring is#99C8FFwith a#101010edge. That is Chrome's default dark-scheme focus ring, not the overlay's designed border (--dock-reveal-border:--workstation-signalat 46% over--workstation-line, a teal-grey).The Problem
Whether the ring paints depends on what held focus before the reveal, not on the reveal itself. A real mouse click never paints it: Chrome's last-input heuristic says pointer. The film driver's rail step (
apps/workstation/tour/GestureDriver.mjs:673-704, #19127) clicks with synthetic events (detail0) and then callsbutton.focus()with no modality. That programmatic focus is focus-visible, and the overlay's programmatic focus inherits it. The frame is embedded in the 13.2 notes, and every scripted capture of a reveal can repeat it.The Architectural Reality
Rail#onRevealStateChange(src/dashboard/dock/interaction/Rail.mjs:740-741) callsRevealOverlay#focusReveal()when a tab click opens a reveal (revealed-focused).Rail#onTabClick(:777) receives the click payload, which carriesdetail(src/main/DomEvents.mjs:329).detailis ≥ 1 for a pointer click and 0 for a keyboard- or AT-activated one.focusReveal()(src/dashboard/dock/interaction/RevealOverlay.mjs:390-396) callsthis.focus(this.id, true)with no modality. The root istabIndex: -1.DomUtils.isFocusable(src/main/DomUtils.mjs:128-131) accepts a negative tab index, so the root itself takes focus.DomAccess#focus(src/main/DomAccess.mjs:358-400) stampsneo-focus-pointerfor'pointer'and says it "suppresses the accidental ring", but no stylesheet keys on that class. Only the Grid view styles its own focus (#18968,resources/scss/src/grid/View.scss:9-19). The contract is unbacked for all three callers that state'pointer':RevealOverlay.mjs:538,src/draggable/container/SortZone.mjs:681andsrc/grid/Body.mjs:1277.resources/scss/src/dashboard/Container.scss:916) and the arrival pulse (:372). A suppression rule must lose to every author rule and beat only the user agent's.Design authority:
DomAccess#focus(src/main/DomAccess.mjs:358-360): "explicit input-modality contract. :focus-visible cannot tie an async worker→main programmatic focus back to the originating pointer gesture, so the caller states it." The same method's comment says "'pointer' suppresses the accidental ring".The Fix
resources/scss/src/Global.scss::where(.neo-focus-pointer:focus-visible) {outline: none}. With zero specificity it beats only the user-agent ring, and any component outline still wins. TheDomAccess#focuscomment names this rule.Rail#onTabClickrecords the opening gesture's modality ('pointer'whendetail >= 1), andfocusReveal(modality)passes it tofocus(). A keyboard-opened reveal passes none, so the user agent's keyboard ring stays.detail: 1, as a real click does.Acceptance Criteria
detail: 1, and asserts that the focused overlay root's computedoutline-styleisnone. The arm is red ondev.outline-style: solidon a locked pane) and the dashboard e2e folder stay green.mainURL serves the new bytes.Out of Scope
Component keyboard rings keyed on
:focus-visibleinstead ofneo-focus-keyboard, and the look of the keyboard ring around the overlay root (it stays the user agent's).Related
#18968, #17317, #19339, #19127, #19506, #14800.
Sweeps: live latest-open sweep checked the latest 20 open issues at 13:33Z, no equivalent · A2A in-flight sweep: 30 messages, no overlapping claim · MC sweep: "rail reveal overlay focus ring, focusReveal modality" (5 results; #18968 and #19339 are the precedents, no decision that the overlay should carry the user-agent ring) · Own-assignment sweep: 2 open (#14800, #15000), none overlapping.
Origin Session ID: dbd862d7-9868-430b-8150-7a1fe23827c0 Retrieval Hint: "rail reveal overlay focus ring focusReveal modality tabindex -1 user agent outline"