detector: catch glow shadows in any color format, zero-offset halos on any background, and text-shadow glows

- parseAnyColor now covers oklab(), hsl()/hsla(), hwb(), and ~35 common
  named colors on top of rgb/rgba/hex/oklch, so checkGlow sees the color
  regardless of authoring format (Chrome preserves oklch() in computed
  styles, which the old rgba-only match silently passed).
- checkGlow gains a second tell: a zero-offset chromatic box/text-shadow
  with blur > 4px is flagged on ANY background (the halo pattern);
  achromatic zero-offset shadows and focus rings stay legal. The
  existing chromatic-blur-on-dark-background rule is unchanged in
  semantics but now parses every color format.
- text-shadow is checked wherever box-shadow was (browser DOM path with
  inherited-value dedupe, static engine via new textShadow cascade
  support, text engines).
- The page-level text scan (regex engine + checkHtmlPatterns) is now a
  shared scanCssTextForGlow that resolves single-level var() refs
  against custom properties collected from the same text; unresolvable
  var() in a shadow color position is skipped, never guessed. Its
  dark-page heuristic accepts var()/oklch backgrounds but only when
  declared at root scope (body/html/:root or body inline style).
- dark-glow keeps its id; registry name/description updated to cover
  both cases.

Validated: three eval repro samples with oklch / var(--x) glows that
previously produced zero findings now flag on the static CLI path; ten
known-good largerun samples stay clean except one with genuine amber
status-dot halos (0 0 12px oklch(.73 .17 65/.4)).

Note: cli/engine/detect-antipatterns-browser.js and the extension
detector are generated and still need 'node scripts/build-browser-detector.js'
+ 'node scripts/build-extension.js' once builds are unblocked.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-07-10 11:01:54 -07:00
co-authored by Claude Fable 5
parent a38a0765a9
commit 0d72991bc8
7 changed files with 478 additions and 81 deletions
@@ -245,6 +245,10 @@ const STATIC_DEFAULT_STYLE = {
outlineColor: 'rgb(0, 0, 0)',
outlineStyle: 'none',
boxShadow: 'none',
// NOT in STATIC_INHERITED_PROPS even though text-shadow inherits in real
// CSS: the glow check only needs to fire once, on the element that
// declares the shadow, not on every descendant.
textShadow: 'none',
fontFamily: '',
fontSize: '16px',
fontStyle: 'normal',
@@ -302,6 +306,7 @@ const STATIC_PROP_MAP = {
'outline-color': 'outlineColor',
'outline-style': 'outlineStyle',
'box-shadow': 'boxShadow',
'text-shadow': 'textShadow',
'font-family': 'fontFamily',
'font-size': 'fontSize',
'font-style': 'fontStyle',