Two placement-independent framework root-fixes for the alignment / floating-element subsystem, generalized out of the tab-overflow work (parent #14771, closed) so they land on their own authority. Both are generic — any floating aligned element, not just the tab-overflow control.
RA-9 — floating-button position: fixed cascade
resources/scss/src/button/Base.scss. A floating button carries both .neo-floating {position: fixed} (component/Base) and .neo-button {position: relative} (button/Base). Equal single-class specificity → .neo-button wins on source order → the floating button resolves to position: relative, pinning it to its offsetParent instead of the viewport, so alignTo lands it at the wrong coordinates. Fix: the compound .neo-button.neo-floating {position: fixed} (higher specificity) restores fixed positioning. Generic to any floating button.
RA-10 — null target-offsetParent observer guards
src/main/DomAccess.mjs. align() stores data.offsetParent = data.targetElement.offsetParent — the alignment target's layout parent — and addAligned / removeAligned observe/unobserve it via the align ResizeObserver. When the target's offsetParent is null — a position: fixed target (e.g. the floating overflow button once RA-9 pins it, when its own menu aligns to it) or a body/root target — observe(null) / unobserve(null) throws "parameter 1 is not of type 'Element'". Fix: null-guard both call sites.
Precise object model (the correction that motivated this leaf): the observed field belongs to the target, not the aligned subject. The subject's positioning (RA-9) and the target's null offsetParent (RA-10) are separate facts that co-occur when a menu aligns to a now-fixed button.
Evidence
Both fixes were exercised by the tab-overflow owner-exact-geometry L3 journey (passing on #15062's branch). The durable replay re-homes to #15099 (dense-workstation scene). No unit coverage: RA-9 is a CSS cascade (not unit-testable) and RA-10's guard is a main-thread DOM path — the e2e is the test-of-record.
Acceptance
Delivered by PR #15109. Parent #14771 (closed). Related: #15098 (tab-native successor, non-closing), #15099 (durable e2e replay).
Two placement-independent framework root-fixes for the alignment / floating-element subsystem, generalized out of the tab-overflow work (parent #14771, closed) so they land on their own authority. Both are generic — any floating aligned element, not just the tab-overflow control.
RA-9 — floating-button
position: fixedcascaderesources/scss/src/button/Base.scss. A floating button carries both.neo-floating {position: fixed}(component/Base) and.neo-button {position: relative}(button/Base). Equal single-class specificity →.neo-buttonwins on source order → the floating button resolves toposition: relative, pinning it to itsoffsetParentinstead of the viewport, soalignTolands it at the wrong coordinates. Fix: the compound.neo-button.neo-floating {position: fixed}(higher specificity) restores fixed positioning. Generic to any floating button.RA-10 — null target-offsetParent observer guards
src/main/DomAccess.mjs.align()storesdata.offsetParent = data.targetElement.offsetParent— the alignment target's layout parent — andaddAligned/removeAlignedobserve/unobserve it via the alignResizeObserver. When the target'soffsetParentis null — aposition: fixedtarget (e.g. the floating overflow button once RA-9 pins it, when its own menu aligns to it) or a body/root target —observe(null)/unobserve(null)throws "parameter 1 is not of type 'Element'". Fix: null-guard both call sites.Precise object model (the correction that motivated this leaf): the observed field belongs to the target, not the aligned subject. The subject's positioning (RA-9) and the target's null
offsetParent(RA-10) are separate facts that co-occur when a menu aligns to a now-fixed button.Evidence
Both fixes were exercised by the tab-overflow owner-exact-geometry L3 journey (passing on #15062's branch). The durable replay re-homes to #15099 (dense-workstation scene). No unit coverage: RA-9 is a CSS cascade (not unit-testable) and RA-10's guard is a main-thread DOM path — the e2e is the test-of-record.
Acceptance
.neo-button.neo-floatingresolves toposition: fixed(RA-9).offsetParentis null does not throw (RA-10).Delivered by PR #15109. Parent #14771 (closed). Related: #15098 (tab-native successor, non-closing), #15099 (durable e2e replay).