feat(plan): device markers are landmarks in the Plan editor

The Plan editor hid every device marker (display: none), so walls,
openings and stairs were placed against devices from memory. It now
shows them exactly as the Background editor does (#362): the same
markers as View, at the Background editor's effective opacity, fully
pointer-inert. The fade is filter: opacity(0.35) on each marker, not
on .devlayer, because room labels and room settings buttons share that
layer and stay opaque and interactive; filter multiplies the marker's
own opacity (.unavail -> 0.35 x 0.35), as the Background layer does.
Marker handlers already fail closed outside View/Devices.

demo/smoke_plan_device_landmarks.mjs proves AC1/AC2: same markers as
View, per-marker alpha equal to Background, core and capsule fall
through, a real click on a marker reaches the Walls tool and a room
settings button below, cursor and target unchanged, handlers inert, no
tabindex. Three mutants guard hiding, opacity override and the pointer
boundary. UX-MODES, DECOR-EDITOR, USER-GUIDE.ru mode table, changelogs.

Issue: #687
User-Visible: yes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
This commit is contained in:
Claude
2026-09-28 09:38:26 +03:00
parent cab4b4153a
commit 560849a1a7
9 changed files with 288 additions and 4 deletions
+13 -1
View File
@@ -1176,8 +1176,20 @@ export const planStyles = css`
.stage.markup .room {
pointer-events: none;
}
/* #687: devices are landmarks in the Plan editor too, exactly as in
Background (#362): the same markers as View, at the same 35% and fully
pointer-inert, so every Plan tool receives the point below them. The
fade sits on each marker, not on .devlayer: room labels share that
layer and stay opaque and interactive here. filter: opacity()
multiplies the marker's own opacity (.unavail), as the Background
layer opacity does. */
.stage.markup .devlayer .dev {
display: none; /* in plan mode the icons do not get in the way; labels stay */
filter: opacity(0.35);
}
.stage.markup .devlayer .dev,
.stage.markup .devlayer .dev *,
.stage.markup .devlayer .dev::before {
pointer-events: none;
}
/* mode frames: the edit modes are visible at a glance */
.stage.mode-plan {