diff --git a/docs/architecture.md b/docs/architecture.md index ce37b9a..309ad4f 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -429,12 +429,17 @@ zeroed); the frame reads the state off its own child with existing `maximized` signal rather than subscribing to `windowState` twice. **Selection band**: the file list's selected row is a FLAT Win7-Explorer blue -(`--w7-sel-bg/-bd` = `#cbe8f6`/`#26a0da`), not 7.css's `--w7-el-grad-h` — that -var is its Aero element-hover ramp and stays reserved for buttons and tabs, -which still want the gloss. The unfocused pane gets `--w7-sel-bg-idle/-bd-idle`, -Explorer's grey inactive selection; the band never disappears with focus, only -weakens (the commander convention above). All four are dark-overridden in BOTH -dark blocks. +(`--w7-sel-bg`, `#cbe8f6`) with **no border** — not 7.css's `--w7-el-grad-h`, +which is its Aero element-hover ramp and stays reserved for buttons and tabs +that still want the gloss, and not its `#aaddfa` row outline, which stacked a +second edge inside the fill and, with the cursor row's dotted rect, drew three +concentric outlines on one row. Every row still reserves `border: 1px solid +transparent` for geometry; the fill paints under it (`background-clip` +defaults to `border-box`). The unfocused pane gets `--w7-sel-bg-idle`, +Explorer's grey inactive selection — the band never disappears with focus, +only weakens (the commander convention above). Both are dark-overridden in +BOTH dark blocks. The context menu's item highlight uses the same +`--w7-sel-bg`, so selection reads identically wherever it appears. **Context menu**: pure 7.css via its real menu contract — `ul[role=menu] > li[role=menuitem] > button` for actions, @@ -446,9 +451,13 @@ one (`dist/gui/menu.css`), including the gutter stripe, disabled state and submenu arrows. Keyboard moves REAL focus between items (7.css styles `:focus-visible` like `:hover`); Enter/Space activate buttons natively. Only menu.css's hardcoded light literals are restated for dark, in `skinfix` — plus -one structural override: `.w7-ctx` restores `position: fixed`, which 7.css's own -`position: relative` on `ul[role=menu]` had been silently winning (see -gotchas.md; `scripts/menu-probe.ts` is the regression test). +three overrides keyed on the app's own `w7-ctx` marker: `position: fixed` +(7.css's `position: relative` on `ul[role=menu]` had been silently winning), +the flat `--w7-sel-bg` highlight in place of its gradient wash, and +`content: none` on the item buttons' pseudo-elements, which kills both the +1s Aero afterglow and the infinite `pulse-anim` on a focused item (see +gotchas.md). `scripts/menu-probe.ts` regression-tests placement AND highlight +flatness, each with a control that proves the check can fail. **Font**: Segoe UI is absent off Windows and not redistributable. Noto Sans — the substitute 7.css itself names — is vendored (OFL-1.1, from diff --git a/docs/gotchas.md b/docs/gotchas.md index d7c1c44..0dd9958 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -176,6 +176,20 @@ touching the adjacent code. bug**: nothing about the idle window changes. `scripts/menu-probe.ts` renders the menu at declared coordinates and scans whether it landed there, with a marker-less control menu as its own discriminator. +- **7.css's button effects reach anything that IS a button — including menu + items — and one of them fades out over a FULL SECOND.** `button::before` is + an Aero glow overlay with `opacity: 0`, raised to 1 on hover, and + `button:not(:hover):before` carries `transition: opacity 1s linear`. + menu.css suppresses it with `content: none` on the **`:hover` arm only**, so + while an item is hovered nothing paints, but the moment the pointer leaves, + the pseudo returns with opacity animating 1 → 0: a blue ghost trailing the + cursor down the menu. Killing `content` in *every* state is the fix — + suppressing the transition alone leaves a glow that simply snaps. Two more + from the same family: `button:focus` runs `pulse-anim` *infinitely* + (`1s ease infinite alternate`), which matters because the context menu moves + REAL focus between items for keyboard nav, and the hover paint is 7.css's + translucent gradient wash — the same one the ListView selection dropped. + All three are overridden together, scoped to `w7-ctx`. - **Its selectors are exact, and a near-miss looks exactly like "7.css doesn't support this".** `menu[role=tablist] button` is a DESCENDANT selector, so every button inside the strip becomes a tab — the `+` and the right-hand diff --git a/scripts/menu-probe.ts b/scripts/menu-probe.ts index 1b533c7..8ac9571 100644 --- a/scripts/menu-probe.ts +++ b/scripts/menu-probe.ts @@ -1,4 +1,4 @@ -// Programmatic POSITIONING test for the win7 context menu. +// Programmatic POSITIONING + HIGHLIGHT test for the win7 context menu. // // bun scripts/menu-probe.ts // @@ -16,6 +16,16 @@ // i.e. the bug verbatim. That one must stay invisible — if it ever shows up, // 7.css stopped forcing `relative` and this probe's premise is stale. // +// It also checks the item HIGHLIGHT, using hover-probe.ts's trick (`:hover` +// rewritten to a `.simhover` class, since headless Firefox has no pointer): +// 7.css paints hovered items with a translucent gradient wash, and this app +// wants one flat colour. A gradient is detectable as vertical colour spread +// down a text-free strip of the item, so "is it flat?" is a measurement, not +// an opinion. What canNOT be measured here is the 1s afterglow fade — a +// temporal effect — but its cause is structural (`button::before` still has +// `content`), and this probe would show the glow's colour if the pseudo ever +// came back. +// // Inherits shot.ts's constraints: dedicated Firefox profile (a running Firefox // holds the default profile's lock), and the page must be written INTO the // dist folder or strict_origin_policy silently unstyles it. @@ -35,6 +45,12 @@ if (!existsSync(DIST)) fail(`no build output at ${DIST} — run: bun run build:u const styles = readdirSync(DIST).find((f) => f.startsWith("styles-") && f.endsWith(".css")); if (!styles) fail(`no styles-*.css in ${DIST} — run: bun run build:ui`); +// Hover as a CLASS: same rewrite hover-probe.ts uses, for the same reason — +// `--screenshot` has no pointer. `:hover` has no partial-token hazard. +const css = await Bun.file(path.join(DIST, styles)).text(); +const PROBE_CSS = "_menu-probe.css"; +await Bun.write(path.join(DIST, PROBE_CSS), css.replaceAll(":hover", ".simhover")); + // ---- the probe page ---- // Geometry (CSS px = image px; headless Firefox applies no DPR scaling). @@ -51,7 +67,7 @@ const menu = (x: number, marker: boolean) => `