Clip the close button's hover glow at the frame edge; add a hover probe

Hovering the win7 X painted a red mark on the window border's far edge.
Diagnosed programmatically, per request, with a new scripts/hover-probe.ts:
Firefox headless has no pointer, so the probe copies the built stylesheet
with every `:hover` rewritten to a `.simhover` class, renders the app's exact
frame markup (w7-frame + direct-child title-bar + aria-label'd controls) with
the X force-hovered, and pixel-scans four regions for red-dominant pixels,
printing a verdict table and exiting non-zero on artifacts.

Verdict from the first run: the right border and the region beside it were
CLEAN — the reported mark is the glow escaping over the TOP edge. 7.css's
hover ::before carries box-shadow 0 0 7px 3px #e68e75, a child's box-shadow
is not clipped by the parent's border or radius, and the caption buttons sit
flush against the window's top edge (border-top: 0) — so 100 red pixels
landed above the frame: a tint across the top border and a halo floating on
the desktop past it.

Fix: clip-path inset(0 0 -1rem 0) on `.w7-frame > .title-bar` in skinfix. The
glow now dies at the frame border — where the real Win7 DWM stopped it — and
the bottom stays open so the authentic bleed toward the caption survives.
clip-path clips hit-testing too, but only outside the region; the drag area
is the title-bar's own box, entirely inside. Scoped to w7-frame so harness
and demo windows keep stock 7.css behaviour.

Verified: probe verdict now clean (escape regions 0, the intended in-frame
glow still measures 30 px — the effect survived, only the escape is gone);
the resting-state harness diffs exactly zero, so nothing but hover pixels
changed; tsc + build clean. The probe stays in scripts/ as the regression
test; gotchas.md records both the clipping rule and the :hover -> class
technique.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-16 18:29:21 +02:00
co-authored by Claude
parent 9c54a441a9
commit 89af52e1c0
3 changed files with 208 additions and 0 deletions
+19
View File
@@ -86,6 +86,25 @@ touching the adjacent code.
and per call, since the scale changes mid-session. The editor's canvas-based
`charWidth` is cached keyed on the computed font string for the same reason.
## Hover states and the frame edge
- **A child's box-shadow is NOT clipped by its parent's border or radius.** The
close button's hover glow (7.css: `0 0 7px 3px #e68e75` on a `::before`)
painted across the window's top border and onto the desktop beyond it — the
caption buttons sit flush against the top edge (`border-top: 0`), and the
frame's rounded transparent corners clip nothing. Fixed with
`clip-path: inset(0 0 -1rem 0)` on `.w7-frame > .title-bar`: glow stops at
the frame like the real DWM, bottom bleed (authentic) stays open. Note
clip-path also clips hit-testing — safe here because the drag region is the
title-bar's own box, entirely inside the clip.
- **Hover states CAN be tested headlessly**: `scripts/hover-probe.ts` copies
the built stylesheet with `:hover` rewritten to `.simhover`, renders the
frame markup with the state forced, and pixel-scans artifact regions,
exiting non-zero on hover-introduced red outside the frame. Firefox
`--screenshot` has no pointer and `import -window` captures the real
pointer's state, so the class rewrite is the only programmatic hover on this
machine. Re-run it after touching title-bar or hover styling.
## The two skin trees (`ui/src/app/skins/`)
- **`.win7` is not a name we may change.** `7.scoped.css` is precompiled with