From f4cb04f892f1bc34207951f77dcaea3cde80ff98 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 31 Aug 2026 16:49:25 -0700 Subject: [PATCH] Oracle: restore detector goldens to post-fix behavior after the engine ports The Aug 17-31 detector fixes (oklch parsing, color-mix nested hex, 1D grid pass, comment stripping, root-relative linked stylesheets, URL userinfo redaction, inert ignore-value refusal) and the comp-fidelity rules organic-clip-path / buried-raster are ported to the engine. Re-records the gap-pinning detect goldens from the fixed binary (glow.html included: its .photo-opaque-grad column now carries the buried-raster finding it was written for), replays the frozen checkHtmlPatterns call vectors through the last JS engine state in history (db1462b9^; args untouched, 14 of 101 results moved), and rewrites the DELTAS gap section into the landed-ports note. Each re-recorded json fixture golden byte-matches that JS state's output; oracle: 770 pass, 0 fail. Prepared with AI assistance (Claude Code). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01WaJv2c4oN8wS7Ttq4XRqyx --- tests/oracle/DELTAS.md | 61 +++++++++++++++---- .../golden/detect-dir-json-all-fixtures.json | 2 +- .../golden/detect-dir-quiet-all-fixtures.json | 2 +- .../golden/detect-dir-text-all-fixtures.json | 2 +- ...etect-fixture-json-buried-raster-html.json | 4 +- ...-fixture-json-codex-grid-1d-pass-html.json | 4 +- .../golden/detect-fixture-json-glow-html.json | 2 +- ...t-fixture-json-organic-clip-path-html.json | 2 +- ...etect-fixture-text-buried-raster-html.json | 4 +- ...-fixture-text-codex-grid-1d-pass-html.json | 4 +- .../golden/detect-fixture-text-glow-html.json | 2 +- ...t-fixture-text-organic-clip-path-html.json | 2 +- .../golden/detect-no-advisory-json.json | 2 +- .../golden/detect-no-advisory-text.json | 2 +- .../rules.checks/checkHtmlPatterns.jsonl | 28 ++++----- 15 files changed, 80 insertions(+), 43 deletions(-) diff --git a/tests/oracle/DELTAS.md b/tests/oracle/DELTAS.md index 22de13e94..b436e94e7 100644 --- a/tests/oracle/DELTAS.md +++ b/tests/oracle/DELTAS.md @@ -34,17 +34,54 @@ origin but not `'wasm-unsafe-eval'` still refuses to compile it. The JS - `live-inject-csp-meta-no-connect-src`: the patched `` reads `script-src 'self' http://localhost:8412 'wasm-unsafe-eval'` (was `script-src 'self' http://localhost:8412`). The `data-impeccable-csp-original` marker, the `connect-src` and `img-src` additions, idempotence, and the revert on unpatch are unchanged. `live-inject-vite-csp-meta` and `live-inject-next-jsx` carry meta tags the patch does not touch, so their goldens did not move. -## Recorded 2026-08-31: main's post-freeze fixture changes, goldens re-recorded from the engine +## Recorded 2026-08-31: detector-engine ports landed, gap goldens restored -The rebase onto main brought fixture updates whose paired JS rule changes have -not been ported to the engine yet. The detect goldens below are re-recorded -from the binary, so they pin the engine's current behavior on the new fixture -content; the entries name the upstream JS change each one still owes. Until a -rule ships in the engine and its golden is re-recorded, the golden is the pin -of the gap, not an endorsement of it. +The section previously here pinned the gap between main's post-freeze detector +fixes and the engine. Those fixes are now ported (engine repo commits: +`c0aa75f` oklch in visual-contrast/neon-text, upstream 1b7da15b #592; +`5cdeec8` color-mix nested hex, upstream 54440319 #578; the 1D grid fix, +upstream a236137b #615, rode along in `9046e8f` via a concurrent staging race; +`6d36231` comment stripping for regex matchers, upstream 067665cc #589 + +ddb60993 + ba873f75 + 9a7d0fbc; `33aef88` root-relative linked stylesheets, +upstream 2b88aa52 #652 + daae1d41; `6d0ecf1` URL userinfo redaction with +origin-scoped basic auth, upstream d5873ff8 + d690349d #657; `09f8ae7` inert +exact ignore-value refusal, upstream be87f5eb #662; `20c8347` the +comp-fidelity rules organic-clip-path and buried-raster, upstream 58561610). +The affected goldens were re-recorded from the fixed engine and each json +fixture golden was byte-verified against the last JS engine state in history +(`db1462b9^`, which carries both main's drift and the comp-fidelity rules): -- `detect-fixture-json-color-html`, `detect-fixture-text-color-html`: the fixture gained the color-mix nested-hex column (upstream 54440319, #578, with explicit sizes from 7426af44); the engine still reads hex codes inside `color-mix(...)` when measuring gradient contrast, so its readings on the reshaped fixture differ from the JS engine's. -- `detect-fixture-json-oklch-neon-text-html`, `detect-fixture-text-oklch-neon-text-html`: new fixture for oklch parsing in visual-contrast and neon-text (upstream 1b7da15b, #592, columns from 8347d77f); the engine does not parse oklch there yet, so the flag column's neon-text goes unflagged and a mis-read low-contrast is recorded. -- `detect-fixture-json-codex-grid-1d-pass-html`, `detect-fixture-text-codex-grid-1d-pass-html`: new pass-case fixture for 1D dashed rules (upstream a236137b/7ddcd533, #615); the engine still flags the 1D line-field as `codex-grid-background`, which is the pre-fix behavior the fixture exists to retire. -- `detect-fixture-json-organic-clip-path-html`, `detect-fixture-text-organic-clip-path-html`, `detect-fixture-json-buried-raster-html`, `detect-fixture-text-buried-raster-html`: fixtures for the two comp-fidelity rules (upstream 58561610: organic-clip-path, buried-raster); neither rule exists in the engine, so only incidental findings (or none) are recorded. -- `detect-dir-json-all-fixtures`, `detect-dir-text-all-fixtures`, `detect-dir-quiet-all-fixtures`, `detect-scope-type`, `detect-scope-both`, `detect-no-advisory-json`, `detect-no-advisory-text`: directory-wide sweeps over `tests/fixtures/antipatterns/`; re-recorded because the fixture set above grew and changed, shifting counts and orderings. +- Moved to post-fix behavior: `detect-fixture-json-codex-grid-1d-pass-html`, + `detect-fixture-text-codex-grid-1d-pass-html` (no finding, exit 0), + `detect-fixture-json-organic-clip-path-html`, + `detect-fixture-text-organic-clip-path-html`, + `detect-fixture-json-buried-raster-html`, + `detect-fixture-text-buried-raster-html` (the new rules fire), + `detect-fixture-json-glow-html`, `detect-fixture-text-glow-html` (glow's + `.photo-opaque-grad` column now carries its intended buried-raster finding), + and the sweeps `detect-dir-json-all-fixtures`, `detect-dir-text-all-fixtures`, + `detect-dir-quiet-all-fixtures`, `detect-no-advisory-json`, + `detect-no-advisory-text`. +- Unchanged on re-record (already matched the fixed JS in the static engine): + `detect-fixture-json-color-html`, `detect-fixture-text-color-html`, + `detect-fixture-json-oklch-neon-text-html`, + `detect-fixture-text-oklch-neon-text-html` (the oklch and color-mix fixes + observably change the browser-side visual-contrast path, which these static + scans do not exercise), `detect-scope-type`, `detect-scope-both`. + +The frozen call vectors for `checkHtmlPatterns` +(`tests/oracle/vectors/calls/rules.checks/checkHtmlPatterns.jsonl`) were +re-recorded the same way: args untouched, results replayed through the +`db1462b9^` JS (14 of 101 moved: the comp-fidelity scans and the +comment-stripping/inline-fragment fixes to `enclosingCssSelector`). No case in +this section is an accepted delta any more; the engine matches the final JS. + +## Recorded 2026-08-31: main's Aug 17-31 verb fixes ported to the engine, goldens re-recorded + +The goldens below froze pre-fix behavior. Each fix landed on main in JS and +was ported to the engine; the cases were re-recorded from the binary and +reviewed line by line, so they now pin the fixed behavior. + +- `hook-session-fresh-then-pending-then-stop`, `hook-session-two-sessions`: the Stop deep pass syncs the remembered set to the live scan, including findings the per-edit pass already surfaced, so a second Stop with nothing new is silent and a fixed-then-reintroduced finding fires again (upstream 3c442af7). +- `hadmin-on`, `hadmin-on-twice`, `hadmin-off-then-status`, `hadmin-on-repairs-existing-manifest`, `hadmin-on-malformed-manifest-backup`: the Claude manifests `hooks on` writes match on `Edit|Write` and the description names the current tools; Claude Code folded multi-edit behavior into Edit (upstream 7d5c60d2). +- `live-commit-mock-unreported-file-change`: the rollback-failure results share one constructor, which moved `unreportedFiles` and `notes` after `pageUrl` in the emitted JSON (upstream 1f2c3f9d). diff --git a/tests/oracle/golden/detect-dir-json-all-fixtures.json b/tests/oracle/golden/detect-dir-json-all-fixtures.json index 09985b007..e77279322 100644 --- a/tests/oracle/golden/detect-dir-json-all-fixtures.json +++ b/tests/oracle/golden/detect-dir-json-all-fixtures.json @@ -1,5 +1,5 @@ { - "stdout": "[\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 52,\n \"snippet\": \"[data-case=\\\"Kinpaku Edge\\\"] — inset box-shadow 3px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 53,\n \"snippet\": \"[data-case=\\\"Patina Edge\\\"] — inset box-shadow 3px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 54,\n \"snippet\": \"[data-case=\\\"Accent Edge\\\"] — inset box-shadow 4px stripe (right)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 55,\n \"snippet\": \"[data-case=\\\"Signal Blue Edge\\\"] — inset box-shadow 5px stripe (top)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 66,\n \"snippet\": \"[data-case=\\\"Chromatic Hex Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 67,\n \"snippet\": \"[data-case=\\\"Named Red Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 68,\n \"snippet\": \"[data-case=\\\"Chromatic Rgb Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 69,\n \"snippet\": \"[data-case=\\\"Chromatic Oklch Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 78,\n \"snippet\": \"[data-case=\\\"Trailing Inset Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 79,\n \"snippet\": \"[data-case=\\\"Trailing Inset Token Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 81,\n \"snippet\": \"[data-case=\\\"Inset Named Token Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 86,\n \"snippet\": \"[data-case=\\\"Two Length Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 87,\n \"snippet\": \"[data-case=\\\"Two Length Trailing Inset Edge\\\"] — inset box-shadow 5px stripe (top)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 88,\n \"snippet\": \"[data-case=\\\"Important Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 89,\n \"snippet\": \"[data-case=\\\"Cascade Override Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 91,\n \"snippet\": \"[data-case=\\\"Color First Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/astro-inset-shadow-stripe.astro\",\n \"line\": 92,\n \"snippet\": \"[data-case=\\\"Color First Var Edge\\\"] — inset box-shadow 4px stripe (left)\"\n },\n {\n \"antipattern\": \"pulsing-dot\",\n \"name\": \"Pulsing status dot\",\n \"description\": \"Small pulsing status dots simulate liveness decoratively. Reserve pulse animation for indicators tied to genuinely live, changing data; a static indicator with clear labeling is honest and calmer.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/blinking-cursor.html\",\n \"line\": 0,\n \"snippet\": \".pass-round-dot — 8x8px dot with infinite \\\"blink-anim\\\" animation\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/border-baseline.html\",\n \"line\": 0,\n \"snippet\": \"border-left: 4px + border-radius: 10px\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/border-baseline.html\",\n \"line\": 0,\n \"snippet\": \"border-right: 5px + border-radius: 10px\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/border-baseline.html\",\n \"line\": 0,\n \"snippet\": \"border-left: 4px\"\n },\n {\n \"antipattern\": \"border-accent-on-rounded\",\n \"name\": \"Border accent on rounded element\",\n \"description\": \"Thick accent border on a rounded card — the border clashes with the rounded corners. Remove the border or the border-radius.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/border-baseline.html\",\n \"line\": 0,\n \"snippet\": \"border-top: 4px + border-radius: 10px\"\n },\n {\n \"antipattern\": \"border-accent-on-rounded\",\n \"name\": \"Border accent on rounded element\",\n \"description\": \"Thick accent border on a rounded card — the border clashes with the rounded corners. Remove the border or the border-radius.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/border-baseline.html\",\n \"line\": 0,\n \"snippet\": \"border-bottom: 3px + border-radius: 10px\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/border-baseline.html\",\n \"line\": 0,\n \"snippet\": \"border-left: 4px + border-radius: 10px\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/border-baseline.html\",\n \"line\": 0,\n \"snippet\": \"border-top: 4px\"\n },\n {\n \"antipattern\": \"side-tab\",\n \"name\": \"Side-tab accent border\",\n \"description\": \"Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/border-baseline.html\",\n \"line\": 0,\n \"snippet\": \"border-bottom: 3px\"\n },\n {\n \"antipattern\": \"cramped-padding\",\n \"name\": \"Cramped padding\",\n \"description\": \"Text is too close to the edge of its container. Two shapes: (1) an element with its own text where the padding is too low for the font size, and (2) a wrapper with text-bearing children and near-zero padding against a visible boundary (border, outline, or non-transparent background) — children land flush against the boundary line. Add at least 8px (ideally 12–16px) of padding inside bordered, outlined, or colored containers.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/clipped-overflow-container.html\",\n \"line\": 0,\n \"snippet\": \"
\\\"pass-split-container\\\": children flush against border on all sides (no inset)\"\n },\n {\n \"antipattern\": \"clipped-overflow-container\",\n \"name\": \"Positioned child clipped by overflow container\",\n \"description\": \"A clipping container (overflow hidden or clip) wrapping an absolutely-positioned child cuts off tooltips, menus, and popovers that need to escape. Let the overflow be visible, or move the positioned layer out of the clip.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/clipped-overflow-container.html\",\n \"line\": 0,\n \"snippet\": \"div.box.flag-overflow-hidden clips a positioned child\"\n },\n {\n \"antipattern\": \"clipped-overflow-container\",\n \"name\": \"Positioned child clipped by overflow container\",\n \"description\": \"A clipping container (overflow hidden or clip) wrapping an absolutely-positioned child cuts off tooltips, menus, and popovers that need to escape. Let the overflow be visible, or move the positioned layer out of the clip.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/clipped-overflow-container.html\",\n \"line\": 0,\n \"snippet\": \"div.box.flag-overflow-clip clips a positioned child\"\n },\n {\n \"antipattern\": \"clipped-overflow-container\",\n \"name\": \"Positioned child clipped by overflow container\",\n \"description\": \"A clipping container (overflow hidden or clip) wrapping an absolutely-positioned child cuts off tooltips, menus, and popovers that need to escape. Let the overflow be visible, or move the positioned layer out of the clip.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/clipped-overflow-container.html\",\n \"line\": 0,\n \"snippet\": \"div.box.flag-overflow-negative clips a positioned child\"\n },\n {\n \"antipattern\": \"clipped-overflow-container\",\n \"name\": \"Positioned child clipped by overflow container\",\n \"description\": \"A clipping container (overflow hidden or clip) wrapping an absolutely-positioned child cuts off tooltips, menus, and popovers that need to escape. Let the overflow be visible, or move the positioned layer out of the clip.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/clipped-overflow-container.html\",\n \"line\": 0,\n \"snippet\": \"div.box.flag-overflow-right clips a positioned child\"\n },\n {\n \"antipattern\": \"clipped-overflow-container\",\n \"name\": \"Positioned child clipped by overflow container\",\n \"description\": \"A clipping container (overflow hidden or clip) wrapping an absolutely-positioned child cuts off tooltips, menus, and popovers that need to escape. Let the overflow be visible, or move the positioned layer out of the clip.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/clipped-overflow-container.html\",\n \"line\": 0,\n \"snippet\": \"div.box.flag-shadow-utility clips a positioned child\"\n },\n {\n \"antipattern\": \"clipped-overflow-container\",\n \"name\": \"Positioned child clipped by overflow container\",\n \"description\": \"A clipping container (overflow hidden or clip) wrapping an absolutely-positioned child cuts off tooltips, menus, and popovers that need to escape. Let the overflow be visible, or move the positioned layer out of the clip.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/clipped-overflow-container.html\",\n \"line\": 0,\n \"snippet\": \"div.box.flag-overlay-surface clips a positioned child\"\n },\n {\n \"antipattern\": \"codex-grid-background\",\n \"name\": \"Decorative grid-line background\",\n \"description\": \"A decorative grid or line-field background drawn with hairline linear-gradient layers tiled by a fixed pixel cell is a recurring generated-UI signature. Reserve grid overlays for actual canvas, map, blueprint, or measurement surfaces; elsewhere use product structure or a plain surface.\",\n \"severity\": \"advisory\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/codex-grid-1d-pass.html\",\n \"line\": 0,\n \"snippet\": \"px-tiled hairline line-field background\"\n },\n {\n \"antipattern\": \"gray-on-color\",\n \"name\": \"Gray text on colored background\",\n \"description\": \"Gray text looks washed out on colored backgrounds. Use a darker shade of the background color instead, or white/near-white for contrast.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"text #969696 on bg #3b82f6\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"1.2:1 (need 4.5:1) — text #969696 on #3b82f6\"\n },\n {\n \"antipattern\": \"gray-on-color\",\n \"name\": \"Gray text on colored background\",\n \"description\": \"Gray text looks washed out on colored backgrounds. Use a darker shade of the background color instead, or white/near-white for contrast.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"text #b4b4b4 on bg #10b981\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"1.2:1 (need 4.5:1) — text #b4b4b4 on #10b981\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"1.7:1 (need 4.5:1) — text #c8c8c8 on #ffffff\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"2.1:1 (need 4.5:1) — text #505050 on #1e1e1e\"\n },\n {\n \"antipattern\": \"gray-on-color\",\n \"name\": \"Gray text on colored background\",\n \"description\": \"Gray text looks washed out on colored backgrounds. Use a darker shade of the background color instead, or white/near-white for contrast.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"text #808080 on bg gradient(#3b82f6, #8b5cf6)\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"1.1:1 (need 3:1) — text #808080 on #8b5cf6\"\n },\n {\n \"antipattern\": \"gray-on-color\",\n \"name\": \"Gray text on colored background\",\n \"description\": \"Gray text looks washed out on colored backgrounds. Use a darker shade of the background color instead, or white/near-white for contrast.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"text #666666 on bg gradient(#3b82f6, #8b5cf6)\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"1.4:1 (need 4.5:1) — text #666666 on #8b5cf6\"\n },\n {\n \"antipattern\": \"gradient-text\",\n \"name\": \"Gradient text\",\n \"description\": \"Gradient text is decorative rather than meaningful — a common AI tell, especially on headings and metrics. Use solid colors for text.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"background-clip: text + gradient\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"2.2:1 (need 4.5:1) — text #5b4f44 on #1f1a15\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"2.1:1 (need 4.5:1) — text #6c7280 on #374151\"\n },\n {\n \"antipattern\": \"gray-on-color\",\n \"name\": \"Gray text on colored background\",\n \"description\": \"Gray text looks washed out on colored backgrounds. Use a darker shade of the background color instead, or white/near-white for contrast.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"text #5c5449 on bg #b6322d\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"1.2:1 (need 4.5:1) — text #5c5449 on #b6322d\"\n },\n {\n \"antipattern\": \"gray-on-color\",\n \"name\": \"Gray text on colored background\",\n \"description\": \"Gray text looks washed out on colored backgrounds. Use a darker shade of the background color instead, or white/near-white for contrast.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"text-gray-400 on bg-blue-500\"\n },\n {\n \"antipattern\": \"gray-on-color\",\n \"name\": \"Gray text on colored background\",\n \"description\": \"Gray text looks washed out on colored backgrounds. Use a darker shade of the background color instead, or white/near-white for contrast.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"text #9ca3af on bg #3b82f6\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"1.4:1 (need 4.5:1) — text #9ca3af on #3b82f6\"\n },\n {\n \"antipattern\": \"ai-color-palette\",\n \"name\": \"AI color palette\",\n \"description\": \"Purple/violet gradients and cyan-on-dark are the most recognizable tells of AI-generated UIs. Choose a distinctive, intentional palette.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"Purple/violet text (#a855f7) on heading\"\n },\n {\n \"antipattern\": \"ai-color-palette\",\n \"name\": \"AI color palette\",\n \"description\": \"Purple/violet gradients and cyan-on-dark are the most recognizable tells of AI-generated UIs. Choose a distinctive, intentional palette.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"text-purple-500 on heading\"\n },\n {\n \"antipattern\": \"ai-color-palette\",\n \"name\": \"AI color palette\",\n \"description\": \"Purple/violet gradients and cyan-on-dark are the most recognizable tells of AI-generated UIs. Choose a distinctive, intentional palette.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"Purple/violet gradient (Tailwind)\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"4.0:1 (need 4.5:1) — text #ffffff on #a855f7\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"1.1:1 (need 4.5:1) — text #3d2418 on #17372d\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"1.3:1 (need 4.5:1) — text #cfc9bd on #e8e2d6\"\n },\n {\n \"antipattern\": \"low-contrast\",\n \"name\": \"Low contrast text\",\n \"description\": \"Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"4.1:1 (need 4.5:1) — text #ffffff on #7d7d7d\"\n },\n {\n \"antipattern\": \"gradient-text\",\n \"name\": \"Gradient text\",\n \"description\": \"Gradient text is decorative rather than meaningful — a common AI tell, especially on headings and metrics. Use solid colors for text.\",\n \"severity\": \"warning\",\n \"category\": \"slop\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"background-clip: text + gradient\"\n },\n {\n \"antipattern\": \"undersized-ui-text\",\n \"name\": \"Undersized functional text\",\n \"description\": \"Interactive and content-bearing UI text (links, buttons, nav items, labels, table cells, meta rows, timecodes) below 11px is a legibility failure, not a style choice. WCAG sets no absolute pixel floor, but functional text under 11px is a defensible quality bar: it fails on high-DPI and small viewports and it degrades tap and read targets. The 11px floor holds even inside a footer; only non-interactive legal smallprint gets the softer 10px floor. Being ON the DESIGN.md size ramp does not exempt a value here: adding 8px to the ramp launders the token but not the legibility problem, and that is exactly the escape hatch this rule closes. Exempts sup/sub, visually-hidden (sr-only) text, and code/terminal contexts. Decorative letterspaced micro-labels are still functional and stay in scope.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"8px functional text \\\"tick\\\" (below 11px floor)\"\n },\n {\n \"antipattern\": \"skipped-heading\",\n \"name\": \"Skipped heading level\",\n \"description\": \"Heading levels should not skip (e.g. h1 then h3 with no h2). Screen readers use heading hierarchy for navigation. Skipping levels breaks the document outline.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"

\\\"Welcome to Our Platform\\\" followed by

\\\"Gradient text\\\" (missing h2)\"\n },\n {\n \"antipattern\": \"skipped-heading\",\n \"name\": \"Skipped heading level\",\n \"description\": \"Heading levels should not skip (e.g. h1 then h3 with no h2). Screen readers use heading hierarchy for navigation. Skipping levels breaks the document outline.\",\n \"severity\": \"warning\",\n \"category\": \"quality\",\n \"file\": \"/tests/fixtures/antipatterns/color.html\",\n \"line\": 0,\n \"snippet\": \"

\\\"Purple heading text\\\" followed by

\\\"Styled and \n
    Dropdown that gets clipped by the hidden ancestor
\n

\n
\n \n Tooltip clipped by overflow clip\n
\n
\n \n Tooltip clipped above the host\n
\n
\n \n
Flyout menu clipped to the right of the host
\n
\n
\n \n
Dropdown with utility classes still gets clipped.
\n
\n
\n \n
Overlay-style dialog content still needs to escape.
\n
\n \n\n \n
\n
\n

Hidden container with only static content.

\n
\n
\n \n Positioned child can escape because overflow is visible.\n
\n
\n \n A genuine scroll region is allowed to contain positioned children.\n
\n
\n

Positioned decoration remains inside the clipping box.

\n \n
\n \n
\n \n
\n
\n

Mockup frame with a contained absolute overlay.

\n \n
\n \n
\n \n
\n
\n
Before/after comparison panel clipped by the split frame.
\n
\n
\n \n\n\n",{"styleText":"\n body { font-family: system-ui, sans-serif; margin: 0; color: #1a1a1a; background: #fff; }\n .cols { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; padding: 24px; }\n .col { padding: 16px; }\n .box { position: relative; width: 200px; height: 120px; margin: 0 0 24px; padding: 16px; border: 1px solid #ddd; }\n .pop { position: absolute; top: 100%; left: 0; width: 220px; background: #222; color: #fff; padding: 8px; }\n .tip-negative { position: absolute; top: -34px; left: 16px; width: 160px; background: #222; color: #fff; padding: 8px; }\n .flyout { position: absolute; top: 28px; left: 100%; width: 180px; background: #222; color: #fff; padding: 8px; }\n .contained-badge { position: absolute; top: 10px; right: 10px; width: 36px; height: 24px; background: #e5f0ff; }\n .button-shine { position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,.6), transparent); }\n .crop-photo { position: absolute; inset: -18px; background: linear-gradient(135deg, #b7d7ff, #486aa3); }\n .inside-overlay { position: absolute; left: 12px; right: 12px; bottom: 12px; min-height: 28px; background: rgba(255,255,255,.86); }\n .pass-hidden-button { position: relative; overflow: hidden; width: 160px; height: 52px; border: 1px solid #ddd; background: #111; color: #fff; }\n .pass-carousel-viewport,\n .pass-fisheye-list,\n .pass-split-container {\n position: relative;\n overflow: hidden;\n width: 200px;\n height: 120px;\n margin: 0 0 24px;\n border: 1px solid #ddd;\n }\n .carousel-slide-next { position: absolute; top: 100%; left: 0; width: 100%; height: 100%; padding: 16px; background: #f5f5f5; }\n .fisheye-next-item { position: absolute; top: 100%; left: 0; width: 100%; padding: 8px; background: none; border: 0; text-align: left; }\n .split-after-panel { position: absolute; top: 0; left: 50%; width: 100%; height: 100%; background: #f5f5f5; }\n \nstyle=\"overflow: hidden\"\nstyle=\"overflow: clip\"\nstyle=\"overflow: hidden\"\nstyle=\"overflow: hidden\"\nstyle=\"overflow: hidden\"\nstyle=\"overflow: clip\"\nstyle=\"overflow: hidden\"\nstyle=\"position: static\"\nstyle=\"overflow: visible\"\nstyle=\"overflow: auto\"\nstyle=\"overflow: hidden\"\nstyle=\"overflow: hidden\"\nstyle=\"overflow: clip\"","classText":"cols\ncol flag\nbox flag-overflow-hidden\npop\nbox flag-overflow-clip\npop\nbox flag-overflow-negative\ntip-negative\nbox flag-overflow-right\nflyout\nbox flag-shadow-utility\npop bg-white shadow-lg\nbox flag-overlay-surface\npop modal-overlay\ncol pass\nbox pass-hidden-no-abs\nbox pass-visible-abs\npop\nbox pass-scroll-abs\npop\nbox pass-contained-abs\ncontained-badge\npass-hidden-button pass-button-shine\nbutton-shine\nbox pass-crop-photo\ncrop-photo\nbox pass-contained-overlay\ninside-overlay\npass-carousel-viewport\ncarousel-slide-next\npass-fisheye-list\nfisheye-next-item\npass-split-container\nsplit-after-panel"}],"result":[]} -{"args":["\n\n\n \n \n Color Anti-Patterns — Should Flag vs Should Pass\n \n\n\n
\n\n \n
\n

Should flag

\n\n

Pure black surfaces

\n
\n

Pure #000 background

\n
\n\n

Gray on color

\n
\n

Gray text on blue background

\n
\n
\n

Gray text on green background

\n
\n\n

Low contrast

\n
\n

Light gray text on white — very low contrast

\n
\n
\n

Dark gray text on near-black — low contrast

\n
\n \n
\n

Welcome to Our Platform

\n

The best solution for modern teams and businesses

\n
\n\n

Gradient text

\n

\n Gradient Heading\n

\n\n

AI color palette

\n

Purple heading text

\n\n

Styled <a> and <button> with low contrast

\n \n
Get started\n \n \n\n

Text-bearing chip with low contrast

\n \n SEV-2\n\n

Tailwind color anti-patterns

\n
\n

bg-black — pure black bg

\n
\n
\n

text-gray-400 on bg-blue-500 — gray on color

\n
\n

text-purple-500 heading

\n
\n

Purple-to-indigo gradient

\n
\n\n

currentcolor surface via var() token

\n \n
\n

Faint warm gray on a bone currentcolor surface

\n
\n
\n\n \n
\n

Should pass

\n\n

Tinted neutrals

\n
\n

Near-black bg, near-white text — tinted, not pure

\n
\n
\n

Near-white bg, near-black text — good contrast, tinted

\n
\n\n

Pure white surface is acceptable

\n
\n

Pure #fff background with dark text — acceptable contrast

\n
\n\n

Good contrast

\n
\n

Near-white text on dark blue — high contrast, not pure white

\n
\n
\n

Dark green text on green bg — same hue family

\n
\n\n

Distinctive accents (not AI purple)

\n

Red heading — not AI purple

\n

Amber heading — distinctive

\n\n

Background-image url() ancestor (not low contrast)

\n \n
\n

White text on image background — should not flag low-contrast

\n
\n\n

Tailwind opacity-modified bg-black (not pure black)

\n \n
\n

bg-black/3 — 3% opacity, not pure black

\n
\n
\n

hover:bg-black/5 — hover state, not pure black

\n
\n
\n

bg-black/50 — 50% opacity, not pure black

\n
\n\n

Inline <a> without own background (must remain skipped)

\n \n

Read more about this here if you want to learn more about the topic.

\n\n

Styled <a> with good contrast (must not flag)

\n \n
High contrast pill\n\n

Chip with good contrast (must not flag)

\n HEALTHY\n\n

Sub-9px decorative chip (below the font floor, must not flag)

\n tick\n\n

background: none resets an earlier background-color

\n \n
\n
light text over the dark panel, not the light code surface
\n
\n\n

Gradient-clipped text (issue #409 Case A — must not flag contrast)

\n \n

Gradient Clipped Heading Text

\n\n

Faint accent-glow gradient (issue #409 Case B — must not flag contrast)

\n \n
\n
\n

Light body copy on a faint accent glow that composites to near-black

\n

Muted secondary line on the same faint glow area here

\n
\n
\n\n

color-mix gradient stop: nested ingredient is not a surface

\n
\n
\n

Light copy on a faint mixed wash over a dark ground stays readable

\n
\n
\n\n

currentcolor surface with good contrast

\n
\n

Dark ink text on a bone currentcolor surface

\n
\n\n

currentcolor surface with unresolvable token (must abstain)

\n \n
\n

Light text on an unknowable currentcolor surface

\n
\n\n

Emoji on light backgrounds

\n \n
\n

⚠️ 🚨 ✨ 🎨

\n
\n
\n

⚠️ 🚨 ✨ 🎨

\n
\n
\n
\n \n\n\n",{"styleText":"\n body { font-family: system-ui, sans-serif; background: #fafafa; padding: 24px; margin: 0; color: #1a1a1a; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1200px; margin: 0 auto; }\n .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .col h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; margin: 24px 0 8px; color: #64748b; }\n .card { padding: 14px 16px; border-radius: 10px; margin-bottom: 10px; }\n /* Styled button color cases (declared via stylesheet so jsdom resolves them\n reliably — inline color doesn't always win over user-agent rules in jsdom\n for and \n\n

Text-bearing chip with low contrast

\n \n SEV-2\n\n

Tailwind color anti-patterns

\n
\n

bg-black — pure black bg

\n
\n
\n

text-gray-400 on bg-blue-500 — gray on color

\n
\n

text-purple-500 heading

\n
\n

Purple-to-indigo gradient

\n
\n\n

currentcolor surface via var() token

\n \n
\n

Faint warm gray on a bone currentcolor surface

\n
\n \n\n \n
\n

Should pass

\n\n

Tinted neutrals

\n
\n

Near-black bg, near-white text — tinted, not pure

\n
\n
\n

Near-white bg, near-black text — good contrast, tinted

\n
\n\n

Pure white surface is acceptable

\n
\n

Pure #fff background with dark text — acceptable contrast

\n
\n\n

Good contrast

\n
\n

Near-white text on dark blue — high contrast, not pure white

\n
\n
\n

Dark green text on green bg — same hue family

\n
\n\n

Distinctive accents (not AI purple)

\n

Red heading — not AI purple

\n

Amber heading — distinctive

\n\n

Background-image url() ancestor (not low contrast)

\n \n
\n

White text on image background — should not flag low-contrast

\n
\n\n

Tailwind opacity-modified bg-black (not pure black)

\n \n
\n

bg-black/3 — 3% opacity, not pure black

\n
\n
\n

hover:bg-black/5 — hover state, not pure black

\n
\n
\n

bg-black/50 — 50% opacity, not pure black

\n
\n\n

Inline <a> without own background (must remain skipped)

\n \n

Read more about this here if you want to learn more about the topic.

\n\n

Styled <a> with good contrast (must not flag)

\n \n High contrast pill\n\n

Chip with good contrast (must not flag)

\n HEALTHY\n\n

Sub-9px decorative chip (below the font floor, must not flag)

\n tick\n\n

background: none resets an earlier background-color

\n \n
\n
light text over the dark panel, not the light code surface
\n
\n\n

Gradient-clipped text (issue #409 Case A — must not flag contrast)

\n \n

Gradient Clipped Heading Text

\n\n

Faint accent-glow gradient (issue #409 Case B — must not flag contrast)

\n \n
\n
\n

Light body copy on a faint accent glow that composites to near-black

\n

Muted secondary line on the same faint glow area here

\n
\n
\n\n

color-mix gradient stop: nested ingredient is not a surface

\n
\n
\n

Light copy on a faint mixed wash over a dark ground stays readable

\n
\n
\n\n

currentcolor surface with good contrast

\n
\n

Dark ink text on a bone currentcolor surface

\n
\n\n

currentcolor surface with unresolvable token (must abstain)

\n \n
\n

Light text on an unknowable currentcolor surface

\n
\n\n

Emoji on light backgrounds

\n \n
\n

⚠️ 🚨 ✨ 🎨

\n
\n
\n

⚠️ 🚨 ✨ 🎨

\n
\n
\n \n \n\n\n",{"styleText":"\n body { font-family: system-ui, sans-serif; background: #fafafa; padding: 24px; margin: 0; color: #1a1a1a; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1200px; margin: 0 auto; }\n .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .col h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; margin: 24px 0 8px; color: #64748b; }\n .card { padding: 14px 16px; border-radius: 10px; margin-bottom: 10px; }\n /* Styled button color cases (declared via stylesheet so jsdom resolves them\n reliably — inline color doesn't always win over user-agent rules in jsdom\n for and \n \n
\n form input: 16px font, 8px / 12px padding\n \n
\n\n

Big text with proportional padding

\n
\n 24px heading, 16px padding\n
Heading With Room To Breathe
\n
\n
\n 32px hero, 20px / 32px padding\n
Hero With Big Padding
\n
\n \n \n \n\n\n",{"styleText":"\n /* Comprehensive fixture for the cramped-padding rule.\n Both columns include a wide variety of cases so we can verify the\n rule scales sensibly with font-size and treats the two axes\n independently (vertical can be tighter because line-height already\n provides built-in breathing room; horizontal has no equivalent). */\n body { font-family: system-ui, sans-serif; background: #fafafa; padding: 24px; margin: 0; color: #0f172a; line-height: 1.5; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1400px; margin: 0 auto; }\n .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .col h3 { font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; margin: 28px 0 10px; color: #64748b; }\n .case { margin-bottom: 14px; padding: 14px 16px; background: white; border: 1px solid #e2e8f0; border-radius: 10px; }\n .case-label { display: block; font-size: 12px; color: #64748b; margin-bottom: 8px; font-style: italic; }\n\n /* ── FLAG: cramped body in cards ── */\n .flag-card-4 { padding: 4px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; }\n .flag-card-2 { padding: 2px; background: #f1f5f9; border-radius: 6px; font-size: 14px; }\n .flag-card-bg4 { padding: 4px; background: #fef3c7; border-radius: 6px; font-size: 16px; }\n\n /* ── FLAG: asymmetric cramping ── */\n .flag-asym-v { padding: 1px 16px; background: #f1f5f9; border-radius: 6px; font-size: 14px; }\n .flag-asym-h { padding: 12px 4px; background: #f1f5f9; border-radius: 6px; font-size: 14px; }\n\n /* ── FLAG: cramped large text (currently MISSED by the 8px floor) ── */\n .flag-heading-tight { padding: 8px; background: #f1f5f9; border-radius: 6px; font-size: 24px; font-weight: 600; line-height: 1.2; }\n .flag-hero-tight { padding: 6px 16px; background: #f1f5f9; border-radius: 6px; font-size: 32px; font-weight: 700; line-height: 1.2; }\n\n /* ── FLAG: cramped multi-line code block ── */\n .flag-pre-tight { padding: 2px; background: #1e293b; color: #e2e8f0; border-radius: 6px; font-family: ui-monospace, monospace; font-size: 14px; line-height: 1.5; }\n\n /* ── PASS: small inline pills (the .detection-cmd category) ── */\n .pass-cmd {\n display: inline-block;\n font-family: ui-monospace, SFMono-Regular, monospace;\n font-size: 13px;\n line-height: 1.625;\n color: #0f172a;\n background: #f5f5f7;\n padding: 6px 14px;\n border-radius: 6px;\n white-space: nowrap;\n }\n .pass-cmd::before { content: '➜ '; color: #ec4899; }\n .pass-badge {\n display: inline-block;\n font-size: 11px;\n line-height: 1.6;\n padding: 4px 8px;\n background: #dbeafe;\n color: #1e40af;\n border-radius: 999px;\n font-weight: 600;\n }\n .pass-chip {\n display: inline-block;\n font-size: 12px;\n line-height: 1.6;\n padding: 4px 10px;\n background: #fef3c7;\n color: #92400e;\n border-radius: 4px;\n font-weight: 500;\n }\n .pass-inline-code-chip {\n display: inline-block;\n font-family: ui-monospace, SFMono-Regular, monospace;\n font-size: 12px;\n line-height: 2;\n padding: 0.3em 0.5em;\n background: #eef2f7;\n color: #0f172a;\n border-radius: 4px;\n }\n\n /* ── PASS: cards at current standards ── */\n .pass-card-min { padding: 8px; background: #f1f5f9; border-radius: 6px; font-size: 16px; line-height: 1.6; }\n .pass-card-good { padding: 16px; background: #f1f5f9; border-radius: 8px; font-size: 14px; line-height: 1.6; }\n .pass-card-large { padding: 12px; background: #f1f5f9; border-radius: 8px; font-size: 18px; line-height: 1.6; }\n\n /* ── PASS: comfortable code blocks ── */\n .pass-pre-min { padding: 8px; background: #1e293b; color: #e2e8f0; border-radius: 6px; font-family: ui-monospace, monospace; font-size: 14px; line-height: 1.5; }\n .pass-pre-good { padding: 12px; background: #1e293b; color: #e2e8f0; border-radius: 6px; font-family: ui-monospace, monospace; font-size: 14px; line-height: 1.5; }\n\n /* ── PASS: interactive elements ── */\n .pass-button-std { padding: 8px 16px; background: #3b82f6; color: white; border: 0; border-radius: 6px; font-size: 14px; cursor: pointer; }\n .pass-input-std { padding: 8px 12px; border: 1px solid #cbd5e1; border-radius: 4px; font-size: 16px; width: 100%; box-sizing: border-box; }\n\n /* ── PASS: big text with proportional padding ── */\n .pass-heading-good { padding: 16px; background: #f1f5f9; border-radius: 8px; font-size: 24px; font-weight: 600; line-height: 1.2; }\n .pass-hero-good { padding: 20px 32px; background: #f1f5f9; border-radius: 8px; font-size: 32px; font-weight: 700; line-height: 1.2; }\n ","classText":"grid\ncol\ncase\ncase-label\nflag-card-4\ncase\ncase-label\nflag-card-2\ncase\ncase-label\nflag-card-bg4\ncase\ncase-label\nflag-asym-v\ncase\ncase-label\nflag-asym-h\ncase\ncase-label\nflag-heading-tight\ncase\ncase-label\nflag-hero-tight\ncase\ncase-label\nflag-pre-tight\ncol\ncase\ncase-label\npass-cmd\ncase\ncase-label\npass-badge\ncase\ncase-label\npass-chip\ncase\ncase-label\npass-inline-code-chip\ncase\ncase-label\npass-card-min\ncase\ncase-label\npass-card-good\ncase\ncase-label\npass-card-large\ncase\ncase-label\npass-pre-min\ncase\ncase-label\npass-pre-good\ncase\ncase-label\npass-button-std\ncase\ncase-label\npass-input-std\ncase\ncase-label\npass-heading-good\ncase\ncase-label\npass-hero-good"}],"result":[]} {"args":["\n\n\n \n Cream palette (Tailwind) fixture\n\n\n

A warm cream surface via Tailwind

\n

The background comes from a utility class (bg-amber-50), not inline CSS, so the static engine never resolves it to a computed color. The class-list fallback should still catch it.

\n\n\n",{"styleText":"","classText":"bg-amber-50 text-stone-800 font-serif"}],"result":[]} {"args":["\n\n\n \n Cream palette fixture\n \n\n\n

A warm cream surface

\n

The whole page sits on the default tasteful off-white that every generated landing page reaches for. The background is the tell, regardless of what sits on top of it.

\n\n\n",{"styleText":"\n body { background: #f5efe2; color: #2a2622; font-family: Georgia, serif; margin: 0; padding: 40px; }\n h1 { font-size: 40px; margin: 0 0 16px; }\n p { max-width: 60ch; line-height: 1.6; }\n ","classText":""}],"result":[]} -{"args":["\n\n\n\n\nReal gradient-text styling\n\n\n\n

Ship Faster With Us

\n\n\n

Inline gradient heading

\n\n\n

Tailwind gradient heading

\n\n

Body copy long enough to make this a real page for the scanners to read.

\n\n\n",{"styleText":"\n body { font-family: Georgia, serif; margin: 0; padding: 40px 24px; background: #fdfcf9; color: #1f2933; }\n /* SHOULD FLAG (gradient-text + ai-color-palette): a real style rule. */\n .gradient-heading {\n background: linear-gradient(135deg, #7c3aed, #a855f7);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n font-size: 44px;\n }\n\nstyle=\"background: linear-gradient(90deg, #667eea, #764ba2); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; font-size: 28px;\"","classText":"gradient-heading\nbg-clip-text bg-gradient-to-r from-purple-500 to-pink-500 text-transparent"}],"result":[{"id":"ai-color-palette","snippet":"Purple/violet accent colors detected","selector":"/* SHOULD FLAG (gradient-text + ai-color-palette): a real style rule. */ .gradient-heading"},{"id":"gradient-text","snippet":"background-clip: text + gradient","selector":"/* SHOULD FLAG (gradient-text + ai-color-palette): a real style rule. */ .gradient-heading"},{"id":"gradient-text","snippet":"bg-clip-text + bg-gradient (Tailwind)"}]} +{"args":["\n\n\n\n\nReal gradient-text styling\n\n\n\n

Ship Faster With Us

\n\n\n

Inline gradient heading

\n\n\n

Tailwind gradient heading

\n\n

Body copy long enough to make this a real page for the scanners to read.

\n\n\n",{"styleText":"\n body { font-family: Georgia, serif; margin: 0; padding: 40px 24px; background: #fdfcf9; color: #1f2933; }\n /* SHOULD FLAG (gradient-text + ai-color-palette): a real style rule. */\n .gradient-heading {\n background: linear-gradient(135deg, #7c3aed, #a855f7);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n font-size: 44px;\n }\n\nstyle=\"background: linear-gradient(90deg, #667eea, #764ba2); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; font-size: 28px;\"","classText":"gradient-heading\nbg-clip-text bg-gradient-to-r from-purple-500 to-pink-500 text-transparent"}],"result":[{"id":"ai-color-palette","snippet":"Purple/violet accent colors detected","selector":".gradient-heading"},{"id":"gradient-text","snippet":"background-clip: text + gradient","selector":".gradient-heading"},{"id":"gradient-text","snippet":"bg-clip-text + bg-gradient (Tailwind)"}]} {"args":["\n\n\n\n\nDocs about CSS anti-patterns\n\n\n\n

Changelog

\n\n\n

Detector

\n

background-clip: text gradients stop tripping the contrast rules when the glyph fill is transparent.

\n\n\n

What the rule catches

\n
.hero-title {\n  background: linear-gradient(135deg, #667eea, #764ba2);\n  -webkit-background-clip: text;\n  background-clip: text;\n  color: #7c3aed;\n}
\n\n\n

The Tailwind form pairs bg-clip-text with bg-gradient-to-r on one element; the two utilities together are the tell.

\n\n\n\n\n

Pulsing dots

\n
.status-dot {\n  width: 8px;\n  height: 8px;\n  border-radius: 50%;\n  animation: pulse 2s ease-in-out infinite;\n}
\n\n\n

Side stripes

\n
.card::before {\n  content: \"\";\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 4px;\n  background: #3b82f6;\n}
\n\n\n\n",{"styleText":"\n body { font-family: Georgia, 'Iowan Old Style', serif; margin: 0; padding: 32px 24px 40px; color: #1f2933; background: #fdfcf9; }\n h1 { font-size: 34px; margin: 0 0 12px; }\n h2 { font-size: 20px; margin: 28px 0 8px; }\n p { font-size: 16px; max-width: 640px; }\n pre { background: #f1efe9; padding: 16px; overflow-x: auto; font-size: 13px; }\n code { font-family: 'SF Mono', ui-monospace, monospace; }\n","classText":""}],"result":[]} {"args":["\n\n\n\nFixture: gradient body ground, oklch stops (low-contrast)\n\n\n\n

Light display text on the lacquer gradient

\n

This paragraph sits directly on the body's dark gradient ground. Its near-white ink clears WCAG AA against both gradient stops by a wide margin, so a detector that measures the real ground must not flag it. A detector that assumes a white body flags it at about 1.3:1.

\n
Light text on a raised solid oklch surface between the text and the body gradient still resolves through the normal opaque-ancestor walk.
\n
\n

Dark ink on a translucent light wash over the dark gradient. The wash composites to a light surface, so this passes; measuring raw gradient stops would wrongly flag it.

\n

Light ink on the same translucent light wash genuinely fails once the wash is composited over the stops; raw stops would wrongly pass it.

\n
\n

This muted dark-gray ink genuinely fails contrast against both stops of the dark gradient ground, which proves the gradient stops are being measured instead of the checks silently skipping.

\n
\n

Muted ink reached through a transparent wrapper still resolves to the body gradient and still fails against its stops.

\n
\n
A non-body gradient with legacy hex stops keeps working through the original rgb/hex parser, and light text on it passes.
\n
Dark ink on a translucent wash over a texture image. The image pixels are unknowable to the analytic walk, so contrast must skip rather than composite the wash over the wrong base.
\n
Dark ink on a photo-backed panel sitting over the dark body gradient. Walking past the photo to the gradient stops would wrongly flag this; the unmeasurable image layer must end the walk.
\n

Muted ink inside an opacity-zero scene deck. Nobody sees this state, so the contrast checks must not measure it.

\n\n\n",{"styleText":"\n /* The impeccable.style false-positive class: the page ground is a gradient\n set via `background:` shorthand, so the body's computed backgroundColor\n is transparent and the ground exists only as a backgroundImage whose\n stops serialize in oklch. The detector must measure text against those\n stops (composited under any translucent layers), never against an\n assumed white body. */\n body {\n margin: 0;\n padding: 48px;\n background: linear-gradient(180deg, oklch(7% 0.006 95), oklch(4% 0.004 95));\n font-family: Arial, sans-serif;\n }\n body > * { margin: 0 0 32px; }\n\n /* ── Should flag ─────────────────────────────────────────────────── */\n .flag-muted-direct {\n width: 560px;\n color: oklch(30% 0 0);\n font-size: 16px;\n line-height: 1.7;\n }\n .flag-muted-nested-wrapper { width: 560px; }\n .flag-muted-nested {\n color: oklch(32% 0 0);\n font-size: 16px;\n line-height: 1.7;\n margin: 0;\n }\n .frosted-light {\n width: 480px;\n padding: 24px;\n background: rgba(250, 249, 246, 0.88);\n border-radius: 4px;\n }\n .flag-light-on-frosted {\n color: oklch(88% 0 0);\n font-size: 15px;\n line-height: 1.6;\n margin: 0;\n }\n\n /* ── Should pass ─────────────────────────────────────────────────── */\n .pass-hero-title {\n width: 640px;\n color: oklch(91% 0 0);\n font-size: 48px;\n }\n .pass-hero-body {\n width: 560px;\n color: oklch(88% 0 0);\n font-size: 16px;\n line-height: 1.7;\n }\n .pass-on-raised {\n width: 420px;\n padding: 24px;\n background: oklch(11% 0.006 95);\n color: oklch(88% 0 0);\n font-size: 15px;\n }\n .pass-dark-on-frosted {\n color: oklch(15% 0.01 95);\n font-size: 15px;\n line-height: 1.6;\n margin: 0 0 12px;\n }\n .pass-hex-gradient {\n width: 520px;\n padding: 24px;\n background-image: linear-gradient(180deg, #14120f, #0a0908);\n color: oklch(90% 0 0);\n font-size: 15px;\n line-height: 1.6;\n }\n .pass-image-backed {\n width: 460px;\n padding: 18px 22px;\n background: linear-gradient(180deg, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.2)), url(\"/fixtures/antipatterns/no-such-texture.png\") center / cover;\n color: oklch(15% 0.01 95);\n font-size: 15px;\n line-height: 1.6;\n }\n .pass-photo-panel {\n width: 460px;\n padding: 18px 22px;\n background-image: url(\"/fixtures/antipatterns/no-such-photo.jpg\");\n color: oklch(20% 0 0);\n font-size: 15px;\n line-height: 1.6;\n }\n .pass-hidden-scene {\n opacity: 0;\n width: 560px;\n }\n .pass-hidden-scene p {\n color: oklch(30% 0 0);\n font-size: 16px;\n line-height: 1.7;\n margin: 0;\n }\n","classText":"pass-hero-title\npass-hero-body\npass-on-raised\nfrosted-light\npass-dark-on-frosted\nflag-light-on-frosted\nflag-muted-direct\nflag-muted-nested-wrapper\nflag-muted-nested\npass-hex-gradient\npass-image-backed\npass-photo-panel\npass-hidden-scene"}],"result":[]} {"args":["\n\n\n\nDark theme, modern color syntax\n\n\n\n\n

Should flag

\n\n
\n

Flag Muted On Oklch Ground: charcoal body copy sitting straight on the lacquer gradient.

\n
\n\n
\n

Flag Dim On Srgb Panel: slate copy on a near-black srgb surface.

\n
\n\n
\n

Flag Dim On Display P3 Panel: slate copy on a near-black display-p3 surface.

\n
\n\n
\n

Flag Dim On Lch Panel: warm gray copy on a warm near-black lch surface.

\n
\n\n
\n

Flag Pale On Light Panel: bone copy on a bone-white srgb surface.

\n
\n\n
\n
\n

Flag Pale On Inherited Light Panel: the ground is inherited from the light section, so the walk must resolve it rather than abstain.

\n
\n
\n\n
\n

Flag Pale On Currentcolor Panel: the ground is the panel's own bone text color, so the keyword must resolve rather than abstain.

\n
\n\n

Should pass

\n\n
\n

Pass Light Text On Oklch Gradient Ground: warm ivory copy on the lacquer gradient, roughly 15:1.

\n
\n\n
\n

Pass Light Text On Srgb Panel: warm ivory copy on the near-black srgb surface.

\n
\n\n
\n

Pass Light Text On Color Mix Panel: warm ivory copy on a surface a browser reports as color(srgb ...).

\n
\n\n
\n

Pass Light Text On Display P3 Panel: warm ivory copy on the near-black display-p3 surface.

\n
\n\n
\n

Pass Light Text On Lch Panel: warm ivory copy on the warm near-black lch surface.

\n
\n\n
\n

Pass Dark Text On Light Panel: ink copy on the bone-white srgb surface.

\n
\n

Pass Unreadable Panel Inside Light Section: the ground is a color space the detector cannot read, so it must abstain instead of measuring against the light section or against white.

\n
\n
\n\n
\n

Pass Image Over Gradient: the visible ground is an image whose pixels the engine cannot read, so it must abstain instead of measuring the loud gradient hidden beneath it.

\n
\n\n\n\n",{"styleText":"\n /* A lacquer-black ground painted as a gradient in oklch, the shape that\n floods dark themes with \"on #ffffff\" low-contrast false positives when\n the detector cannot read the ground and assumes white. */\n body {\n margin: 0;\n padding: 24px;\n background: linear-gradient(oklch(0.07 0.006 95), oklch(0.11 0.008 95));\n font-family: Georgia, serif;\n font-size: 15px;\n line-height: 1.6;\n }\n\n section {\n padding: 24px;\n margin-bottom: 24px;\n width: 640px;\n }\n\n p { margin: 0 0 12px; font-size: 15px; }\n\n /* Readable grounds, each written in a color syntax a real browser keeps\n verbatim in getComputedStyle output. */\n .panel-srgb { background-color: color(srgb 0.1 0.11 0.12); }\n .panel-mix { background-color: color-mix(in srgb, white 6%, #0b0b0d); }\n .panel-p3 { background-color: color(display-p3 0.07 0.07 0.08); }\n .panel-lch { background-color: lch(18 4 60); }\n .panel-light { background-color: color(srgb 0.98 0.97 0.95); }\n\n /* A color space the detector does not model. Nested inside the light\n panel so a detector that walks PAST the unreadable layer would measure\n light text against the light section and invent a finding. */\n .panel-unreadable { background-color: color(rec2020 0.05 0.05 0.05); padding: 20px; }\n\n /* An image layer stacked ABOVE a loud gradient. The image is the visible\n surface and its pixels are unreadable; a detector that falls back to\n gradient stops here measures a layer the visitor never sees. */\n .panel-image-over-gradient { background-image: url(\"opaque-panel.png\"), linear-gradient(#ff0000, #0000ff); }\n\n /* Keywords a real browser resolves before getComputedStyle output but a\n partial cascade hands through verbatim: inherit takes the parent's\n ground, currentcolor paints with the element's own text color. Both are\n knowable surfaces; abstaining on them would hide real findings. */\n .panel-inherit { background-color: inherit; padding: 20px; }\n .panel-current { background-color: currentcolor; color: color(srgb 0.94 0.93 0.91); }\n .text-pale-2 { color: color(srgb 0.78 0.77 0.75); }\n\n .text-light { color: oklch(0.92 0.01 90); }\n .text-dark { color: color(srgb 0.1 0.11 0.12); }\n\n .text-muted-ground { color: oklch(0.32 0.01 90); }\n .text-dim-srgb { color: color(srgb 0.28 0.28 0.3); }\n .text-dim-p3 { color: color(display-p3 0.35 0.35 0.36); }\n .text-dim-lch { color: lch(35 3 60); }\n .text-pale-light { color: color(srgb 0.75 0.74 0.72); }\n","classText":"text-light\ntext-muted-ground\npanel-srgb\ntext-dim-srgb\npanel-p3\ntext-dim-p3\npanel-lch\ntext-dim-lch\npanel-light\ntext-pale-light\npanel-light\npanel-inherit\ntext-pale-2\npanel-current\ntext-pale-light\ntext-light\ntext-light\npanel-srgb\ntext-light\npanel-mix\ntext-light\npanel-p3\ntext-light\npanel-lch\ntext-light\npanel-light\ntext-dark\npanel-unreadable\ntext-light\npanel-image-over-gradient\ntext-muted-ground"}],"result":[]} @@ -16,12 +16,12 @@ {"args":["\n\n\n\nfirst-viewport-column-overflow fixture\n\n\n\n
\n
\n

Upload your film and add a narrator

\n

Paste a link or drop a file. We transcribe it, translate, and one narrator reads over the top.

\n

The original stays audible underneath, just quieter.

\n
\n \n
\n\n
\n
\n

Left column with a normal amount of copy that fits comfortably within the opening viewport.

\n

Two short paragraphs, nothing that runs long.

\n
\n
\n

Right column, also short. Both sides sit inside the first screen.

\n

No column stretches the fold.

\n
\n
\n\n
\n
\n
\n\n\n",{"styleText":"\n * { margin: 0; box-sizing: border-box; }\n body { font-family: system-ui, sans-serif; color: #111; background: #fff; }\n p { margin: 0 0 14px; line-height: 1.6; }\n\n /* ── FLAG: two-column opening section, right column runs far past the fold\n while the left column fits inside one viewport ── */\n .flag { display: grid; grid-template-columns: 1.4fr 1fr; gap: 40px; padding: 40px; }\n .flag .short { }\n .flag .short h1 { font-size: 40px; margin-bottom: 16px; }\n .flag .tall .filler { height: 1600px; background: #eee; border-radius: 8px; padding: 16px; }\n\n /* ── PASS: balanced two-column section, both fit ── */\n .pass-balanced { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; padding: 40px; }\n .pass-balanced .col { }\n\n /* ── PASS: single full-page hero (no sibling column) ── */\n .pass-hero { padding: 40px; }\n .pass-hero .art { height: 1400px; background: #f3f3f3; }\n","classText":"flag\nshort\ntall\nfiller\npass-balanced\ncol\ncol\npass-hero\nart"}],"result":[]} {"args":["\n\n\n \n \n Flush Against Border; Should Flag vs Should Pass\n \n\n\n
\n\n \n
\n

Should flag

\n\n

Border + zero side-padding

\n
\n section: full border, padding 28px 0 0; label and pills touch the left/right border lines.\n
\n Supported dev servers\n
    \n
  • Vite
  • \n
  • Next.js
  • \n
  • SvelteKit
  • \n
  • Astro
  • \n
\n
\n
\n\n

All sides flush against a border

\n
\n card: 1px border on all sides, padding 0; heading and body touch every side.\n
\n

Card flush against the borders

\n

Body copy sits flush against every visible border line.

\n
\n
\n\n

Background color, zero padding

\n
\n no border, but a non-transparent bg; text flush against the bg's edge counts too.\n
\n

Title flush against the bg edge

\n

Body copy with zero padding around a colored fill.

\n
\n
\n\n

Outline (not border), zero padding

\n
\n outline draws outside the box; content at the box edge sits next to the outline.\n
\n

Title flush against the outline

\n

The outline counts as a visible boundary too.

\n
\n
\n\n

Left-side flush, other sides fine

\n
\n card: padding 12px 16px 12px 0; text touches the left border, other sides are inset.\n
\n

Title flush only on the left

\n

Padding-left zero with a full border.

\n
\n
\n
\n\n \n
\n

Should pass

\n\n

No boundary at all

\n
\n no bg, no border, no outline; zero padding is fine.\n
\n Supported dev servers\n
    \n
  • Vite
  • \n
  • Next.js
  • \n
  • SvelteKit
  • \n
\n
\n
\n\n

Top-only border, no side borders

\n
\n border-top only, padding-top 24px; no left/right border to be flush against.\n
\n Supported dev servers\n
    \n
  • Vite
  • \n
  • Next.js
  • \n
  • SvelteKit
  • \n
\n
\n
\n\n

Bordered card with proper inset

\n
\n card: 1px border + padding 18px 20px; comfortable inset on every side.\n
\n

Card with proper inset

\n

Body copy sits comfortably away from the borders.

\n
\n
\n\n

Background card with proper inset

\n
\n non-transparent bg + padding 14px 18px; content has room to breathe.\n
\n

Title with inset on bg

\n

Body copy is comfortably inset from the bg edge.

\n
\n
\n\n

Outline with proper inset

\n
\n outline + padding 14px 18px; content is comfortably inside.\n
\n

Title with inset and outline

\n

Outline boundary with proper inset works.

\n
\n
\n\n

Image-only container, no text

\n
\n card: padding 0, border all sides; no text means nothing can be flush.\n
\n
\n
\n
\n\n

Child margins provide the inset

\n
\n card: parent padding 0, but text children have margins that create visible inset.\n
\n

Title inset by child margin

\n

Body copy is not visually flush even though the parent has zero padding.

\n
\n
\n\n

Inner shell provides the inset

\n
\n card: parent padding 0, but an inner shell is offset from every edge.\n
\n
\n

Title inset by inner shell

\n

The direct child creates the breathing room.

\n
\n
\n
\n\n

Same background as parent

\n
\n child padding 0, but it has the same background as the parent, so no child boundary is visible.\n
\n
\n

Same-surface visual shell

\n

The text belongs to the parent surface, not to a distinct zero-padding card.

\n
\n
\n
\n\n

Full-bleed marquee shell

\n
\n marquee shell clips animated cards intentionally; the cards, not the shell, own text padding.\n
\n
\n

Quote card with its own comfortable padding.

\n

Another moving card, also padded inside.

\n
\n
\n
\n\n

Inner text surface

\n
\n outer shell has a scene background; the inner window owns the actual text padding.\n
\n
\n

Build step running

\n

Detector output belongs to the mock window.

\n
\n
\n
\n
\n
\n \n\n\n",{"styleText":"\n /* Fixture for the flush-against-border rule.\n\n The rule is more general than its name suggests: it fires when a\n container has any visible boundary (border, outline, OR a\n non-transparent background) AND zero inline padding on the\n bounded side, AND text-bearing children land flush against that\n boundary.\n\n Distinct from cramped-padding (which fires when an element has\n its OWN direct text and the padding/font-size ratio is wrong).\n Here the container has NO direct text; only children; so\n cramped-padding gives it a pass. */\n\n body { font-family: system-ui, sans-serif; background: #fafafa; padding: 24px; margin: 0; color: #0f172a; line-height: 1.5; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1400px; margin: 0 auto; }\n .col h2 { font-size: 22px; font-weight: 700; margin: 0 0 16px; color: #0f172a; line-height: 1.2; }\n .col h3 { font-size: 13px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em; margin: 28px 0 10px; color: #64748b; }\n .case { margin-bottom: 14px; }\n .case-label { display: block; font-size: 12px; color: #64748b; margin-bottom: 8px; font-style: italic; max-width: 60ch; }\n\n /* ────────────────────────────────────────────────────────────\n SHOULD FLAG\n ──────────────────────────────────────────────────────────── */\n\n /* ── FLAG: the /live-mode-frameworks bug; border + zero side-padding ── */\n .flag-frameworks {\n padding: 28px 0 0;\n background: #fffbe6;\n border: 1px solid #d4a017;\n border-radius: 8px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n .flag-frameworks-label {\n font-family: ui-monospace, monospace;\n font-size: 11px;\n letter-spacing: 0.18em;\n text-transform: uppercase;\n color: #8b6914;\n }\n .flag-frameworks-list {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n list-style: none;\n padding: 0;\n margin: 0;\n }\n .flag-frameworks-list li {\n font-family: ui-monospace, monospace;\n font-size: 13px;\n padding: 6px 12px;\n background: #fef3c7;\n border: 1px solid #d4a017;\n border-radius: 4px;\n color: #78350f;\n }\n\n /* ── FLAG: child text flush against the four borders of a card ── */\n .flag-card-borders {\n padding: 0;\n background: white;\n border: 1px solid #cbd5e1;\n border-radius: 8px;\n }\n .flag-card-borders h4 { margin: 0; font-size: 14px; color: #0f172a; }\n .flag-card-borders p { margin: 4px 0 0; font-size: 13px; color: #475569; }\n\n /* ── FLAG: non-transparent background, zero padding ── */\n .flag-bg-only {\n padding: 0;\n background: #fde68a;\n border-radius: 6px;\n border: 0;\n }\n .flag-bg-only h4 { margin: 0; font-size: 14px; color: #78350f; }\n .flag-bg-only p { margin: 4px 0 0; font-size: 13px; color: #78350f; }\n\n /* ── FLAG: outline (no border), zero padding ── */\n .flag-outline-only {\n padding: 0;\n background: transparent;\n border: 0;\n outline: 2px solid #94a3b8;\n outline-offset: 0;\n }\n .flag-outline-only h4 { margin: 0; font-size: 14px; color: #0f172a; }\n .flag-outline-only p { margin: 4px 0 0; font-size: 13px; color: #475569; }\n\n /* ── FLAG: border-left + zero left-padding, other sides fine ── */\n .flag-asym-leftflush {\n padding: 12px 16px 12px 0;\n background: white;\n border: 1px solid #cbd5e1;\n border-radius: 4px;\n }\n .flag-asym-leftflush h4 { margin: 0; font-size: 14px; color: #0f172a; }\n .flag-asym-leftflush p { margin: 4px 0 0; font-size: 13px; color: #475569; }\n\n /* ────────────────────────────────────────────────────────────\n SHOULD PASS\n ──────────────────────────────────────────────────────────── */\n\n /* ── PASS: no boundary at all (no bg, no border, no outline) ── */\n .pass-no-boundary {\n padding: 0;\n background: transparent;\n border: 0;\n outline: 0;\n }\n .pass-no-boundary-label {\n font-family: ui-monospace, monospace;\n font-size: 11px;\n letter-spacing: 0.18em;\n text-transform: uppercase;\n color: #475569;\n margin-bottom: 10px;\n }\n .pass-no-boundary-list {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n list-style: none;\n padding: 0;\n margin: 0;\n }\n .pass-no-boundary-list li {\n font-size: 13px;\n padding: 6px 12px;\n background: #f5f5f7;\n border: 1px solid #e2e8f0;\n border-radius: 4px;\n color: #0f172a;\n }\n\n /* ── PASS: top-only border, no left/right border, padding-top fine ── */\n .pass-top-rule {\n padding: 24px 0 0;\n background: transparent;\n border: 0;\n border-top: 1px solid #cbd5e1;\n }\n .pass-top-rule-label {\n font-family: ui-monospace, monospace;\n font-size: 11px;\n letter-spacing: 0.18em;\n text-transform: uppercase;\n color: #475569;\n margin-bottom: 10px;\n }\n .pass-top-rule-list {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n list-style: none;\n padding: 0;\n margin: 0;\n }\n .pass-top-rule-list li {\n font-size: 13px;\n padding: 6px 12px;\n background: #f5f5f7;\n border: 1px solid #e2e8f0;\n border-radius: 4px;\n color: #0f172a;\n }\n\n /* ── PASS: bordered card with comfortable inset on all sides ── */\n .pass-bordered-padded {\n padding: 18px 20px;\n background: white;\n border: 1px solid #cbd5e1;\n border-radius: 8px;\n }\n .pass-bordered-padded h4 { margin: 0; font-size: 14px; color: #0f172a; }\n .pass-bordered-padded p { margin: 4px 0 0; font-size: 13px; color: #475569; }\n\n /* ── PASS: background card with comfortable inset ── */\n .pass-bg-padded {\n padding: 14px 18px;\n background: #fde68a;\n border-radius: 6px;\n border: 0;\n }\n .pass-bg-padded h4 { margin: 0; font-size: 14px; color: #78350f; }\n .pass-bg-padded p { margin: 4px 0 0; font-size: 13px; color: #78350f; }\n\n /* ── PASS: outline with comfortable inset ── */\n .pass-outline-padded {\n padding: 14px 18px;\n outline: 2px solid #94a3b8;\n outline-offset: 0;\n border: 0;\n background: transparent;\n }\n .pass-outline-padded h4 { margin: 0; font-size: 14px; color: #0f172a; }\n .pass-outline-padded p { margin: 4px 0 0; font-size: 13px; color: #475569; }\n\n /* ── PASS: image-only container, no text means no flush issue ── */\n .pass-image-only {\n padding: 0;\n background: white;\n border: 1px solid #cbd5e1;\n border-radius: 8px;\n width: 200px;\n overflow: hidden;\n }\n .pass-image-only .placeholder-img {\n width: 100%;\n height: 80px;\n background: linear-gradient(135deg, #cbd5e1, #94a3b8);\n }\n\n /* ── PASS: parent has zero padding, but child margins create the visible inset ── */\n .pass-margin-inset {\n padding: 0;\n background: white;\n border: 1px solid #cbd5e1;\n border-radius: 8px;\n }\n .pass-margin-inset h4 { margin: 16px 18px 4px; font-size: 14px; color: #0f172a; }\n .pass-margin-inset p { margin: 0 18px 16px; font-size: 13px; color: #475569; }\n\n /* ── PASS: an inner shell, not the parent, owns the inset spacing ── */\n .pass-inner-shell {\n padding: 0;\n background: white;\n border: 1px solid #cbd5e1;\n border-radius: 8px;\n }\n .pass-inner-shell .inner-shell {\n margin: 18px;\n }\n .pass-inner-shell h4 { margin: 0 0 4px; font-size: 14px; color: #0f172a; }\n .pass-inner-shell p { margin: 0; font-size: 13px; color: #475569; }\n\n /* ── PASS: same background as parent, so the child draws no visible boundary ── */\n .pass-same-bg-parent {\n padding: 16px;\n background: #eef2f7;\n border-radius: 8px;\n }\n .pass-same-bg-child {\n padding: 0;\n background: #eef2f7;\n border: 0;\n border-radius: 8px;\n }\n .pass-same-bg-child h4 { margin: 0; font-size: 14px; color: #0f172a; }\n .pass-same-bg-child p { margin: 4px 0 0; font-size: 13px; color: #475569; }\n\n /* ── PASS: full-bleed marquee/surface, not a text card missing padding ── */\n .pass-marquee-shell {\n padding: 0;\n background: #172033;\n color: white;\n overflow: hidden;\n border: 0;\n }\n .pass-marquee-track {\n display: flex;\n gap: 12px;\n width: max-content;\n }\n .pass-marquee-card {\n width: 220px;\n padding: 14px;\n background: #23304a;\n border: 1px solid rgba(255, 255, 255, 0.16);\n }\n .pass-marquee-card p { margin: 0; font-size: 13px; }\n\n /* ── PASS: outer scene owns background; inner text surface owns padding ── */\n .pass-inner-text-surface {\n padding: 0;\n background: #0f172a;\n color: white;\n overflow: hidden;\n border: 0;\n }\n .pass-inner-text-surface-window {\n display: grid;\n gap: 6px;\n min-height: 92px;\n padding: 14px;\n background: #111827;\n border: 1px solid rgba(255, 255, 255, 0.16);\n }\n .pass-inner-text-surface-window p { margin: 0; font-size: 13px; }\n ","classText":"grid\ncol\ncase\ncase-label\nflag-frameworks\nflag-frameworks-label\nflag-frameworks-list\ncase\ncase-label\nflag-card-borders\ncase\ncase-label\nflag-bg-only\ncase\ncase-label\nflag-outline-only\ncase\ncase-label\nflag-asym-leftflush\ncol\ncase\ncase-label\npass-no-boundary\npass-no-boundary-label\npass-no-boundary-list\ncase\ncase-label\npass-top-rule\npass-top-rule-label\npass-top-rule-list\ncase\ncase-label\npass-bordered-padded\ncase\ncase-label\npass-bg-padded\ncase\ncase-label\npass-outline-padded\ncase\ncase-label\npass-image-only\nplaceholder-img\ncase\ncase-label\npass-margin-inset\ncase\ncase-label\npass-inner-shell\ninner-shell\ncase\ncase-label\npass-same-bg-parent\npass-same-bg-child\ncase\ncase-label\npass-marquee-shell\npass-marquee-track\npass-marquee-card\npass-marquee-card\ncase\ncase-label\npass-inner-text-surface\npass-inner-text-surface-window"}],"result":[]} {"args":["\n\n\n \n Image hover-transform fixture\n \n\n\n
\n \n
\n
\n \"CSS\n
\n \"Tailwind\n
\n\n \n
\n \"Static\n
A card that lifts on hover, which is fine because it is not an image.
\n
\n
\n\n\n",{"styleText":"\n body { font-family: system-ui, sans-serif; margin: 0; color: #1a1a1a; background: #fff; }\n .cols { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; padding: 24px; }\n .col { padding: 16px; }\n img { display: block; width: 160px; height: 120px; margin: 0 0 24px; background: #ddd; }\n .flag-css-hover img { transition: transform 0.3s; }\n .flag-css-hover img:hover { transform: scale(1.05); }\n .card:hover { transform: translateY(-4px); }\n ","classText":"cols\ncol flag\nflag-css-hover\nflag-tw-hover hover:scale-105 transition-transform\ncol pass\npass-static\ncard pass-non-img-hover"}],"result":[{"id":"image-hover-transform","snippet":"img:hover { transform } rule","selector":".flag-css-hover img:hover"},{"id":"image-hover-transform","snippet":"Tailwind hover transform on "}]} -{"args":["\n\n\n \n \n Dark Glow Anti-Patterns — Should Flag vs Should Pass\n \n\n\n
\n \n
\n

Should flag

\n\n

CSS colored glows on dark background

\n
\n
\n

Blue glow

\n

box-shadow: 0 0 20px rgba(59, 130, 246, 0.4)

\n
\n
\n

Purple glow

\n

box-shadow: 0 0 25px rgba(139, 92, 246, 0.35)

\n
\n
\n

Cyan glow

\n

box-shadow: 0 0 15px rgba(6, 182, 212, 0.5)

\n
\n
\n

Multi-shadow with colored glow

\n

Normal shadow + purple glow combined.

\n
\n
\n\n

Inline-style glow (regex path)

\n
\n
\n

Inline pink glow

\n

Inline style for regex detection path.

\n
\n
\n\n

Modern color formats, var() refs, text-shadow

\n
\n
\n

OKLCH glow

\n

box-shadow: 0 0 18px oklch(0.72 0.15 195 / 0.5)

\n
\n
\n

Hex glow

\n

box-shadow: 0 0 16px #3b82f6

\n
\n
\n

HSL glow

\n

box-shadow: 0 0 22px hsl(280, 80%, 60%)

\n
\n
\n

Glow via var()

\n

box-shadow: 0 0 10px var(--fixture-glow)

\n
\n
\n

Glowing text

\n

text-shadow: 0 0 12px #22d3ee on the heading.

\n
\n
\n\n

Zero-offset halo on LIGHT background

\n
\n

Chromatic halo on light page

\n

box-shadow: 0 0 20px oklch(0.65 0.2 300 / 0.45)

\n
\n\n

Zero-offset halo on unreadable (image) surface

\n
\n
\n

Halo over photo background

\n

box-shadow: 0 0 26px rgba(217, 70, 239, 0.5)

\n
\n
\n\n

Colored glow under an opaque gradient over an image (browser)

\n
\n
\n

Opaque dark gradient covers the photo

\n

box-shadow: 0 6px 22px rgba(249, 115, 22, 0.5)

\n
\n
\n
\n\n \n
\n

Should pass

\n\n

Light page + colored shadow

\n
\n

Colored shadow on light background

\n

Not dark mode, colored shadow is fine.

\n
\n\n

Dark cards with neutral shadows

\n
\n
\n

Normal gray shadow on dark card

\n

Gray/black shadow is not a glow.

\n
\n
\n

Focus ring (spread, no blur)

\n

Functional ring, not decorative glow.

\n
\n
\n

Tiny blur (<5px)

\n

Too subtle to be \"glowing\".

\n
\n
\n

Small dark elevation

\n

Subtle shadow on dark card.

\n
\n
\n

Medium dark elevation

\n

Standard dark card shadow.

\n
\n
\n

Large dark elevation

\n

Prominent shadow on dark card.

\n
\n
\n

Inset shadow

\n

Inner shadow, not a glow.

\n
\n
\n

Multi-shadow dark card

\n

Layered gray shadows, no color glow.

\n
\n
\n\n

Medium-gray background (not dark enough)

\n
\n

Not dark enough background

\n

Medium gray doesn't qualify as \"dark mode\".

\n
\n\n

Colored drop shadow / neutral halo on light background

\n
\n

Offset colored drop shadow

\n

Real drop shadow with a color tint — not a halo.

\n
\n
\n

Soft neutral halo

\n

Achromatic zero-offset shadow is ambient elevation.

\n
\n\n

Offset chromatic shadow on unreadable (image) surface

\n
\n
\n

Offset colored shadow over photo background

\n

Surface unknown, offset shadow — abstain, not flag.

\n
\n
\n\n

Offset chromatic shadow under a translucent gradient over an image

\n
\n
\n

The wash blends with unknowable image pixels

\n

Surface unknown — abstain, never score the wash stops as dark.

\n
\n
\n\n

Neutral text-shadow on dark card

\n
\n
\n

Offset neutral text-shadow

\n

Legibility aid, not a glow.

\n
\n
\n\n

Light elevated cards

\n
\n

Small elevation (Tailwind shadow-sm)

\n

Standard subtle card shadow.

\n
\n
\n

Medium elevation (Tailwind shadow-md)

\n

Standard card shadow.

\n
\n
\n

Warm deep shadow

\n

Large spread neutral shadow.

\n
\n
\n
\n \n\n\n",{"styleText":"\n /* Two-column fixture: left = should flag, right = should pass.\n The dark-glow rule fires when a colored box-shadow appears on a\n child whose ancestor has a dark background. Each column wraps\n its dark-context cases in its own .dark-context section so the\n parent-bg lookup behaves predictably regardless of layout. */\n body { font-family: system-ui, sans-serif; background: #f9fafb; padding: 24px; margin: 0; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1200px; margin: 0 auto; }\n .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .col h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; margin: 24px 0 8px; color: #64748b; }\n .dark-context { background: #111827; padding: 16px; border-radius: 12px; }\n .dark-context + .dark-context { margin-top: 12px; }\n /* Card variants: explicit dark vs light pairings, both WCAG AA compliant */\n .card { padding: 14px 16px; border-radius: 10px; margin-bottom: 10px; }\n .card h4 { font-weight: 600; font-size: 13px; margin: 0; }\n .card p { font-size: 12px; margin: 4px 0 0; }\n .card-dark { background: #1f2937; }\n .card-dark h4 { color: #f9fafb; }\n .card-dark p { color: #cbd5e1; }\n .card-light { background: white; }\n .card-light h4 { color: #0f172a; }\n .card-light p { color: #475569; }\n\n /* ── FLAG: dark background + colored glow ── */\n .glow-blue { box-shadow: 0 0 20px rgba(59, 130, 246, 0.4); }\n .glow-purple { box-shadow: 0 0 25px rgba(139, 92, 246, 0.35); }\n .glow-cyan { box-shadow: 0 0 15px rgba(6, 182, 212, 0.5); }\n .glow-multi { box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3), 0 0 30px rgba(168, 85, 247, 0.3); }\n\n /* ── FLAG: modern color formats, var() refs, text-shadow ── */\n :root { --fixture-glow: oklch(0.78 0.14 155); }\n .glow-oklch { box-shadow: 0 0 18px oklch(0.72 0.15 195 / 0.5); }\n .glow-hex { box-shadow: 0 0 16px #3b82f6; }\n .glow-hsl { box-shadow: 0 0 22px hsl(280, 80%, 60%); }\n .glow-var { box-shadow: 0 0 10px var(--fixture-glow); }\n .glow-text h4 { text-shadow: 0 0 12px #22d3ee; }\n /* Zero-offset chromatic halo is slop on light backgrounds too */\n .glow-light-oklch { box-shadow: 0 0 20px oklch(0.65 0.2 300 / 0.45); }\n /* Unreadable surface: url() image ancestor. The zero-offset halo tell\n holds on ANY background, so an unknown surface must not suppress it.\n Both element loops must agree here (the browser adapter once returned\n [] for the whole element on an unresolved surface). */\n .photo-context { background-image: url('/fixtures/antipatterns/missing-photo.png'); padding: 16px; border-radius: 12px; }\n .glow-photo-halo { box-shadow: 0 0 26px rgba(217, 70, 239, 0.5); }\n /* Opaque gradient atop a url() layer: every stop is opaque, so the\n gradient provably covers the image — the surface IS the dark\n gradient, and the dark-background glow tell may score against it\n (browser hunt; the static loop has no gradient hunt). */\n .photo-opaque-grad { background: linear-gradient(#111827, #0b1220), url('/fixtures/antipatterns/missing-photo.png'); padding: 16px; border-radius: 12px; }\n .glow-photo-opaque { box-shadow: 0 6px 22px rgba(249, 115, 22, 0.5); }\n\n /* ── PASS: same dark/light backgrounds, but neutral or no glow ── */\n .light-colored-shadow { box-shadow: 0 2px 4px rgba(59, 130, 246, 0.15); }\n .dark-normal-shadow { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); }\n .dark-focus-ring { box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5); }\n .dark-subtle-shadow { box-shadow: 0 1px 3px rgba(59, 130, 246, 0.2); }\n .dark-elevated-sm { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); }\n .dark-elevated-md { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.4); }\n .dark-elevated-lg { box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5); }\n .dark-elevated-inset { box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3); }\n .dark-elevated-multi { box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.2); }\n .elevated-sm-light { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); }\n .elevated-md-light { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); }\n .elevated-warm-light { box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.15); }\n /* Medium-gray card: lighter than dark mode, used to demonstrate \"not dark enough\" for glow detection. White text for AA contrast. */\n .card-medium { background: #6b7280; }\n .card-medium h4 { color: #ffffff; }\n .card-medium p { color: #ffffff; }\n .medium-gray-shadow { box-shadow: 0 2px 4px rgba(59, 130, 246, 0.3); }\n /* Offset chromatic drop shadow on a light background: a real drop\n shadow, not a halo — must NOT flag under the zero-offset rule.\n (Element path; the page-level text scan caps at one finding.) */\n .light-offset-colored { box-shadow: 0 8px 20px rgba(59, 130, 246, 0.25); }\n /* Achromatic zero-offset shadow: soft ambient elevation, stays legal */\n .light-soft-neutral { box-shadow: 0 0 24px rgba(0, 0, 0, 0.15); }\n /* Offset chromatic shadow under the same unreadable url() surface:\n the dark-background glow tell needs a surface we can read — abstain. */\n .photo-offset-colored { box-shadow: 0 6px 20px rgba(16, 185, 129, 0.35); }\n /* Translucent gradient atop a url() layer: the image shows through the\n 20% wash, so the real surface is a blend with unknowable pixels (a\n white photo composites to ~#cccccc, not black). Averaging the wash\n stops as if they were the surface scored this \"dark\" — abstain. */\n .photo-translucent-grad { background: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)), url('/fixtures/antipatterns/missing-photo.png'); padding: 16px; border-radius: 12px; }\n .photo-translucent-offset { box-shadow: 0 6px 22px rgba(244, 63, 94, 0.45); }\n /* Offset neutral text-shadow on dark card: legibility aid, not a glow */\n .dark-text-offset h4 { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); }\n \nstyle=\"box-shadow: 0 0 20px rgba(236, 72, 153, 0.5);\"","classText":"grid\ncol\ndark-context\ncard card-dark glow-blue\ncard card-dark glow-purple\ncard card-dark glow-cyan\ncard card-dark glow-multi\ndark-context\ncard card-dark\ndark-context\ncard card-dark glow-oklch\ncard card-dark glow-hex\ncard card-dark glow-hsl\ncard card-dark glow-var\ncard card-dark glow-text\ncard card-light glow-light-oklch\nphoto-context\ncard card-light glow-photo-halo\nphoto-opaque-grad\ncard card-dark glow-photo-opaque\ncol\ncard card-light light-colored-shadow\ndark-context\ncard card-dark dark-normal-shadow\ncard card-dark dark-focus-ring\ncard card-dark dark-subtle-shadow\ncard card-dark dark-elevated-sm\ncard card-dark dark-elevated-md\ncard card-dark dark-elevated-lg\ncard card-dark dark-elevated-inset\ncard card-dark dark-elevated-multi\ncard card-medium medium-gray-shadow\ncard card-light light-offset-colored\ncard card-light light-soft-neutral\nphoto-context\ncard card-light photo-offset-colored\nphoto-translucent-grad\ncard card-light photo-translucent-offset\ndark-context\ncard card-dark dark-text-offset\ncard card-light elevated-sm-light\ncard card-light elevated-md-light\ncard card-light elevated-warm-light"}],"result":[{"id":"dark-glow","snippet":"Zero-offset box-shadow glow (#3b82f6)","selector":"/* ── FLAG: dark background + colored glow ── */ .glow-blue"}]} -{"args":["\n\n\n \n Recurring generated-UI tell fixture\n \n\n\n
\n \n
\n
\n Thin hairline border paired with a wide diffuse shadow.\n
\n
\n
\n

We retired the growth theater and shipped something that actually works.

\n
\n\n \n
\n
\n Hairline border with a tight, purposeful shadow.\n
\n
\n A quiet low-contrast hairline with a broad but restrained ambient shadow.\n
\n
\n OKLCH shadow hue values should not be mistaken for shadow blur.\n
\n
\n
\n
\n
\n
\n

We measured real outcomes for the people who use this every day.

\n
\n
\n\n\n",{"styleText":"\n body { font-family: system-ui, sans-serif; margin: 0; color: #1a1a1a; background: #fff; }\n .cols { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; padding: 24px; }\n .col { padding: 16px; }\n .card { padding: 24px; margin: 0 0 24px; border-radius: 12px; }\n .stripes { height: 80px; margin: 0 0 24px; border-radius: 12px; }\n .grid { height: 80px; margin: 0 0 24px; border-radius: 12px; }\n \nstyle=\"border: 1px solid #e5e7eb; box-shadow: 0 0 24px rgba(0,0,0,0.18)\"\nstyle=\"background: repeating-linear-gradient(45deg, #eee, #eee 10px, #fafafa 10px, #fafafa 20px)\"\nstyle=\"background: linear-gradient(90deg, oklch(96% 0.012 82 / 0.055) 1px, transparent 1px), linear-gradient(180deg, oklch(96% 0.012 82 / 0.05) 1px, transparent 1px); background-size: 78px 78px, 78px 78px;\"\nstyle=\"border: 1px solid #e5e7eb; box-shadow: 0 1px 4px rgba(0,0,0,0.08)\"\nstyle=\"border: 1px solid rgba(148, 163, 184, 0.16); box-shadow: 0 18px 48px -16px rgba(15, 23, 42, 0.18)\"\nstyle=\"border: 1px solid oklch(78% 0 0 / 0.16); box-shadow: 0 16px 36px -12px oklch(2% 0.004 95 / 0.18)\"\nstyle=\"background: linear-gradient(180deg, #f3f4f6, #ffffff)\"\nstyle=\"background: linear-gradient(180deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px); background-size: 100% 32px\"\nstyle=\"background: linear-gradient(90deg, #f3f4f6, #e5e7eb), linear-gradient(180deg, #eef2ff, #ffffff)\"\nstyle=\"background: linear-gradient(90deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px), linear-gradient(180deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px)\"\nstyle=\"background: linear-gradient(90deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px); background-size: 32px 32px; mask-image: linear-gradient(180deg, #000 1px, transparent 1px)\"","classText":"cols\ncol flag\ncard flag-thin-border-wide-shadow\nstripes flag-repeating-stripes\ngrid flag-codex-grid\nflag-theater\ncol pass\ncard pass-tight-shadow\ncard pass-soft-border-wide-shadow\ncard pass-oklch-soft-shadow\nstripes pass-plain-gradient\ngrid pass-single-axis-rule\ngrid pass-two-color-blend\ngrid pass-crosshair-no-tiling\ngrid pass-bg-plus-mask-hairline\npass-no-theater"}],"result":[{"id":"repeating-stripes-gradient","snippet":"repeating-gradient decorative stripes","selector":".grid"},{"id":"codex-grid-background","snippet":"two-axis grid-line gradient background","selector":".grid"},{"id":"theater-slop-phrase","snippet":"\"growth theater\""}]} +{"args":["\n\n\n \n \n Dark Glow Anti-Patterns — Should Flag vs Should Pass\n \n\n\n
\n \n
\n

Should flag

\n\n

CSS colored glows on dark background

\n
\n
\n

Blue glow

\n

box-shadow: 0 0 20px rgba(59, 130, 246, 0.4)

\n
\n
\n

Purple glow

\n

box-shadow: 0 0 25px rgba(139, 92, 246, 0.35)

\n
\n
\n

Cyan glow

\n

box-shadow: 0 0 15px rgba(6, 182, 212, 0.5)

\n
\n
\n

Multi-shadow with colored glow

\n

Normal shadow + purple glow combined.

\n
\n
\n\n

Inline-style glow (regex path)

\n
\n
\n

Inline pink glow

\n

Inline style for regex detection path.

\n
\n
\n\n

Modern color formats, var() refs, text-shadow

\n
\n
\n

OKLCH glow

\n

box-shadow: 0 0 18px oklch(0.72 0.15 195 / 0.5)

\n
\n
\n

Hex glow

\n

box-shadow: 0 0 16px #3b82f6

\n
\n
\n

HSL glow

\n

box-shadow: 0 0 22px hsl(280, 80%, 60%)

\n
\n
\n

Glow via var()

\n

box-shadow: 0 0 10px var(--fixture-glow)

\n
\n
\n

Glowing text

\n

text-shadow: 0 0 12px #22d3ee on the heading.

\n
\n
\n\n

Zero-offset halo on LIGHT background

\n
\n

Chromatic halo on light page

\n

box-shadow: 0 0 20px oklch(0.65 0.2 300 / 0.45)

\n
\n\n

Zero-offset halo on unreadable (image) surface

\n
\n
\n

Halo over photo background

\n

box-shadow: 0 0 26px rgba(217, 70, 239, 0.5)

\n
\n
\n\n

Colored glow under an opaque gradient over an image (browser)

\n
\n
\n

Opaque dark gradient covers the photo

\n

box-shadow: 0 6px 22px rgba(249, 115, 22, 0.5)

\n
\n
\n
\n\n \n
\n

Should pass

\n\n

Light page + colored shadow

\n
\n

Colored shadow on light background

\n

Not dark mode, colored shadow is fine.

\n
\n\n

Dark cards with neutral shadows

\n
\n
\n

Normal gray shadow on dark card

\n

Gray/black shadow is not a glow.

\n
\n
\n

Focus ring (spread, no blur)

\n

Functional ring, not decorative glow.

\n
\n
\n

Tiny blur (<5px)

\n

Too subtle to be \"glowing\".

\n
\n
\n

Small dark elevation

\n

Subtle shadow on dark card.

\n
\n
\n

Medium dark elevation

\n

Standard dark card shadow.

\n
\n
\n

Large dark elevation

\n

Prominent shadow on dark card.

\n
\n
\n

Inset shadow

\n

Inner shadow, not a glow.

\n
\n
\n

Multi-shadow dark card

\n

Layered gray shadows, no color glow.

\n
\n
\n\n

Medium-gray background (not dark enough)

\n
\n

Not dark enough background

\n

Medium gray doesn't qualify as \"dark mode\".

\n
\n\n

Colored drop shadow / neutral halo on light background

\n
\n

Offset colored drop shadow

\n

Real drop shadow with a color tint — not a halo.

\n
\n
\n

Soft neutral halo

\n

Achromatic zero-offset shadow is ambient elevation.

\n
\n\n

Offset chromatic shadow on unreadable (image) surface

\n
\n
\n

Offset colored shadow over photo background

\n

Surface unknown, offset shadow — abstain, not flag.

\n
\n
\n\n

Offset chromatic shadow under a translucent gradient over an image

\n
\n
\n

The wash blends with unknowable image pixels

\n

Surface unknown — abstain, never score the wash stops as dark.

\n
\n
\n\n

Neutral text-shadow on dark card

\n
\n
\n

Offset neutral text-shadow

\n

Legibility aid, not a glow.

\n
\n
\n\n

Light elevated cards

\n
\n

Small elevation (Tailwind shadow-sm)

\n

Standard subtle card shadow.

\n
\n
\n

Medium elevation (Tailwind shadow-md)

\n

Standard card shadow.

\n
\n
\n

Warm deep shadow

\n

Large spread neutral shadow.

\n
\n
\n
\n \n\n\n",{"styleText":"\n /* Two-column fixture: left = should flag, right = should pass.\n The dark-glow rule fires when a colored box-shadow appears on a\n child whose ancestor has a dark background. Each column wraps\n its dark-context cases in its own .dark-context section so the\n parent-bg lookup behaves predictably regardless of layout. */\n body { font-family: system-ui, sans-serif; background: #f9fafb; padding: 24px; margin: 0; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1200px; margin: 0 auto; }\n .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .col h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; margin: 24px 0 8px; color: #64748b; }\n .dark-context { background: #111827; padding: 16px; border-radius: 12px; }\n .dark-context + .dark-context { margin-top: 12px; }\n /* Card variants: explicit dark vs light pairings, both WCAG AA compliant */\n .card { padding: 14px 16px; border-radius: 10px; margin-bottom: 10px; }\n .card h4 { font-weight: 600; font-size: 13px; margin: 0; }\n .card p { font-size: 12px; margin: 4px 0 0; }\n .card-dark { background: #1f2937; }\n .card-dark h4 { color: #f9fafb; }\n .card-dark p { color: #cbd5e1; }\n .card-light { background: white; }\n .card-light h4 { color: #0f172a; }\n .card-light p { color: #475569; }\n\n /* ── FLAG: dark background + colored glow ── */\n .glow-blue { box-shadow: 0 0 20px rgba(59, 130, 246, 0.4); }\n .glow-purple { box-shadow: 0 0 25px rgba(139, 92, 246, 0.35); }\n .glow-cyan { box-shadow: 0 0 15px rgba(6, 182, 212, 0.5); }\n .glow-multi { box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3), 0 0 30px rgba(168, 85, 247, 0.3); }\n\n /* ── FLAG: modern color formats, var() refs, text-shadow ── */\n :root { --fixture-glow: oklch(0.78 0.14 155); }\n .glow-oklch { box-shadow: 0 0 18px oklch(0.72 0.15 195 / 0.5); }\n .glow-hex { box-shadow: 0 0 16px #3b82f6; }\n .glow-hsl { box-shadow: 0 0 22px hsl(280, 80%, 60%); }\n .glow-var { box-shadow: 0 0 10px var(--fixture-glow); }\n .glow-text h4 { text-shadow: 0 0 12px #22d3ee; }\n /* Zero-offset chromatic halo is slop on light backgrounds too */\n .glow-light-oklch { box-shadow: 0 0 20px oklch(0.65 0.2 300 / 0.45); }\n /* Unreadable surface: url() image ancestor. The zero-offset halo tell\n holds on ANY background, so an unknown surface must not suppress it.\n Both element loops must agree here (the browser adapter once returned\n [] for the whole element on an unresolved surface). */\n .photo-context { background-image: url('/fixtures/antipatterns/missing-photo.png'); padding: 16px; border-radius: 12px; }\n .glow-photo-halo { box-shadow: 0 0 26px rgba(217, 70, 239, 0.5); }\n /* Opaque gradient atop a url() layer: every stop is opaque, so the\n gradient provably covers the image — the surface IS the dark\n gradient, and the dark-background glow tell may score against it\n (browser hunt; the static loop has no gradient hunt). */\n .photo-opaque-grad { background: linear-gradient(#111827, #0b1220), url('/fixtures/antipatterns/missing-photo.png'); padding: 16px; border-radius: 12px; }\n .glow-photo-opaque { box-shadow: 0 6px 22px rgba(249, 115, 22, 0.5); }\n\n /* ── PASS: same dark/light backgrounds, but neutral or no glow ── */\n .light-colored-shadow { box-shadow: 0 2px 4px rgba(59, 130, 246, 0.15); }\n .dark-normal-shadow { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); }\n .dark-focus-ring { box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5); }\n .dark-subtle-shadow { box-shadow: 0 1px 3px rgba(59, 130, 246, 0.2); }\n .dark-elevated-sm { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); }\n .dark-elevated-md { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.4); }\n .dark-elevated-lg { box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5); }\n .dark-elevated-inset { box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3); }\n .dark-elevated-multi { box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.2); }\n .elevated-sm-light { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); }\n .elevated-md-light { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); }\n .elevated-warm-light { box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.15); }\n /* Medium-gray card: lighter than dark mode, used to demonstrate \"not dark enough\" for glow detection. White text for AA contrast. */\n .card-medium { background: #6b7280; }\n .card-medium h4 { color: #ffffff; }\n .card-medium p { color: #ffffff; }\n .medium-gray-shadow { box-shadow: 0 2px 4px rgba(59, 130, 246, 0.3); }\n /* Offset chromatic drop shadow on a light background: a real drop\n shadow, not a halo — must NOT flag under the zero-offset rule.\n (Element path; the page-level text scan caps at one finding.) */\n .light-offset-colored { box-shadow: 0 8px 20px rgba(59, 130, 246, 0.25); }\n /* Achromatic zero-offset shadow: soft ambient elevation, stays legal */\n .light-soft-neutral { box-shadow: 0 0 24px rgba(0, 0, 0, 0.15); }\n /* Offset chromatic shadow under the same unreadable url() surface:\n the dark-background glow tell needs a surface we can read — abstain. */\n .photo-offset-colored { box-shadow: 0 6px 20px rgba(16, 185, 129, 0.35); }\n /* Translucent gradient atop a url() layer: the image shows through the\n 20% wash, so the real surface is a blend with unknowable pixels (a\n white photo composites to ~#cccccc, not black). Averaging the wash\n stops as if they were the surface scored this \"dark\" — abstain. */\n .photo-translucent-grad { background: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)), url('/fixtures/antipatterns/missing-photo.png'); padding: 16px; border-radius: 12px; }\n .photo-translucent-offset { box-shadow: 0 6px 22px rgba(244, 63, 94, 0.45); }\n /* Offset neutral text-shadow on dark card: legibility aid, not a glow */\n .dark-text-offset h4 { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); }\n \nstyle=\"box-shadow: 0 0 20px rgba(236, 72, 153, 0.5);\"","classText":"grid\ncol\ndark-context\ncard card-dark glow-blue\ncard card-dark glow-purple\ncard card-dark glow-cyan\ncard card-dark glow-multi\ndark-context\ncard card-dark\ndark-context\ncard card-dark glow-oklch\ncard card-dark glow-hex\ncard card-dark glow-hsl\ncard card-dark glow-var\ncard card-dark glow-text\ncard card-light glow-light-oklch\nphoto-context\ncard card-light glow-photo-halo\nphoto-opaque-grad\ncard card-dark glow-photo-opaque\ncol\ncard card-light light-colored-shadow\ndark-context\ncard card-dark dark-normal-shadow\ncard card-dark dark-focus-ring\ncard card-dark dark-subtle-shadow\ncard card-dark dark-elevated-sm\ncard card-dark dark-elevated-md\ncard card-dark dark-elevated-lg\ncard card-dark dark-elevated-inset\ncard card-dark dark-elevated-multi\ncard card-medium medium-gray-shadow\ncard card-light light-offset-colored\ncard card-light light-soft-neutral\nphoto-context\ncard card-light photo-offset-colored\nphoto-translucent-grad\ncard card-light photo-translucent-offset\ndark-context\ncard card-dark dark-text-offset\ncard card-light elevated-sm-light\ncard card-light elevated-md-light\ncard card-light elevated-warm-light"}],"result":[{"id":"buried-raster","snippet":"raster under a near-opaque gradient wash: linear-gradient(#111827, #0b1220), url('/fixtures/antipatterns/missing-photo.png')","selector":"the static loop has no gradient hunt). */ .photo-opaque-grad"},{"id":"dark-glow","snippet":"Zero-offset box-shadow glow (#3b82f6)","selector":".glow-blue"}]} +{"args":["\n\n\n \n Recurring generated-UI tell fixture\n \n\n\n
\n \n
\n
\n Thin hairline border paired with a wide diffuse shadow.\n
\n
\n
\n

We retired the growth theater and shipped something that actually works.

\n
\n\n \n
\n
\n Hairline border with a tight, purposeful shadow.\n
\n
\n A quiet low-contrast hairline with a broad but restrained ambient shadow.\n
\n
\n OKLCH shadow hue values should not be mistaken for shadow blur.\n
\n
\n
\n
\n
\n
\n

We measured real outcomes for the people who use this every day.

\n
\n
\n\n\n",{"styleText":"\n body { font-family: system-ui, sans-serif; margin: 0; color: #1a1a1a; background: #fff; }\n .cols { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; padding: 24px; }\n .col { padding: 16px; }\n .card { padding: 24px; margin: 0 0 24px; border-radius: 12px; }\n .stripes { height: 80px; margin: 0 0 24px; border-radius: 12px; }\n .grid { height: 80px; margin: 0 0 24px; border-radius: 12px; }\n \nstyle=\"border: 1px solid #e5e7eb; box-shadow: 0 0 24px rgba(0,0,0,0.18)\"\nstyle=\"background: repeating-linear-gradient(45deg, #eee, #eee 10px, #fafafa 10px, #fafafa 20px)\"\nstyle=\"background: linear-gradient(90deg, oklch(96% 0.012 82 / 0.055) 1px, transparent 1px), linear-gradient(180deg, oklch(96% 0.012 82 / 0.05) 1px, transparent 1px); background-size: 78px 78px, 78px 78px;\"\nstyle=\"border: 1px solid #e5e7eb; box-shadow: 0 1px 4px rgba(0,0,0,0.08)\"\nstyle=\"border: 1px solid rgba(148, 163, 184, 0.16); box-shadow: 0 18px 48px -16px rgba(15, 23, 42, 0.18)\"\nstyle=\"border: 1px solid oklch(78% 0 0 / 0.16); box-shadow: 0 16px 36px -12px oklch(2% 0.004 95 / 0.18)\"\nstyle=\"background: linear-gradient(180deg, #f3f4f6, #ffffff)\"\nstyle=\"background: linear-gradient(180deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px); background-size: 100% 32px\"\nstyle=\"background: linear-gradient(90deg, #f3f4f6, #e5e7eb), linear-gradient(180deg, #eef2ff, #ffffff)\"\nstyle=\"background: linear-gradient(90deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px), linear-gradient(180deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px)\"\nstyle=\"background: linear-gradient(90deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px); background-size: 32px 32px; mask-image: linear-gradient(180deg, #000 1px, transparent 1px)\"","classText":"cols\ncol flag\ncard flag-thin-border-wide-shadow\nstripes flag-repeating-stripes\ngrid flag-codex-grid\nflag-theater\ncol pass\ncard pass-tight-shadow\ncard pass-soft-border-wide-shadow\ncard pass-oklch-soft-shadow\nstripes pass-plain-gradient\ngrid pass-single-axis-rule\ngrid pass-two-color-blend\ngrid pass-crosshair-no-tiling\ngrid pass-bg-plus-mask-hairline\npass-no-theater"}],"result":[{"id":"repeating-stripes-gradient","snippet":"repeating-gradient decorative stripes"},{"id":"codex-grid-background","snippet":"two-axis grid-line gradient background"},{"id":"theater-slop-phrase","snippet":"\"growth theater\""}]} {"args":["\n\n\n\nHeading rhythm fixture\n\n\n\n\n

Pass First Heading

\n

Opening paragraph after the first heading on the page. The first heading has\n nothing above it, so it is exempt from the rhythm comparison entirely.

\n\n

A closing paragraph of the previous block of content,\n sitting directly above the crowded heading with no gap at all between them.

\n

Flag Crowded One

\n

The content this heading introduces sits forty pixels away while the previous\n block touches the heading, so the heading reads as a caption for the text above.

\n\n

Another closing paragraph of a previous content block, again flush against\n the heading that follows it in the document flow.

\n

Flag Crowded Two

\n

Second crowded case. Two or more headings must violate the principle before\n the rule fires, because a single occurrence is treated as noise.

\n\n

A third closing paragraph that the next heading will visually attach to,\n which is exactly the inversion this rule measures.

\n

Flag Crowded Three

\n

Third crowded case, this time an h3, to confirm the rule reads h2 through h4.

\n\n

Pass Generous Above

\n

Sixty-four pixels above and sixteen below. The heading clearly binds to this\n paragraph, which is the healthy shape.

\n\n

Pass Near Equal

\n

Twenty pixels above and twenty-four below. Ambiguous rather than inverted,\n so the rule leaves it alone.

\n\n

Chapter Four

\n

Pass Eyebrow Cluster

\n

The tiny label above belongs to the heading cluster. Space is measured from\n the top of the cluster, where seventy-two pixels separate it from this text.

\n\n
\n

Pass Card Heading

\n

A heading inside a small card. The card boundary provides the separation,\n so the rule exempts headings inside panels shorter than two hundred pixels.

\n
\n\n
\n

Pass Band Heading

\n

This heading is the first content inside a section that draws its own\n background, so the band edge is the separator above it.

\n
\n\n\n\n",{"styleText":"\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: Georgia, serif; font-size: 16px; line-height: 1.5; width: 720px; }\n h2 { font-size: 28px; line-height: 1.2; }\n h3 { font-size: 20px; line-height: 1.2; }\n p { max-width: 60ch; }\n\n /* FLAG: zero space above the heading, clear space below it */\n .flag-crowded { margin: 0 0 40px; }\n .flag-crowded + p { margin: 0 0 24px; }\n\n /* PASS: generous space above, tight below */\n .pass-generous { margin: 64px 0 16px; }\n\n /* PASS: near-equal spacing is ambiguous, not inverted */\n .pass-near-equal { margin: 20px 0 24px; }\n\n /* PASS: eyebrow label bound to the heading; real space sits above the cluster */\n .pass-eyebrow-label { font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; margin: 72px 0 8px; }\n .pass-eyebrow-heading { margin: 0 0 24px; }\n\n /* PASS: small card, its boundary provides the separation */\n .pass-card { box-shadow: 0 1px 4px rgba(0,0,0,0.2); background: #f4f4f4; padding: 16px; margin: 48px 0; width: 320px; }\n .pass-card h3 { margin: 0 0 20px; }\n\n /* PASS: heading first inside a banded section; the band edge separates */\n .pass-band { background: #ececec; padding: 8px 0 32px; margin-top: 8px; }\n .pass-band h2 { margin: 0 0 24px; }\n\nstyle=\"margin-top: 24px;\"","classText":"pass-first\nflag-crowded\nflag-crowded\nflag-crowded\npass-generous\npass-near-equal\npass-eyebrow-label\npass-eyebrow-heading\npass-card\npass-band"}],"result":[]} {"args":["\n\n\n \n Hero-Eyebrow-Chip — Should Flag vs Should Pass\n \n\n\n
\n\n \n
\n

Should flag

\n\n
\n
AI-NATIVE WORKFLOWS
\n

Eyebrow Above Hero

\n

Classic uppercase tracked div eyebrow above an 88px hero.

\n
\n\n
\n NEW IN 2026\n

Span Eyebrow Above Hero

\n

Span variant with the same uppercase + tracking + small-size shape.

\n
\n\n
\n FEATURED\n

Pill Chip Above Hero

\n

Pill-shaped chip with background, border-radius, padding.

\n
\n\n
\n NEW\n

Already Uppercase Text

\n

Text typed uppercase, no text-transform, but matching tracking and size.

\n
\n\n
\n
A VERY LONG UPPERCASE TABLE OF CONTENTS HEADER
\n

Long Uppercase Sentence Above Hero

\n

46-char uppercase tracked label — under the 60-char eyebrow ceiling, so it still reads as an oversized eyebrow.

\n
\n
\n\n \n
\n

Should pass

\n\n
\n
UPPERCASE LABEL
\n

Eyebrow With Normal Tracking

\n

Uppercase label above a hero but with letter-spacing: normal.

\n
\n\n
\n
CARD CAPTION
\n

Plain body text below the caption.

\n

Uppercase Caption Far From Hero

\n

Hero exists, but its preceding sibling is a paragraph, not the eyebrow.

\n
\n\n
\n

Hero With No Eyebrow

\n

Bare h1 at 64px, nothing above it.

\n
\n\n
\n

SECTION HEADING

\n

Heading Above Heading

\n

An h2 styled like an eyebrow above an h1 — heading-tag exclusion must skip this.

\n
\n\n
\n
SECTION KICKER
\n

Body-Sized Heading Below Eyebrow

\n

A compact product/page heading is not an oversized marketing hero.

\n
\n\n
\n
NEXT FROM
\n

Application Panel Heading

\n

Context labels inside tab panels describe application state rather than decorating a marketing hero.

\n
\n\n
\n\n
\n\n\n",{"styleText":"\n /* ─── Layout convention: two-column fixture ─────────────────────────\n Left column = patterns the rule SHOULD flag.\n Right column = legitimate patterns the rule should NOT flag.\n Each test case is annotated with a unique

text so the test\n can match snippets back to expectations.\n ──────────────────────────────────────────────────────────────── */\n body { font-family: system-ui, sans-serif; margin: 0; padding: 24px; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1200px; margin: 0 auto; }\n .col h2.col-label { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .case { margin-bottom: 32px; padding: 24px; border: 1px solid #e2e8f0; border-radius: 12px; background: #fff; }\n .case p { font-size: 14px; margin: 12px 0 0; color: #64748b; }\n .case h1 { margin: 0; font-family: 'Inter', sans-serif; line-height: 1.05; }\n\n /* Hero size used by most cases */\n .hero { font-size: 88px; font-weight: 600; }\n\n /* ── FLAG cases ── */\n\n .eyebrow-classic {\n text-transform: uppercase;\n letter-spacing: 0.15em;\n font-size: 12px;\n color: #64748b;\n font-weight: 600;\n margin: 0 0 16px;\n }\n\n .eyebrow-span {\n display: inline-block;\n text-transform: uppercase;\n letter-spacing: 0.16em;\n font-size: 11px;\n color: #475569;\n font-weight: 600;\n margin: 0 0 16px;\n }\n\n .eyebrow-pill {\n display: inline-block;\n text-transform: uppercase;\n letter-spacing: 0.14em;\n font-size: 12px;\n background: #f1f5f9;\n color: #334155;\n border-radius: 999px;\n padding: 4px 12px;\n font-weight: 600;\n margin: 0 0 16px;\n }\n\n .eyebrow-already-uppercase {\n letter-spacing: 0.18em;\n font-size: 11px;\n color: #b45309;\n font-weight: 700;\n margin: 0 0 16px;\n }\n\n /* ── PASS cases ── */\n\n .pass-eyebrow-no-tracking {\n text-transform: uppercase;\n letter-spacing: normal;\n font-size: 12px;\n color: #64748b;\n font-weight: 600;\n margin: 0 0 16px;\n }\n\n .pass-body-heading {\n font-size: 24px;\n font-weight: 600;\n font-family: 'Inter', sans-serif;\n margin: 0;\n }\n\n .pass-card-caption {\n text-transform: uppercase;\n letter-spacing: 0.18em;\n font-size: 11px;\n color: #94a3b8;\n font-weight: 600;\n margin: 0 0 8px;\n }\n\n .pass-bare-hero {\n font-size: 64px;\n }\n\n .pass-h2-above-h1 {\n font-size: 14px;\n text-transform: uppercase;\n letter-spacing: 0.18em;\n font-weight: 700;\n color: #475569;\n margin: 0 0 16px;\n font-family: 'Inter', sans-serif;\n }\n\n .pass-long-uppercase {\n text-transform: uppercase;\n letter-spacing: 0.14em;\n font-size: 12px;\n color: #475569;\n font-weight: 600;\n margin: 0 0 16px;\n }\n \nstyle=\"margin-top:32px\"","classText":"grid\ncol\ncol-label\ncase\neyebrow-classic\nhero\ncase\neyebrow-span\nhero\ncase\neyebrow-pill\nhero\ncase\neyebrow-already-uppercase\nhero\ncase\npass-long-uppercase\nhero\ncol\ncol-label\ncase\npass-eyebrow-no-tracking\nhero\ncase\npass-card-caption\nhero\ncase\npass-bare-hero\ncase\npass-h2-above-h1\nhero\ncase\neyebrow-classic\npass-body-heading\ncase\neyebrow-classic\nhero"}],"result":[]} {"args":["\n\n \n \n Hook inline ignore comments do not suppress detector findings\n \n \n \n \n
\n

Roboto remains a detector finding

\n

\n This fixture deliberately uses Roboto across enough visible text for\n the browser detector to report the overused-font page finding. Hook\n exceptions must live in .impeccable/hook.json instead of source comments.\n

\n

\n The comments above look like old inline hook suppressions, but they are\n intentionally inert and should not hide the finding from headless scans.\n

\n
    \n
  • Roboto usage sample one.
  • \n
  • Roboto usage sample two.
  • \n
  • Roboto usage sample three.
  • \n
  • Roboto usage sample four.
  • \n
  • Roboto usage sample five.
  • \n
  • Roboto usage sample six.
  • \n
  • Roboto usage sample seven.
  • \n
  • Roboto usage sample eight.
  • \n
  • Roboto usage sample nine.
  • \n
  • Roboto usage sample ten.
  • \n
  • Roboto usage sample eleven.
  • \n
  • Roboto usage sample twelve.
  • \n
  • Roboto usage sample thirteen.
  • \n
  • Roboto usage sample fourteen.
  • \n
  • Roboto usage sample fifteen.
  • \n
  • Roboto usage sample sixteen.
  • \n
  • Roboto usage sample seventeen.
  • \n
  • Roboto usage sample eighteen.
  • \n
  • Roboto usage sample nineteen.
  • \n
  • Roboto usage sample twenty.
  • \n
\n
\n \n\n",{"styleText":"\n /* impeccable: ignore overused-font */\n body {\n font-family: \"Roboto\", ui-sans-serif, system-ui, sans-serif;\n margin: 0;\n padding: 48px;\n }\n\n main {\n max-width: 62ch;\n }\n ","classText":""}],"result":[]} -{"args":["\n\n\n \n Icon-Tile-Stack — Should Flag vs Should Pass\n \n\n\n
\n\n \n
\n

Should flag

\n\n
\n
\n \n \n \n
\n

Lightning Fast

\n

Built for speed and performance from the ground up.

\n
\n\n
\n
\n \n \n \n
\n

Secure Storage

\n

Enterprise-grade security for your peace of mind.

\n
\n\n
\n
\n \n \n \n \n
\n

Easy Setup

\n

Get started in minutes with zero configuration.

\n
\n\n
\n
\n \n \n \n \n \n
\n

Powerful Analytics

\n

Insights that drive smarter business decisions.

\n
\n\n
\n
\n

Emoji Inline Icon

\n

The tile contains an emoji directly, no SVG child.

\n
\n
\n\n \n
\n

Should pass

\n\n \n
\n
\n \n \n \n \n
\n

Sarah Chen

\n

Product designer based in Berlin.

\n
\n\n \n
\n
\n

Article Headline

\n

A summary of an interesting article.

\n
\n\n \n
\n
\n
\n \n \n \n
\n
\n

Inline Side By Side

\n

Icon sits next to the heading, not above it.

\n
\n
\n
\n\n \n
\n

Plain Heading No Icon

\n

Just a heading with body text, nothing above.

\n
\n\n \n
\n
\n \n \n \n
\n

Tiny Icon Above Me

\n

The icon container is smaller than 32px.

\n
\n\n \n
\n
\n

Huge Hero Image

\n

The container is larger than the size cap.

\n
\n
\n
\n \n\n\n",{"styleText":"\n /* ─── Layout convention: two-column fixture ─────────────────────────\n Left column = patterns the rule SHOULD flag.\n Right column = legitimate patterns the rule should NOT flag.\n Each test case is annotated with a unique

text so the test\n can match snippets back to expectations.\n ──────────────────────────────────────────────────────────────── */\n body { font-family: system-ui, sans-serif; margin: 0; padding: 24px; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 960px; margin: 0 auto; }\n .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .case { margin-bottom: 24px; padding: 16px; border: 1px solid #e2e8f0; border-radius: 12px; background: #fff; }\n .case h3 { font-size: 18px; margin: 0 0 4px; color: #0f172a; }\n .case p { font-size: 14px; margin: 0; color: #64748b; }\n\n /* ── FLAG cases ── */\n\n /* 1: pastel-gradient icon-tile (the canonical massive-icons.html shape) */\n .icon-pastel {\n width: 80px; height: 80px;\n border-radius: 20px;\n background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* 2: solid-color icon-tile, white svg inside (no gradient) */\n .icon-solid {\n width: 64px; height: 64px;\n border-radius: 16px;\n background: #3b82f6;\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* 3: white-bg outlined icon-tile (no chromatic background at all) */\n .icon-white {\n width: 72px; height: 72px;\n border-radius: 18px;\n background: #ffffff;\n border: 1px solid #e2e8f0;\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* 4: larger square (still inside the 32–128 range) */\n .icon-large {\n width: 96px; height: 96px;\n border-radius: 24px;\n background: #f1f5f9;\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* 5: inline emoji icon — tile contains an emoji/symbol character directly,\n not an or child. This is the \"card-icon\" pattern from many\n generated demos. */\n .icon-emoji {\n width: 48px; height: 48px;\n border-radius: 12px;\n background: linear-gradient(135deg, #8b5cf6, #a855f7);\n display: flex; align-items: center; justify-content: center;\n font-size: 24px;\n margin-bottom: 16px;\n }\n\n /* ── PASS cases ── */\n\n /* a: round avatar above name (border-radius: 50% — circle, not rounded square) */\n .avatar-round {\n width: 64px; height: 64px;\n border-radius: 50%;\n background: #f59e0b;\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* b: wide thumbnail above article title (16:9, much wider than tall) */\n .thumb-wide {\n width: 200px; height: 112px;\n border-radius: 8px;\n background: #cbd5e1;\n margin-bottom: 16px;\n }\n\n /* c: inline icon next to heading (icon and h3 on the same row, NOT stacked) */\n .inline-row { display: flex; align-items: center; gap: 12px; }\n .inline-row .icon-inline {\n width: 80px; height: 80px;\n border-radius: 20px;\n background: #ddd6fe;\n display: flex; align-items: center; justify-content: center;\n flex-shrink: 0;\n }\n\n /* d: nothing above the heading at all */\n .no-icon h3 { margin-top: 0; }\n\n /* e: icon-tile that's too small (under 32px) — out of size range */\n .icon-tiny {\n width: 24px; height: 24px;\n border-radius: 6px;\n background: #93c5fd;\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* f: oversized image card / hero image (over 128px) — out of size range */\n .img-huge {\n width: 200px; height: 200px;\n border-radius: 16px;\n background: #cbd5e1;\n margin-bottom: 16px;\n }\n ","classText":"grid\ncol\ncase\nicon-pastel\ncase\nicon-solid\ncase\nicon-white\ncase\nicon-large\ncase\nicon-emoji\ncol\ncase\navatar-round\ncase\nthumb-wide\ncase\ninline-row\nicon-inline\ncase no-icon\ncase\nicon-tiny\ncase\nimg-huge"}],"result":[{"id":"ai-color-palette","snippet":"Purple/violet accent colors detected","selector":{"$undef":true}}]} +{"args":["\n\n\n \n Icon-Tile-Stack — Should Flag vs Should Pass\n \n\n\n
\n\n \n
\n

Should flag

\n\n
\n
\n \n \n \n
\n

Lightning Fast

\n

Built for speed and performance from the ground up.

\n
\n\n
\n
\n \n \n \n
\n

Secure Storage

\n

Enterprise-grade security for your peace of mind.

\n
\n\n
\n
\n \n \n \n \n
\n

Easy Setup

\n

Get started in minutes with zero configuration.

\n
\n\n
\n
\n \n \n \n \n \n
\n

Powerful Analytics

\n

Insights that drive smarter business decisions.

\n
\n\n
\n
\n

Emoji Inline Icon

\n

The tile contains an emoji directly, no SVG child.

\n
\n
\n\n \n
\n

Should pass

\n\n \n
\n
\n \n \n \n \n
\n

Sarah Chen

\n

Product designer based in Berlin.

\n
\n\n \n
\n
\n

Article Headline

\n

A summary of an interesting article.

\n
\n\n \n
\n
\n
\n \n \n \n
\n
\n

Inline Side By Side

\n

Icon sits next to the heading, not above it.

\n
\n
\n
\n\n \n
\n

Plain Heading No Icon

\n

Just a heading with body text, nothing above.

\n
\n\n \n
\n
\n \n \n \n
\n

Tiny Icon Above Me

\n

The icon container is smaller than 32px.

\n
\n\n \n
\n
\n

Huge Hero Image

\n

The container is larger than the size cap.

\n
\n
\n
\n \n\n\n",{"styleText":"\n /* ─── Layout convention: two-column fixture ─────────────────────────\n Left column = patterns the rule SHOULD flag.\n Right column = legitimate patterns the rule should NOT flag.\n Each test case is annotated with a unique

text so the test\n can match snippets back to expectations.\n ──────────────────────────────────────────────────────────────── */\n body { font-family: system-ui, sans-serif; margin: 0; padding: 24px; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 960px; margin: 0 auto; }\n .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .case { margin-bottom: 24px; padding: 16px; border: 1px solid #e2e8f0; border-radius: 12px; background: #fff; }\n .case h3 { font-size: 18px; margin: 0 0 4px; color: #0f172a; }\n .case p { font-size: 14px; margin: 0; color: #64748b; }\n\n /* ── FLAG cases ── */\n\n /* 1: pastel-gradient icon-tile (the canonical massive-icons.html shape) */\n .icon-pastel {\n width: 80px; height: 80px;\n border-radius: 20px;\n background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* 2: solid-color icon-tile, white svg inside (no gradient) */\n .icon-solid {\n width: 64px; height: 64px;\n border-radius: 16px;\n background: #3b82f6;\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* 3: white-bg outlined icon-tile (no chromatic background at all) */\n .icon-white {\n width: 72px; height: 72px;\n border-radius: 18px;\n background: #ffffff;\n border: 1px solid #e2e8f0;\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* 4: larger square (still inside the 32–128 range) */\n .icon-large {\n width: 96px; height: 96px;\n border-radius: 24px;\n background: #f1f5f9;\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* 5: inline emoji icon — tile contains an emoji/symbol character directly,\n not an or child. This is the \"card-icon\" pattern from many\n generated demos. */\n .icon-emoji {\n width: 48px; height: 48px;\n border-radius: 12px;\n background: linear-gradient(135deg, #8b5cf6, #a855f7);\n display: flex; align-items: center; justify-content: center;\n font-size: 24px;\n margin-bottom: 16px;\n }\n\n /* ── PASS cases ── */\n\n /* a: round avatar above name (border-radius: 50% — circle, not rounded square) */\n .avatar-round {\n width: 64px; height: 64px;\n border-radius: 50%;\n background: #f59e0b;\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* b: wide thumbnail above article title (16:9, much wider than tall) */\n .thumb-wide {\n width: 200px; height: 112px;\n border-radius: 8px;\n background: #cbd5e1;\n margin-bottom: 16px;\n }\n\n /* c: inline icon next to heading (icon and h3 on the same row, NOT stacked) */\n .inline-row { display: flex; align-items: center; gap: 12px; }\n .inline-row .icon-inline {\n width: 80px; height: 80px;\n border-radius: 20px;\n background: #ddd6fe;\n display: flex; align-items: center; justify-content: center;\n flex-shrink: 0;\n }\n\n /* d: nothing above the heading at all */\n .no-icon h3 { margin-top: 0; }\n\n /* e: icon-tile that's too small (under 32px) — out of size range */\n .icon-tiny {\n width: 24px; height: 24px;\n border-radius: 6px;\n background: #93c5fd;\n display: flex; align-items: center; justify-content: center;\n margin-bottom: 16px;\n }\n\n /* f: oversized image card / hero image (over 128px) — out of size range */\n .img-huge {\n width: 200px; height: 200px;\n border-radius: 16px;\n background: #cbd5e1;\n margin-bottom: 16px;\n }\n ","classText":"grid\ncol\ncase\nicon-pastel\ncase\nicon-solid\ncase\nicon-white\ncase\nicon-large\ncase\nicon-emoji\ncol\ncase\navatar-round\ncase\nthumb-wide\ncase\ninline-row\nicon-inline\ncase no-icon\ncase\nicon-tiny\ncase\nimg-huge"}],"result":[{"id":"ai-color-palette","snippet":"Purple/violet accent colors detected","selector":".icon-emoji"}]} {"args":["\n\n\n\nFixture: image-backed text sampled at the pixel level by default\n\n\n\n
\n
Decoy 1
\n
Decoy 2
\n
Decoy 3
\n
Decoy 4
\n
Decoy 5
\n
Decoy 6
\n
Decoy 7
\n
Decoy 8
\n
Decoy 9
\n
Decoy 10
\n
Decoy 11
\n
Decoy 12
\n
Decoy 13
\n
Decoy 14
\n
\n
\n

White text on a near-white image background is unreadable, and only pixel sampling can prove it.

\n
\n
\n

Dark ink on the same image background reads fine and must not flag.

\n
\n\n\n",{"styleText":"\n body { margin: 0; padding: 40px; background: #17150f; font-family: Arial, sans-serif; }\n /* A same-origin (data-URI) near-white image background. The analytic walk\n cannot know its pixels, so the default overlay pass must sample the image\n itself: white text on it fails, dark ink on it passes. */\n .photo-panel {\n width: 420px;\n padding: 24px;\n margin: 0 0 24px;\n background: url(\"data:image/svg+xml;utf8,\") center / cover no-repeat;\n }\n .flag-white-on-light { color: #fdfdfd; font-size: 16px; line-height: 1.6; margin: 0; }\n .pass-ink-on-light { color: #262421; font-size: 16px; line-height: 1.6; margin: 0; }\n /* Fourteen gradient-backed decoys sit BEFORE the photo panels in DOM\n order. They are visual-contrast candidates (gradient background) but not\n image-backed; with the default 12-candidate cap they would starve the\n image-only pass to zero unless the mode filters inside the collector.\n Their ink is dark on a light gradient, so no analytic finding fires. */\n .decoy { display: inline-block; padding: 4px 8px; margin: 0 4px 6px 0; background: linear-gradient(180deg, #f2efe6, #e8e4d8); color: #24211c; font-size: 12px; }\n","classText":"decoy-row\ndecoy\ndecoy\ndecoy\ndecoy\ndecoy\ndecoy\ndecoy\ndecoy\ndecoy\ndecoy\ndecoy\ndecoy\ndecoy\ndecoy\nphoto-panel\nflag-white-on-light\nphoto-panel\npass-ink-on-light"}],"result":[]} {"args":["\n\n\n \n Italic-Serif-Display — Should Flag vs Should Pass\n \n\n\n
\n\n \n
\n

Should flag

\n\n
\n

Fraunces 88px italic

\n

The Lumina hero pattern: oversized Fraunces italic display.

\n
\n\n
\n

Recoleta 64px italic

\n

Recoleta italic at 64px, generic serif fallback.

\n
\n\n
\n

Playfair 72px italic

\n

Playfair Display italic at hero scale.

\n
\n\n
\n

Unknown Serif Generic Fallback

\n

Primary font unknown to the detector, but the stack ends in generic serif.

\n
\n
\n\n \n
\n

Should pass

\n\n
\n

Sans Italic Display

\n

Italic at hero scale, but in a sans-serif face.

\n
\n\n
\n

Roman Serif Display

\n

Fraunces at 88px, but font-style is normal (not italic).

\n
\n\n
\n
Italic Serif Pull Quote
\n

Italic serif at 24px is a legitimate pull-quote pattern, not a hero.

\n
\n\n
\n

Inline Em Inside Roman

\n

Roman h1 with an inline italic em — v1 deliberately does not flag this.

\n
\n\n
\n

Italic Serif at 32px

\n

Italic serif h2 below the 48px hero threshold.

\n
\n\n
\n

h1 Sans-Serif Roman

\n

Baseline-clean control: sans-serif, roman, hero scale.

\n
\n
\n\n
\n\n\n",{"styleText":"\n /* ─── Layout convention: two-column fixture ─────────────────────────\n Left column = patterns the rule SHOULD flag.\n Right column = legitimate patterns the rule should NOT flag.\n Each test case is annotated with a unique

/

/
\n text so the test can match snippets back to expectations.\n ──────────────────────────────────────────────────────────────── */\n body { font-family: system-ui, sans-serif; margin: 0; padding: 24px; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1200px; margin: 0 auto; }\n .col h2.col-label { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .case { margin-bottom: 32px; padding: 24px; border: 1px solid #e2e8f0; border-radius: 12px; background: #fff; }\n .case p { font-size: 14px; margin: 12px 0 0; color: #64748b; }\n\n /* ── FLAG cases ── */\n\n /* 1: Fraunces 88px italic — the Lumina hero pattern */\n .hero-fraunces {\n font-family: 'Fraunces', Georgia, serif;\n font-style: italic;\n font-size: 88px;\n font-weight: 400;\n line-height: 1.05;\n margin: 0;\n }\n\n /* 2: Recoleta 64px italic */\n .hero-recoleta {\n font-family: 'Recoleta', serif;\n font-style: italic;\n font-size: 64px;\n font-weight: 400;\n margin: 0;\n }\n\n /* 3: Playfair Display 72px italic */\n .hero-playfair {\n font-family: 'Playfair Display', serif;\n font-style: italic;\n font-size: 72px;\n font-weight: 500;\n margin: 0;\n }\n\n /* 4: Unknown serif primary, but generic `serif` fallback in stack */\n .hero-unknown-serif {\n font-family: 'CustomSerifFace', serif;\n font-style: italic;\n font-size: 56px;\n font-weight: 400;\n margin: 0;\n }\n\n /* ── PASS cases ── */\n\n /* a: italic, but sans-serif primary (Karla) — italic display in a sans is rare and usually intentional */\n .pass-sans-italic {\n font-family: 'Karla', sans-serif;\n font-style: italic;\n font-size: 64px;\n font-weight: 600;\n margin: 0;\n }\n\n /* b: serif at 88px, but font-style: normal */\n .pass-roman-serif {\n font-family: 'Fraunces', Georgia, serif;\n font-style: normal;\n font-size: 88px;\n font-weight: 600;\n margin: 0;\n }\n\n /* c: italic serif blockquote at 24px (genuine pull quote, not a hero) */\n .pass-pull-quote {\n font-family: 'Fraunces', Georgia, serif;\n font-style: italic;\n font-size: 24px;\n font-weight: 400;\n margin: 0;\n color: #334155;\n }\n\n /* d: roman h1 with an italic inside — v1 explicitly does NOT flag this */\n .pass-roman-h1-em-italic {\n font-family: 'Inter', sans-serif;\n font-style: normal;\n font-size: 72px;\n font-weight: 600;\n margin: 0;\n }\n .pass-roman-h1-em-italic em {\n font-family: 'Fraunces', Georgia, serif;\n font-style: italic;\n font-weight: 400;\n }\n\n /* e: italic serif h2 at 32px — under the 48px hero threshold */\n .pass-italic-serif-32 {\n font-family: 'Fraunces', Georgia, serif;\n font-style: italic;\n font-size: 32px;\n font-weight: 400;\n margin: 0;\n }\n\n /* f: baseline-clean h1 — sans-serif roman */\n .pass-h1-sans-roman {\n font-family: 'Inter', sans-serif;\n font-style: normal;\n font-size: 64px;\n font-weight: 700;\n margin: 0;\n }\n ","classText":"grid\ncol\ncol-label\ncase\nhero-fraunces\ncase\nhero-recoleta\ncase\nhero-playfair\ncase\nhero-unknown-serif\ncol\ncol-label\ncase\npass-sans-italic\ncase\npass-roman-serif\ncase\npass-pull-quote\ncase\npass-roman-h1-em-italic\ncase\npass-italic-serif-32\ncase\npass-h1-sans-roman"}],"result":[]} {"args":["\n\n\n \n Kicker Above Heading Fixture\n \n\n\n
\n
\n

Should flag

\n\n
\n Invitation protocol\n

\"A Single Kicker Still Flags\"

\n

One tracked uppercase label above one heading is enough. No repetition required.

\n
\n\n
\n Output model\n

\"Standard Tracking Kicker\"

\n

Uppercase at 12px with 0.08em tracking is the most common authored kicker and must flag.

\n
\n\n
\n

Preview sequence

\n

\"Kicker Above An H3\"

\n

Subsection headings get no eyebrow either.

\n
\n\n
\n
Access window
\n

\"Kicker Above An H4\"

\n

The ban runs down to h4.

\n
\n\n
\n Platform notes\n

\"Sub Hero Heading\"

\n

A 32px h1 is below hero scale, so this pair belongs to the general ban.

\n
\n\n
\n materials briefing\n

\"Small Caps Kicker\"

\n

Small-caps styling is the same label in a different costume.

\n
\n\n
\n
Field studies
\n
\"Heading Role Kicker\"
\n

Elements carrying a heading role are headings for this rule.

\n
\n
\n\n
\n

Should pass

\n\n
\n\n
\n Home / Journal / Archive\n

\"Breadcrumb Trail Outside Nav\"

\n

A path with separators is wayfinding, not a kicker, even without a nav wrapper.

\n
\n\n
\n News · Jan 12, 2026\n

\"Dateline Above Headline\"

\n

Editorial category-and-date meta lines are content metadata.

\n
\n\n
\n Field report\n

\"Editorial Card Meta\"

\n

Category labels inside an article card are structured metadata for scanning.

\n
\n\n
\n \n \n

\"Form Heading Is Separate\"

\n
\n\n
\n
Plate study
\n

\"Figure Caption Label\"

\n
\n\n
\n Section 4.2\n

\"Limitation Of Liability\"

\n

Legal and document numbering identifies the clause; it is not decoration.

\n
\n\n
\n § 12.3\n

\"Indemnification Clause\"

\n

Statutory references keep their marker.

\n
\n\n
\n Chapter Four\n

\"Chapter Numbering Passes\"

\n

Spelled-out chapter numbering is document structure, like legal numbering.

\n
\n\n
\n Next from\n

\"Application Panel Context\"

\n

Context labels inside application panels describe state, not decoration.

\n
\n\n
\n \n

\"Page Title After Nav\"

\n

A navigation landmark preceding the page title is chrome, not a kicker.

\n
\n\n
\n

\"48%\"

\n Growth yoy\n

Stat callouts put the small label below the number. That direction is legal.

\n
\n\n
\n A quiet lead-in sentence\n

\"Sentence Case Lead In\"

\n

Not uppercase, not small-caps: an ordinary standfirst.

\n
\n\n
\n New arrivals\n

\"Untracked Caps Label\"

\n

Uppercase without tracking lacks the kicker styling signature.

\n
\n\n
\n Archive code\n

\"Intentional Brand Label\"

\n

Deliberate brand systems can opt out with an explicit marker.

\n
\n\n
\n Platform overview\n

\"Hero Owned By Hero Rule\"

\n

Hero-scale h1 eyebrows stay with hero-eyebrow-chip; this rule stands down.

\n
\n\n
\n
\n Suite\n

\"Garden Suite\"

\n

Category labels inside sibling cards are metadata for comparison.

\n
\n
\n Suite\n

\"Sea Loft\"

\n

The label is useful because the user is scanning sibling cards.

\n
\n
\n\n
    \n
  1. \n Step 01\n

    \"Step Indicator\"

    \n

    Step indicators in ordered flows are sequence markers.

    \n
  2. \n
\n\n
\n
\n Amalfi Coast\n

\"Mockup Hero Variant One\"

\n
\n
\n
\n
\n\n\n",{"styleText":"\n body {\n margin: 0;\n font-family: Arial, sans-serif;\n background: #f6f2ec;\n color: #171411;\n }\n main {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 32px;\n padding: 32px;\n }\n .col {\n min-width: 0;\n border: 1px solid #c9bfb2;\n padding: 24px;\n }\n .case {\n min-height: 120px;\n margin: 0 0 24px;\n padding: 16px;\n background: #fffaf3;\n }\n .kicker,\n .pass-kicker,\n .pass-kicker-caps {\n display: block;\n width: 240px;\n min-height: 16px;\n margin: 0 0 8px;\n font-size: 12px;\n line-height: 16px;\n letter-spacing: 0.11em;\n color: #5b5046;\n }\n .kicker,\n .pass-kicker-caps {\n text-transform: uppercase;\n }\n /* The wild's most common kicker recipe: 0.08em tracking at a sub-13px\n size computes to under 1px, which the old absolute floor excluded. */\n .tight-tracked-kicker {\n display: block;\n width: 240px;\n min-height: 16px;\n margin: 0 0 8px;\n font-size: 12px;\n line-height: 16px;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: #5b5046;\n }\n .smallcaps-kicker {\n display: block;\n width: 240px;\n min-height: 16px;\n margin: 0 0 8px;\n font-size: 12px;\n line-height: 16px;\n letter-spacing: 0.12em;\n font-variant: small-caps;\n color: #5b5046;\n }\n .untracked-caps {\n display: block;\n width: 240px;\n min-height: 16px;\n margin: 0 0 8px;\n font-size: 12px;\n line-height: 16px;\n letter-spacing: normal;\n text-transform: uppercase;\n color: #5b5046;\n }\n h1,\n h2 {\n margin: 0 0 12px;\n font-size: 32px;\n line-height: 38px;\n font-weight: 700;\n }\n h3 {\n margin: 0 0 12px;\n font-size: 24px;\n line-height: 30px;\n font-weight: 700;\n }\n h4 {\n margin: 0 0 12px;\n font-size: 20px;\n line-height: 26px;\n font-weight: 700;\n }\n .role-heading {\n margin: 0 0 12px;\n font-size: 28px;\n line-height: 34px;\n font-weight: 700;\n }\n .hero-h1 {\n margin: 0 0 12px;\n font-size: 64px;\n line-height: 70px;\n font-weight: 700;\n }\n .hero-eyebrow {\n display: block;\n width: 240px;\n min-height: 16px;\n margin: 0 0 8px;\n font-size: 12px;\n line-height: 16px;\n letter-spacing: 2px;\n text-transform: uppercase;\n color: #5b5046;\n }\n p,\n label,\n figcaption,\n a,\n li {\n font-size: 16px;\n line-height: 24px;\n }\n nav,\n form,\n figure,\n ol {\n margin: 0 0 24px;\n padding: 16px;\n border: 1px solid #d8cec0;\n min-height: 80px;\n }\n .card-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 12px;\n margin: 0 0 24px;\n }\n .suite-card {\n display: block;\n min-height: 120px;\n padding: 16px;\n border: 1px solid #d8cec0;\n background: #fff;\n }\n .taxonomy-label {\n display: block;\n margin: 0 0 8px;\n font-size: 12px;\n line-height: 16px;\n letter-spacing: 0.11em;\n text-transform: uppercase;\n color: #5b5046;\n }\n .suite-card h3 {\n font-size: 24px;\n line-height: 30px;\n }\n .stat {\n min-height: 100px;\n padding: 16px;\n background: #fffaf3;\n }\n .stat h3 {\n font-size: 40px;\n line-height: 46px;\n }\n .hidden-mockup {\n display: grid;\n gap: 12px;\n margin: 0 0 24px;\n }\n .mockup-hero {\n min-height: 120px;\n padding: 16px;\n border: 1px solid #d8cec0;\n background: #fff;\n }\n .mockup-hero h2 {\n font-size: 24px;\n line-height: 30px;\n }\n \nstyle=\"width: 220px; height: 40px;\"","classText":"col\ncase\nkicker\ncase\ntight-tracked-kicker\ncase\nkicker\ncase\nkicker\ncase\nkicker\nsub-hero\ncase\nsmallcaps-kicker\ncase\nkicker\nrole-heading\ncol\ncase\npass-kicker\ncase\npass-kicker-caps\ncase\npass-kicker-caps\ncase\npass-kicker-caps\ncase\npass-kicker\ncase\npass-kicker-caps\ncase\npass-kicker-caps\ncase\npass-kicker-caps\ncase\npass-kicker-caps\ncase\npass-kicker-caps\ncase\nstat\npass-kicker-caps\ncase\npass-kicker\ncase\nuntracked-caps\ncase\npass-kicker-caps\ncase\nhero-eyebrow\nhero-h1\ncard-grid\nsuite-card\ntaxonomy-label\nsuite-card\ntaxonomy-label\ncase\npass-kicker-caps\nhidden-mockup\nmockup-hero\ntaxonomy-label"}],"result":[]} @@ -41,10 +41,10 @@ {"args":["\n\n\nPseudo-element side stripe fixture\n\n\n\n
Card with pseudo stripe
\n
Row with right stripe
\n
One
Two
\n
Timeline
\n
Quoted text
\n \n
Panel
\n

Heading

\n\n\n",{"styleText":"\n :root {\n --ok: oklch(0.78 0.145 155);\n --line: rgba(0, 0, 0, 0.08);\n }\n\n /* FLAG: classic ::before accent stripe — absolute, full height, left edge,\n chromatic background resolved through a custom property. */\n .card-stripe { position: relative; border-radius: 12px; }\n .card-stripe::before {\n content: \"\";\n position: absolute;\n left: 0; top: 0; bottom: 0;\n width: 5px;\n background: var(--ok);\n }\n\n /* FLAG: right-edge variant using inset shorthand + literal color. */\n .row-stripe { position: relative; }\n .row-stripe::after {\n content: \"\";\n position: absolute;\n inset: 0 0 0 auto;\n width: 4px;\n background-color: #3b82f6;\n }\n\n /* PASS: 1px neutral hairline divider (below width threshold + neutral). */\n .col + .col::before {\n content: \"\";\n position: absolute;\n left: 0; top: 0; bottom: 0;\n width: 1px;\n background: var(--line);\n }\n\n /* PASS: neutral 4px rail (timeline spine) — chromatic gate rejects it. */\n .timeline::before {\n content: \"\";\n position: absolute;\n left: 0; top: 0; bottom: 0;\n width: 4px;\n background: rgb(210, 210, 214);\n }\n\n /* PASS: blockquote decoration is exempt in prose contexts. */\n blockquote::before {\n content: \"\";\n position: absolute;\n left: 0; top: 0; bottom: 0;\n width: 4px;\n background: #d97706;\n }\n\n /* PASS: toggle knob — offset from the edge, not a stripe. */\n .switch::before {\n content: \"\";\n position: absolute;\n left: 2px; top: 2px;\n width: 10px; height: 10px;\n border-radius: 50%;\n background: #3b82f6;\n }\n\n /* PASS: wide decorative panel, not a stripe. */\n .panel::before {\n content: \"\";\n position: absolute;\n left: 0; top: 0; bottom: 0;\n width: 40px;\n background: #3b82f6;\n }\n\n /* PASS: horizontal underline accent (not full height, not edge-anchored\n vertically). */\n .heading::after {\n content: \"\";\n position: absolute;\n left: 0; bottom: 0;\n width: 6px; height: 3px;\n background: #3b82f6;\n }\n","classText":"card-stripe\nrow-stripe\ncol\ncol\ntimeline\nswitch\npanel\nheading"}],"result":[{"id":"side-tab","snippet":".card-stripe::before — absolute 5px pseudo-element stripe (left: 0)","index":287,"selector":".card-stripe::before"},{"id":"side-tab","snippet":".row-stripe::after — absolute 4px pseudo-element stripe (right: 0)","index":543,"selector":".row-stripe::after"}]} {"args":["\n\n\nPulsing status dot fixture\n\n\n\n
\n Brand\n
\n \n Online\n \n \n \n
Card
\n \n \n \n \n \n
\n\n\n",{"styleText":"\n :root { --dot: 8px; }\n\n /* FLAG: tiny circular live dot on an infinite opacity pulse. */\n .live-dot {\n width: 7px; height: 7px;\n border-radius: 50%;\n background: #22c55e;\n animation: pulse 2.4s ease-out infinite;\n }\n @keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n }\n\n /* FLAG: box-shadow ripple variant, var-sized, pill radius. */\n .status .dot {\n width: var(--dot); height: var(--dot);\n border-radius: 999px;\n background: #ef4444;\n animation: ripple 1.8s linear infinite;\n }\n @keyframes ripple {\n 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); }\n 100% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); }\n }\n\n /* FLAG: longhand animation-name + iteration-count. */\n .beacon {\n width: 10px; height: 10px;\n border-radius: 50%;\n background: #f59e0b;\n animation-name: pulse;\n animation-duration: 2s;\n animation-iteration-count: infinite;\n }\n\n /* PASS: rotation-only spinner — same size class, must never flag. */\n .spinner {\n width: 14px; height: 14px;\n border-radius: 50%;\n border: 2px solid #e5e7eb;\n border-top-color: #3b82f6;\n animation: spin 0.8s linear infinite;\n }\n @keyframes spin { to { transform: rotate(360deg); } }\n\n /* PASS: named pulse but the local keyframes only rotate. */\n .fake-pulse {\n width: 8px; height: 8px;\n border-radius: 50%;\n animation: pulse-ring 1s linear infinite;\n }\n @keyframes pulse-ring { to { transform: rotate(180deg); } }\n\n /* PASS: large breathing card — not a dot. */\n .breathing-card {\n width: 240px; height: 120px;\n border-radius: 16px;\n animation: pulse 3s ease-in-out infinite;\n }\n\n /* PASS: finite attention pulse (no infinite). */\n .nudge {\n width: 8px; height: 8px;\n border-radius: 50%;\n animation: pulse 0.6s ease-out 3;\n }\n\n /* PASS: square badge, not circular. */\n .square-badge {\n width: 12px; height: 12px;\n border-radius: 2px;\n animation: pulse 2s infinite;\n }\n\n /* FLAG (error): header logo dot whose size and animation live in\n separate rule blocks, animation added inside a matching media query,\n with a reduced-motion reset that must not mask the default. */\n .rec-mark {\n width: 10px; height: 10px;\n border-radius: 50%;\n background: #dc2626;\n }\n @media (prefers-reduced-motion: no-preference) {\n .rec-mark { animation: pulse 2.4s ease-in-out infinite; }\n }\n @media (prefers-reduced-motion: reduce) {\n .rec-mark { animation: none; }\n }\n","classText":"rec-mark\nlive-dot\nstatus\ndot\nbeacon\nspinner\nfake-pulse\nbreathing-card\nnudge\nsquare-badge\nanimate-ping w-2 h-2 rounded-full bg-emerald-500\nanimate-pulse rounded-md w-48 h-6 bg-gray-200"}],"result":[{"id":"pulsing-dot","snippet":".live-dot — 7x7px dot with infinite \"pulse\" animation","selector":".live-dot"},{"id":"pulsing-dot","snippet":".status .dot — 8x8px dot with infinite \"ripple\" animation","selector":".status .dot"},{"id":"pulsing-dot","snippet":".beacon — 10x10px dot with infinite \"pulse\" animation","selector":".beacon"},{"id":"pulsing-dot","snippet":".rec-mark — 10x10px dot with infinite \"pulse\" animation in header/nav","selector":".rec-mark","severity":"error"},{"id":"pulsing-dot","snippet":"animate-ping on tiny rounded-full element"}]} {"args":["\n\n\n \n \n Quality (Typography & Readability) — Should Flag vs Should Pass\n \n\n\n
\n\n \n
\n

Should flag

\n\n

Line length too long

\n
\n no max-width on a paragraph\n

This paragraph has no max-width constraint at all, which means on a wide monitor or ultrawide display, each line of text can stretch to 150 or even 200 characters wide. Research consistently shows that line lengths beyond 75 characters significantly reduce reading speed and comprehension. The eye has to travel too far to find the beginning of the next line, causing readers to lose their place. A simple max-width of 65ch to 75ch on the paragraph or its container would fix this entirely.

\n
\n\n

Tight line height

\n
\n line-height: 1.0\n

This paragraph has a line-height of 1.0, which means the lines are touching. Multi-line body text needs breathing room between lines for readability. A line-height of 1.5 to 1.7 is generally recommended for body text.

\n
\n\n

Tiny body text

\n
\n 10px body text\n

This body text is only 10px. While this might be fine for a disclaimer or legal footnote, it's too small for primary content that users need to actually read. Aim for at least 14px for body content, 16px is ideal.

\n
\n\n

Justified text without hyphens

\n
\n text-align: justify, no hyphens: auto\n

This paragraph uses text-align: justify, which forces each line to stretch to fill the full width. Without hyphenation support, this creates uneven gaps between words known as \"rivers of white space\" that flow vertically through the text. Left-aligned text is almost always more readable on the web.

\n
\n\n

All-caps body text

\n
\n text-transform: uppercase on a long passage\n

This entire paragraph is in uppercase via text-transform. While all-caps works for short labels, headings, or navigation items, longer body text in uppercase is significantly harder to read because we lose the word shape cues that come from ascenders and descenders in mixed-case text.

\n
\n\n

Wide letter spacing on body text

\n
\n letter-spacing: 0.15em on body text\n

This body text has letter-spacing: 0.15em applied to it. While subtle tracking adjustments can improve readability for headings or all-caps text, adding significant letter spacing to body text actually makes it harder to read by disrupting natural character groupings.

\n
\n\n

Skipped heading levels

\n
\n h1 → h3 (missing h2)\n

Top heading

\n

Skips straight to h3

\n
\n
\n\n \n
\n

Should pass

\n\n

Comfortable line length

\n
\n max-width: 65ch on the paragraph\n

This paragraph has a max-width of 65ch, keeping the line length comfortable for reading. The eye can easily track from the end of one line to the beginning of the next without losing its place.

\n
\n\n

Comfortable line height

\n
\n line-height: 1.6\n

This paragraph has a line-height of 1.6, which gives multi-line text plenty of room to breathe and improves the rhythm of the page.

\n
\n\n

Comfortable body text size

\n
\n 16px body text\n

This is 16px body text — the recommended baseline for comfortable reading on modern displays.

\n
\n\n

Justified text with hyphens

\n
\n text-align: justify + hyphens: auto\n

When justified text is paired with hyphens: auto, the browser can break long words across lines, eliminating the rivers of white space and making the justification look intentional rather than awkward.

\n
\n\n

Short label in all-caps

\n
\n short label, uppercase\n Featured\n
\n\n

Wide tracking on a short uppercase label

\n
\n letter-spacing on a short uppercase label\n Beta\n
\n\n

Proper heading hierarchy

\n
\n h1 → h2 → h3\n

Top heading

\n

Second level

\n

Third level

\n
\n\n

Small mockup metadata

\n
\n terminal/diff metadata at tiny sizes\n /impeccable polish : scanning codebase\n
12 files inspected · 4 visual issues queued
\n
+ Replace generic button label with action-specific copy
\n
\n
\n
\n \n \n \n \n impeccable\n \n\n\n",{"styleText":"\n /* Two-column fixture: left = should flag, right = should pass.\n Covers the typography-quality rules that need real browser layout\n (line-length, tight-leading, tiny-text, justified-text, all-caps-body,\n wide-tracking, skipped-heading). All are browser-only — see\n tests/detect-antipatterns-browser.test.mjs for assertions. */\n body { font-family: system-ui, sans-serif; background: #fafafa; padding: 24px; margin: 0; color: #0f172a; line-height: 1.6; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1280px; margin: 0 auto; }\n .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .col h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; margin: 24px 0 8px; color: #64748b; }\n .case { margin-bottom: 16px; padding: 16px; background: white; border: 1px solid #e2e8f0; border-radius: 8px; }\n .case-label { display: block; font-size: 12px; color: #64748b; margin-bottom: 6px; font-style: italic; }\n\n /* ── FLAG: typography quality issues ── */\n\n /* Line length: 12px body text fits >85 chars/line in a ~528px column.\n 12px is not below the tiny-text 12px floor (rule fires at <12px). */\n .long-lines {\n font-size: 12px;\n line-height: 1.6;\n }\n\n /* Tight leading */\n .tight-leading {\n font-size: 16px;\n line-height: 1.0;\n max-width: 40em;\n }\n\n /* Tiny body text */\n .tiny-text {\n font-size: 10px;\n line-height: 1.6;\n max-width: 40em;\n }\n .tiny-text-11 {\n font-size: 11px;\n line-height: 1.6;\n max-width: 40em;\n }\n\n /* Justified text without hyphens */\n .justified-no-hyphens {\n text-align: justify;\n max-width: 30em;\n font-size: 16px;\n line-height: 1.6;\n }\n\n /* All-caps long body */\n .all-caps-body {\n text-transform: uppercase;\n font-size: 16px;\n max-width: 40em;\n line-height: 1.6;\n }\n\n /* Wide letter spacing on body */\n .wide-tracking-body {\n letter-spacing: 0.15em;\n font-size: 16px;\n max-width: 40em;\n line-height: 1.6;\n }\n\n /* ── PASS: comfortable typography ── */\n\n .good-measure {\n max-width: 65ch;\n font-size: 16px;\n line-height: 1.6;\n }\n\n .good-leading {\n font-size: 16px;\n line-height: 1.6;\n max-width: 40em;\n }\n\n .good-text-size {\n font-size: 16px;\n line-height: 1.6;\n max-width: 40em;\n }\n\n /* Justified text WITH hyphens — fine */\n .justified-with-hyphens {\n text-align: justify;\n hyphens: auto;\n -webkit-hyphens: auto;\n max-width: 30em;\n font-size: 16px;\n line-height: 1.6;\n }\n\n /* Short label in all-caps (passes — under 30 chars) */\n .label-caps {\n text-transform: uppercase;\n font-size: 12px;\n font-weight: 600;\n letter-spacing: 0.1em;\n color: #475569;\n }\n\n /* Wide tracking on a short uppercase label (passes — both conditions excluded) */\n .label-tracking {\n letter-spacing: 0.15em;\n text-transform: uppercase;\n font-size: 12px;\n font-weight: 600;\n color: #475569;\n }\n\n .mock-terminal-title,\n .mock-terminal-meta,\n .mock-diff-line {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n color: #475569;\n line-height: 1.5;\n }\n .mock-terminal-title { font-size: 11px; }\n .mock-terminal-meta { font-size: 10.8px; }\n .mock-diff-line { font-size: 11.84px; }\n \nstyle=\"font-size: 20px; margin: 0 0 4px;\"\nstyle=\"font-size: 16px; margin: 0;\"\nstyle=\"font-size: 20px; margin: 0 0 4px;\"\nstyle=\"font-size: 18px; margin: 0 0 4px;\"\nstyle=\"font-size: 16px; margin: 0;\"","classText":"grid\ncol\ncase\ncase-label\nlong-lines\ncase\ncase-label\ntight-leading\ncase\ncase-label\ntiny-text\ncase\ncase-label\njustified-no-hyphens\ncase\ncase-label\nall-caps-body\ncase\ncase-label\nwide-tracking-body\ncase\ncase-label\ncol\ncase\ncase-label\ngood-measure\ncase\ncase-label\ngood-leading\ncase\ncase-label\ngood-text-size\ncase\ncase-label\njustified-with-hyphens\ncase\ncase-label\nlabel-caps\ncase\ncase-label\nlabel-tracking\ncase\ncase-label\ncase\ncase-label\nmock-terminal-title\nmock-terminal-meta\nmock-diff-line\nsvg-metrics-pass"}],"result":[]} -{"args":["\n\n\n\nradial-spotlight-glow fixture\n\n\n\n
\n \n
\n
\n
\n
\n
\n\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n\n",{"styleText":"\n /* jsdom / static-html engine does no layout: every case declares explicit\n pixel width + height so the size gate can read them. */\n body { margin: 0; background: #0b0d13; }\n .grid { display: flex; flex-wrap: wrap; gap: 24px; padding: 24px; }\n .case { color: #e6e6e6; }\n\n /* ───────── SHOULD FLAG: decorative low-opacity chromatic spotlights ───────── */\n\n /* The exact declaration that evaded the detector: soft blue spotlight fading\n to transparent, painted on a large mobile hero. */\n .flag-hero-blue {\n width: 360px; height: 560px;\n background: radial-gradient(circle at 52% 38%, rgba(80,111,255,0.26), transparent 44%);\n }\n /* Violet accent wash on a full section. */\n .flag-section-violet {\n width: 900px; height: 600px;\n background-image: radial-gradient(circle, rgba(139,92,246,0.30), transparent 60%);\n }\n /* Cyan overlay-style glow (the pseudo-element overlay div reflex). */\n .flag-overlay-cyan {\n width: 760px; height: 480px;\n background: radial-gradient(ellipse at top, rgba(34,211,238,0.22), transparent 70%);\n }\n /* Single glow drawn with two low-alpha stops of one hue fading out. */\n .flag-two-stop-rose {\n width: 640px; height: 400px;\n background: radial-gradient(circle, rgba(255,90,120,0.28) 0%, rgba(255,90,120,0.12) 45%, transparent 75%);\n }\n /* Same tell written as an 8-digit hex (#506fff at alpha 0x3d ≈ 0.24). */\n .flag-hex-alpha {\n width: 700px; height: 460px;\n background: radial-gradient(circle, #506fff3d, transparent 50%);\n }\n\n /* ───────── SHOULD PASS: real backgrounds, small elements, neutrals, rich art ───────── */\n\n /* Opaque radial background — a real surface, not a glow (no transparent end). */\n .pass-opaque-bg {\n width: 800px; height: 520px;\n background: radial-gradient(circle, #1e3a8a, #0f172a);\n }\n /* Small badge: chromatic low-alpha radial glow, but tiny. */\n .pass-badge {\n width: 40px; height: 40px;\n background: radial-gradient(circle, rgba(80,111,255,0.30), transparent);\n }\n /* Avatar-scale light: the subject IS a small light, exempt by size. */\n .pass-avatar-light {\n width: 72px; height: 72px;\n background: radial-gradient(circle, rgba(255,196,64,0.35), transparent 70%);\n }\n /* Neutral near-black vignette — grayscale, not the accent-glow tell. */\n .pass-neutral-vignette {\n width: 800px; height: 520px;\n background: radial-gradient(circle, rgba(0,0,0,0.40), transparent 80%);\n }\n /* Neutral near-white vignette — grayscale, exempt. */\n .pass-white-vignette {\n width: 820px; height: 540px;\n background: radial-gradient(ellipse, rgba(255,255,255,0.35), transparent 70%);\n }\n /* Rich three-color radial composition — real color structure, opaque, no fade. */\n .pass-rich-composition {\n width: 800px; height: 520px;\n background: radial-gradient(circle, #ff0080 0%, #7928ca 45%, #0070f3 100%);\n }\n /* Rich composition that does fade out, but its color stops are opaque. */\n .pass-rich-transparent {\n width: 780px; height: 500px;\n background: radial-gradient(circle, rgba(255,0,128,0.90) 0%, rgba(121,40,202,0.85) 50%, transparent);\n }\n /* Opaque center glow (the radial-halo case, alpha ≥ 0.45) — not this rule. */\n .pass-opaque-center {\n width: 800px; height: 520px;\n background: radial-gradient(circle, rgba(80,111,255,0.85), transparent);\n }\n /* Low-alpha chromatic wash, but LINEAR, not radial. */\n .pass-linear-wash {\n width: 800px; height: 520px;\n background: linear-gradient(120deg, rgba(80,111,255,0.28), transparent 60%);\n }\n","classText":"grid\ncase flag-hero-blue\ncase flag-section-violet\ncase flag-overlay-cyan\ncase flag-two-stop-rose\ncase flag-hex-alpha\ncase pass-opaque-bg\ncase pass-badge\ncase pass-avatar-light\ncase pass-neutral-vignette\ncase pass-white-vignette\ncase pass-rich-composition\ncase pass-rich-transparent\ncase pass-opaque-center\ncase pass-linear-wash"}],"result":[{"id":"radial-halo","snippet":"radial-gradient halo (#ff0080 → transparent) on dark page","selector":"/* Rich composition that does fade out, but its color stops are opaque. */ .pass-rich-transparent"}]} +{"args":["\n\n\n\nradial-spotlight-glow fixture\n\n\n\n
\n \n
\n
\n
\n
\n
\n\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n\n",{"styleText":"\n /* jsdom / static-html engine does no layout: every case declares explicit\n pixel width + height so the size gate can read them. */\n body { margin: 0; background: #0b0d13; }\n .grid { display: flex; flex-wrap: wrap; gap: 24px; padding: 24px; }\n .case { color: #e6e6e6; }\n\n /* ───────── SHOULD FLAG: decorative low-opacity chromatic spotlights ───────── */\n\n /* The exact declaration that evaded the detector: soft blue spotlight fading\n to transparent, painted on a large mobile hero. */\n .flag-hero-blue {\n width: 360px; height: 560px;\n background: radial-gradient(circle at 52% 38%, rgba(80,111,255,0.26), transparent 44%);\n }\n /* Violet accent wash on a full section. */\n .flag-section-violet {\n width: 900px; height: 600px;\n background-image: radial-gradient(circle, rgba(139,92,246,0.30), transparent 60%);\n }\n /* Cyan overlay-style glow (the pseudo-element overlay div reflex). */\n .flag-overlay-cyan {\n width: 760px; height: 480px;\n background: radial-gradient(ellipse at top, rgba(34,211,238,0.22), transparent 70%);\n }\n /* Single glow drawn with two low-alpha stops of one hue fading out. */\n .flag-two-stop-rose {\n width: 640px; height: 400px;\n background: radial-gradient(circle, rgba(255,90,120,0.28) 0%, rgba(255,90,120,0.12) 45%, transparent 75%);\n }\n /* Same tell written as an 8-digit hex (#506fff at alpha 0x3d ≈ 0.24). */\n .flag-hex-alpha {\n width: 700px; height: 460px;\n background: radial-gradient(circle, #506fff3d, transparent 50%);\n }\n\n /* ───────── SHOULD PASS: real backgrounds, small elements, neutrals, rich art ───────── */\n\n /* Opaque radial background — a real surface, not a glow (no transparent end). */\n .pass-opaque-bg {\n width: 800px; height: 520px;\n background: radial-gradient(circle, #1e3a8a, #0f172a);\n }\n /* Small badge: chromatic low-alpha radial glow, but tiny. */\n .pass-badge {\n width: 40px; height: 40px;\n background: radial-gradient(circle, rgba(80,111,255,0.30), transparent);\n }\n /* Avatar-scale light: the subject IS a small light, exempt by size. */\n .pass-avatar-light {\n width: 72px; height: 72px;\n background: radial-gradient(circle, rgba(255,196,64,0.35), transparent 70%);\n }\n /* Neutral near-black vignette — grayscale, not the accent-glow tell. */\n .pass-neutral-vignette {\n width: 800px; height: 520px;\n background: radial-gradient(circle, rgba(0,0,0,0.40), transparent 80%);\n }\n /* Neutral near-white vignette — grayscale, exempt. */\n .pass-white-vignette {\n width: 820px; height: 540px;\n background: radial-gradient(ellipse, rgba(255,255,255,0.35), transparent 70%);\n }\n /* Rich three-color radial composition — real color structure, opaque, no fade. */\n .pass-rich-composition {\n width: 800px; height: 520px;\n background: radial-gradient(circle, #ff0080 0%, #7928ca 45%, #0070f3 100%);\n }\n /* Rich composition that does fade out, but its color stops are opaque. */\n .pass-rich-transparent {\n width: 780px; height: 500px;\n background: radial-gradient(circle, rgba(255,0,128,0.90) 0%, rgba(121,40,202,0.85) 50%, transparent);\n }\n /* Opaque center glow (the radial-halo case, alpha ≥ 0.45) — not this rule. */\n .pass-opaque-center {\n width: 800px; height: 520px;\n background: radial-gradient(circle, rgba(80,111,255,0.85), transparent);\n }\n /* Low-alpha chromatic wash, but LINEAR, not radial. */\n .pass-linear-wash {\n width: 800px; height: 520px;\n background: linear-gradient(120deg, rgba(80,111,255,0.28), transparent 60%);\n }\n","classText":"grid\ncase flag-hero-blue\ncase flag-section-violet\ncase flag-overlay-cyan\ncase flag-two-stop-rose\ncase flag-hex-alpha\ncase pass-opaque-bg\ncase pass-badge\ncase pass-avatar-light\ncase pass-neutral-vignette\ncase pass-white-vignette\ncase pass-rich-composition\ncase pass-rich-transparent\ncase pass-opaque-center\ncase pass-linear-wash"}],"result":[{"id":"radial-halo","snippet":"radial-gradient halo (#ff0080 → transparent) on dark page","selector":".pass-rich-transparent"}]} {"args":["\n\n\n \n Repeated Container Text Fixture\n \n\n\n\n \n\n \n
\n

Museumplein departure

\n
Suspended
\n
Suspended
\n

This service is Suspended until further notice.

\n
\n\n \n
\n

Evening show

\n
Unavailable
\n
Unavailable
\n
Unavailable
\n

Currently Unavailable at this venue.

\n
\n\n \n\n \n
\n

Deploy history

\n \n \n \n \n
build 12Rolled back
build 13Rolled back
build 14Rolled back
\n
\n\n \n
\n

Departures

\n
On schedule
\n
On schedule
\n
On schedule
\n
\n\n \n
\n

Sections

\n \n
\n\n \n
\n

Toggles

\n
Off
\n
Off
\n
Off
\n
\n\n \n
\n

Scores

\n
2026
\n
2026
\n
2026
\n
\n\n \n
Standby mode
\n
Standby mode
\n
Standby mode
\n\n \n
\n

Availability

\n
\n
Open slot
\n
Open slot
\n
Open slot
\n
\n
\n\n \n
\n

Corner case

\n
Rescheduled
\n
Rescheduled
\n
\n\n\n\n",{"styleText":"\n body {\n font-family: Georgia, serif;\n font-size: 16px;\n margin: 0;\n padding: 40px;\n background: #f5f5f4;\n color: #222222;\n }\n .card {\n background: #ffffff;\n border: 1px solid #d6d3d1;\n border-radius: 10px;\n padding: 20px;\n width: 360px;\n margin-bottom: 32px;\n }\n .shadow-card {\n background: #ffffff;\n border-radius: 10px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\n padding: 20px;\n width: 360px;\n margin-bottom: 32px;\n }\n h2 { font-size: 22px; margin: 0 0 10px; }\n .big-word { font-size: 30px; font-weight: 700; color: #b91c1c; }\n .tag { font-size: 12px; text-transform: uppercase; color: #b91c1c; }\n .row { padding: 6px 0; border-bottom: 1px solid #eeeeee; }\n .status { font-size: 13px; color: #57534e; }\n td, th { padding: 6px 10px; font-size: 14px; }\n ","classText":"card\nheadline\nbig-word\nmeta\ntag\nnote\nshadow-card\nbanner\nbig-word\ndetail\ntag\nfooter\nstatus\naside\ncard\ncard\nrow\nstatus\nrow\nstatus\nrow\nstatus\ncard\na\nb\nc\ncard\none\ntwo\nthree\ncard\none\ntwo\nthree\ncard\ntag\ncard\ntag\ncard\ntag\ncard\ncell-a\ncell-b\ncell-c\ncard\nheadline\nbig-word\nmeta\ntag"}],"result":[]} {"args":["\n\n\n \n Working reveal-on-scroll fixture (browser-only pass case)\n \n\n\n
\n

Visible hero headline stays readable

\n

Identical markup to the broken fixture, but the script parses and runs, so every\n reveal section becomes visible once the detector's reveal sweep scrolls it into view.\n Nothing on this page may produce a script-error or content-hidden finding.

\n\n \n \n \n
Decorative aria-hidden copy that also stays out of the denominator.
\n \n\n
\n

First revealed section

\n

This block starts at opacity zero, exactly like a broken page would, but its\n IntersectionObserver is alive. During the sweep it gains the in-view class and\n transitions to full opacity, so the post-sweep measurement sees it as visible.

\n
\n
\n

Second revealed section

\n

More reveal-on-scroll copy that carries a meaningful share of the page's\n character count. If the sweep or the exclusion rules regress, this fixture is the\n page that starts producing a false content-hidden-at-rest finding.

\n
\n
\n

Third revealed section

\n

The smooth scroll-behavior on the root element is deliberate: the sweep must\n use instant scrolling or it never actually reaches these sections before it\n measures, which was the first false-positive mode found while calibrating.

\n
\n
\n\n \n\n\n",{"styleText":"\n html { scroll-behavior: smooth; }\n body { font-family: system-ui, sans-serif; margin: 0; color: #1a1a1a; background: #fff; }\n main { max-width: 640px; margin: 0 auto; padding: 32px 24px; }\n section { margin: 0 0 480px; }\n .reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.4s ease-out, transform 0.4s ease-out; }\n .reveal.in-view { opacity: 1; transform: none; }\n .menu { display: none; }\n ","classText":"menu\nreveal\nreveal\nreveal"}],"result":[]} -{"args":["\n\n\n\nFixture: data-impeccable-ignore scoped waivers\n\n\n\n \n
The control case has a 6px side-tab accent border and no waiver, so the side-tab rule must flag it.
\n\n \n
\n
The waiver names pulsing-dot, not side-tab, so this 8px case must still flag.
\n
\n\n \n
\n
A waiver on a preceding sibling is not an ancestor; this 12px case must still flag.
\n\n \n
\n
\"side-tabs\" is not a rule id; the 5px case must still flag.
\n
\n\n \n
\n
Inside a container waived for exactly side-tab; must not flag.
\n
\n\n \n
\n
\n
Two levels below the waiving container; the ancestor walk must still find it.
\n
\n
\n\n \n
\n
Inside a star-waived container; must not flag.
\n
\n\n \n
\n
side-tab appears in the comma list; must not flag.
\n
\n\n \n
The waiver sits on the element itself; must not flag.
\n\n \n
\n
One voice.Another voice.One voice.Another voice.
\n
\n\n\n",{"styleText":"\n body { margin: 0; padding: 40px; background: #faf8f4; font-family: Arial, sans-serif; color: #262421; }\n /* Every case carries a UNIQUE border-left width so each finding's snippet\n (`border-left: Npx`) attributes to exactly one case. Flag widths: 5, 6,\n 8, 12. Pass widths: 4, 7, 9, 10, 11. */\n .tabbed {\n width: 420px;\n padding: 16px 20px;\n margin: 0 0 24px;\n background: #ffffff;\n border: 1px solid #ddd8d0;\n border-left: 6px solid #b8422e;\n }\n .w4 { border-left-width: 4px; }\n .w5 { border-left-width: 5px; }\n .w7 { border-left-width: 7px; }\n .w8 { border-left-width: 8px; }\n .w9 { border-left-width: 9px; }\n .w10 { border-left-width: 10px; }\n .w11 { border-left-width: 11px; }\n .w12 { border-left-width: 12px; }\n /* Marquee specimen: keyframes + an infinite loop track. The section that\n hosts it carries a marquee waiver; the CSS-scan finding must resolve the\n selector to the live element and honor the ancestor attribute. */\n @keyframes ticker-loop { from { transform: translateX(0); } to { transform: translateX(-50%); } }\n .quote-track { display: flex; width: max-content; animation: ticker-loop 80s linear infinite; }\n .quote-track span { padding: 8px 16px; }\n /* Dead grid CSS: this two-axis hairline grid selector matches nothing on\n this page, so the browser pass must drop the codex-grid finding — the\n pattern never renders here. */\n .never-rendered-grid {\n background:\n linear-gradient(90deg, rgba(200,180,120,0.08) 1px, transparent 1px),\n linear-gradient(180deg, rgba(200,180,120,0.08) 1px, transparent 1px);\n background-size: 24px 24px;\n }\n /* Overshoot bezier inside a keyframe STEP: enclosingCssSelector must refuse\n `to` as a selector (it would match nothing and wrongly drop the finding),\n so this bounce-easing finding stays page-level and is retained. */\n @keyframes springy {\n from { transform: none; }\n to { transform: translateY(-4px); animation-timing-function: cubic-bezier(0.3, 1.8, 0.6, 1); }\n }\n","classText":"tabbed control-flags\ntabbed w8 flags-other-rule-waived\ntabbed w12 flags-sibling-waiver\ntabbed w5 flags-misspelled-rule\ntabbed w7 pass-exact-rule\ntabbed w9 pass-nested-depth\ntabbed w10 pass-star\ntabbed w11 pass-rule-list\ntabbed w4 pass-self-waiver\nquote-track"}],"result":[{"id":"bounce-easing","snippet":"cubic-bezier(0.3, 1.8, 0.6, 1)","selector":{"$undef":true}},{"id":"marquee","snippet":".quote-track — infinite horizontal loop animation \"ticker-loop\"","selector":".quote-track"},{"id":"codex-grid-background","snippet":"two-axis grid-line gradient background","selector":"/* Dead grid CSS: this two-axis hairline grid selector matches nothing on this page, so the browser pass must drop the codex-grid finding — the pattern never renders here. */ .never-rendered-grid"}]} +{"args":["\n\n\n\nFixture: data-impeccable-ignore scoped waivers\n\n\n\n \n
The control case has a 6px side-tab accent border and no waiver, so the side-tab rule must flag it.
\n\n \n
\n
The waiver names pulsing-dot, not side-tab, so this 8px case must still flag.
\n
\n\n \n
\n
A waiver on a preceding sibling is not an ancestor; this 12px case must still flag.
\n\n \n
\n
\"side-tabs\" is not a rule id; the 5px case must still flag.
\n
\n\n \n
\n
Inside a container waived for exactly side-tab; must not flag.
\n
\n\n \n
\n
\n
Two levels below the waiving container; the ancestor walk must still find it.
\n
\n
\n\n \n
\n
Inside a star-waived container; must not flag.
\n
\n\n \n
\n
side-tab appears in the comma list; must not flag.
\n
\n\n \n
The waiver sits on the element itself; must not flag.
\n\n \n
\n
One voice.Another voice.One voice.Another voice.
\n
\n\n\n",{"styleText":"\n body { margin: 0; padding: 40px; background: #faf8f4; font-family: Arial, sans-serif; color: #262421; }\n /* Every case carries a UNIQUE border-left width so each finding's snippet\n (`border-left: Npx`) attributes to exactly one case. Flag widths: 5, 6,\n 8, 12. Pass widths: 4, 7, 9, 10, 11. */\n .tabbed {\n width: 420px;\n padding: 16px 20px;\n margin: 0 0 24px;\n background: #ffffff;\n border: 1px solid #ddd8d0;\n border-left: 6px solid #b8422e;\n }\n .w4 { border-left-width: 4px; }\n .w5 { border-left-width: 5px; }\n .w7 { border-left-width: 7px; }\n .w8 { border-left-width: 8px; }\n .w9 { border-left-width: 9px; }\n .w10 { border-left-width: 10px; }\n .w11 { border-left-width: 11px; }\n .w12 { border-left-width: 12px; }\n /* Marquee specimen: keyframes + an infinite loop track. The section that\n hosts it carries a marquee waiver; the CSS-scan finding must resolve the\n selector to the live element and honor the ancestor attribute. */\n @keyframes ticker-loop { from { transform: translateX(0); } to { transform: translateX(-50%); } }\n .quote-track { display: flex; width: max-content; animation: ticker-loop 80s linear infinite; }\n .quote-track span { padding: 8px 16px; }\n /* Dead grid CSS: this two-axis hairline grid selector matches nothing on\n this page, so the browser pass must drop the codex-grid finding — the\n pattern never renders here. */\n .never-rendered-grid {\n background:\n linear-gradient(90deg, rgba(200,180,120,0.08) 1px, transparent 1px),\n linear-gradient(180deg, rgba(200,180,120,0.08) 1px, transparent 1px);\n background-size: 24px 24px;\n }\n /* Overshoot bezier inside a keyframe STEP: enclosingCssSelector must refuse\n `to` as a selector (it would match nothing and wrongly drop the finding),\n so this bounce-easing finding stays page-level and is retained. */\n @keyframes springy {\n from { transform: none; }\n to { transform: translateY(-4px); animation-timing-function: cubic-bezier(0.3, 1.8, 0.6, 1); }\n }\n","classText":"tabbed control-flags\ntabbed w8 flags-other-rule-waived\ntabbed w12 flags-sibling-waiver\ntabbed w5 flags-misspelled-rule\ntabbed w7 pass-exact-rule\ntabbed w9 pass-nested-depth\ntabbed w10 pass-star\ntabbed w11 pass-rule-list\ntabbed w4 pass-self-waiver\nquote-track"}],"result":[{"id":"bounce-easing","snippet":"cubic-bezier(0.3, 1.8, 0.6, 1)"},{"id":"marquee","snippet":".quote-track — infinite horizontal loop animation \"ticker-loop\"","selector":".quote-track"},{"id":"codex-grid-background","snippet":"two-axis grid-line gradient background","selector":".never-rendered-grid"}]} {"args":["\n\n\n \n Script error + content hidden fixture (browser-only)\n \n\n\n
\n

Visible hero headline stays readable

\n

The opening paragraph renders normally, exactly like the real broken sample: the\n first viewport looks fine while everything below it never appears.

\n\n
\n

First hidden section

\n

This block waits for an IntersectionObserver that will never construct, because\n the single script tag below fails to parse. Its text ships in the document but the\n reveal class never lands, so the reader scrolls through blank space.

\n
\n
\n

Second hidden section

\n

More shipped-but-invisible copy. Together the hidden sections carry well over\n thirty percent of the character count of the page, which is the failed-reveal\n signature this fixture exists to reproduce for the detector tests.

\n
\n
\n

Third hidden section

\n

A final block of body copy that stays at opacity zero forever. A healthy page\n with this exact markup reveals every one of these sections during the detector's\n reveal sweep; this one cannot, because its JavaScript died at parse time.

\n
\n
\n\n \n\n\n",{"styleText":"\n html { scroll-behavior: smooth; }\n body { font-family: system-ui, sans-serif; margin: 0; color: #1a1a1a; background: #fff; }\n main { max-width: 640px; margin: 0 auto; padding: 32px 24px; }\n section { margin: 0 0 480px; }\n .reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.4s ease-out, transform 0.4s ease-out; }\n .reveal.in-view { opacity: 1; transform: none; }\n ","classText":"reveal\nreveal\nreveal"}],"result":[]} {"args":["\n\n\n\n\nShadowed form.id regression fixture\n\n\n\n
\n

Impeccable Test Product

\n

$49.00

\n\n \n
\n \n \n \n \n \n \n \n
\n
\n\n\n\n",{"styleText":"\n body { font-family: system-ui, sans-serif; background: #ffffff; color: #1a1a1a; margin: 0; padding: 24px; }\n .product { max-width: 640px; margin: 0 auto; }\n h1 { font-size: 28px; margin: 0 0 12px; }\n .price { font-size: 20px; font-weight: 600; }\n form { margin-top: 16px; }\n .add-to-cart { background: #1a1a1a; color: #ffffff; border: 0; padding: 12px 24px; border-radius: 6px; font-size: 16px; cursor: pointer; }\n label { display: block; margin: 8px 0 4px; font-size: 14px; }\n select, input[type=\"number\"] { padding: 8px; font-size: 14px; }\n","classText":"product\nprice\nadd-to-cart"}],"result":[]} {"args":["\n\n\n\nShape-assembled illustration fixture\n\n\n
\n \n \n \n \n \n \n \n \n \n \n \n Acme\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n Jan\n Mar\n May\n Jul\n \n\n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n
\n\n\n",{"styleText":"","classText":"mascot"}],"result":[{"id":"shape-assembled-illustration","snippet":"inline scene: 12 primitive shapes, ~640x480px, 6 fill colors"}]} @@ -64,8 +64,8 @@ {"args":["\n\n\n \n \n Clean Patterns — Should NOT Flag\n \n\n\n

Clean Patterns: Should Pass

\n

None of these should be flagged. They're all intentional, well-established web patterns.

\n\n \n

Clean Cards

\n
\n
\n

Full border card

\n

Subtle 1px border all around. Clean and intentional.

\n
\n\n
\n

Top border, no radius

\n

A hairline top rule without rounded corners is a clean section divider.

\n
\n\n
\n

Bottom border, no radius

\n

Bottom accent without rounded corners is also clean.

\n
\n\n
\n New\n

No border at all

\n

Just a shadow. Simple and effective.

\n
\n
\n\n \n

Below Threshold (Thin, No Radius)

\n
\n
\n

border-left: 1px solid, no radius — not flagged

\n
\n
\n

border-right: 2px solid, no radius — not flagged

\n
\n
\n

1px inline border-left, no radius — not flagged

\n
\n
\n \n

Dark Mode (Clean)

\n
\n
\n

Dark card, full border

\n

Uniform 1px border all around. Clean.

\n
\n
\n

Dark section, bottom border, no radius

\n

Bottom accent without radius is fine.

\n
\n
\n

Dark card, no border

\n

Shadow only. Clean.

\n
\n
\n\n\n\n",{"styleText":"\n body { font-family: system-ui, sans-serif; background: #f9fafb; padding: 2rem; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; }\n h2 { font-size: 1.125rem; margin: 2.5rem 0 0.75rem; color: #6b7280; border-bottom: 1px solid #e5e7eb; padding-bottom: 0.5rem; }\n p.intro { color: #6b7280; margin-bottom: 2rem; max-width: 36rem; }\n .section { max-width: 28rem; }\n .card-rounded { background: white; padding: 1.5rem; border-radius: 0.5rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); max-width: 28rem; margin-bottom: 1rem; }\n .card-rounded h3 { font-weight: 600; color: #111827; }\n .card-rounded p { font-size: 0.875rem; color: #6b7280; margin-top: 0.25rem; }\n .card-flat { background: white; padding: 1rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); max-width: 28rem; margin-bottom: 1rem; }\n .badge { display: inline-block; font-size: 0.75rem; padding: 0.125rem 0.5rem; border-radius: 9999px; background: #dbeafe; color: #1d4ed8; }\n\n /* Below-threshold side borders without radius */\n .thin-left { border-left: 1px solid #3b82f6; }\n .thin-right { border-right: 2px solid #8b5cf6; }\n \nstyle=\"border: 1px solid #e5e7eb;\"\nstyle=\"max-width: 28rem; margin-bottom: 1rem; padding: 1.5rem; background: white; border-top: 1px solid #3b82f6; box-shadow: 0 1px 3px rgba(0,0,0,0.1);\"\nstyle=\"font-weight: 600; color: #111827;\"\nstyle=\"font-size: 0.875rem; color: #6b7280; margin-top: 0.25rem;\"\nstyle=\"max-width: 28rem; margin-bottom: 1rem; padding: 1.5rem; background: white; border-bottom: 2px solid #10b981; box-shadow: 0 1px 3px rgba(0,0,0,0.1);\"\nstyle=\"font-weight: 600; color: #111827;\"\nstyle=\"font-size: 0.875rem; color: #6b7280; margin-top: 0.25rem;\"\nstyle=\"border-left: 1px solid #10b981;\"\nstyle=\"background: #1f2937; padding: 1.5rem; border-radius: 0.5rem; border: 1px solid #374151; max-width: 28rem; margin-bottom: 1rem;\"\nstyle=\"font-weight: 600; color: white;\"\nstyle=\"font-size: 0.875rem; color: #9ca3af; margin-top: 0.25rem;\"\nstyle=\"background: #111827; padding: 1.5rem; max-width: 28rem; margin-bottom: 1rem; border-bottom: 2px solid #6366f1;\"\nstyle=\"font-weight: 600; color: white;\"\nstyle=\"font-size: 0.875rem; color: #9ca3af; margin-top: 0.25rem;\"\nstyle=\"background: #1e293b; padding: 1.5rem; border-radius: 0.5rem; max-width: 28rem; margin-bottom: 1rem; box-shadow: 0 4px 6px rgba(0,0,0,0.3);\"\nstyle=\"font-weight: 600; color: white;\"\nstyle=\"font-size: 0.875rem; color: #94a3b8; margin-top: 0.25rem;\"","classText":"intro\nsection\ncard-rounded\ncard-rounded\nbadge\nsection\ncard-flat thin-left\ncard-flat thin-right\ncard-flat\nsection"}],"result":[]} {"args":["\n\n\n \n \n Border Anti-Patterns — Should Flag vs Should Pass\n \n\n\n

Border side-tab detector cases

\n

A paired fixture for colored side borders and rounded accent borders. The left column should produce border findings; the right column should stay clean.

\n\n
\n
\n

Should flag

\n\n
\n

Rounded card with colored left border

\n

Classic side tab: border-left is thick, colored, and paired with rounded corners.

\n
\n\n
\n

Rounded card with colored right border

\n

The right-side version is the same visual trope mirrored.

\n
\n\n
\n

Thick colored side border without radius

\n

A thick chromatic side stripe still reads as a tab even without rounded corners.

\n
\n\n
\n

Rounded card with top accent border

\n

A heavy top accent on a rounded card is the horizontal variant of the same pattern.

\n
\n\n
\n

Rounded card with bottom accent border

\n

The bottom accent is also a decorative stripe on a card surface.

\n
\n\n
\n

Dark card with bright side stripe

\n

Dark surfaces can hide the cliche, but the thick colored side stripe remains.

\n
\n
\n\n
\n

Should pass

\n\n
\n

Uniform full border

\n

A quiet all-around border frames the card instead of creating a side tab.

\n
\n\n
\n

Neutral structural side rule

\n

A gray structural rule can be a legitimate divider when it is not chromatic emphasis.

\n
\n\n
\n

Thin colored side rule

\n

A 1px colored rule is below the decorative side-tab threshold.

\n
\n\n
\n

Status toast with severity accent

\n

A live status region carries a colored side bar as a severity accent, not a decorative side tab.

\n
\n\n
\n

Square top border

\n

A chromatic top stripe on a card is the horizontal variant of the side tab.

\n
\n\n
\n

Square bottom border

\n

A chromatic bottom stripe on a badge or card is the same decorative tell.

\n
\n\n
\n
\n

Selected tab underline

\n

An active-state underline inside a tablist is an affordance, not a stripe.

\n
\n
\n\n
\n

Thick color band

\n

A band well past stripe thickness is a compositional block, not an accent stripe.

\n
\n\n
\n

Dark card with uniform border

\n

The dark surface has a full neutral outline, not a chromatic side stripe.

\n
\n
\n
\n\n \n\n\n",{"styleText":"\n body {\n margin: 0;\n padding: 24px;\n background: #f8fafc;\n color: #111827;\n font: 14px/1.5 system-ui, sans-serif;\n }\n\n h1 {\n max-width: 1180px;\n margin: 0 auto 8px;\n font-size: 34px;\n line-height: 1.05;\n font-weight: 720;\n }\n\n .intro {\n max-width: 1180px;\n margin: 0 auto 24px;\n color: #4b5563;\n }\n\n .grid {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n gap: 32px;\n max-width: 1180px;\n margin: 0 auto;\n }\n\n .col h2 {\n margin: 0 0 14px;\n color: #475569;\n font-size: 13px;\n font-weight: 760;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n }\n\n .case {\n margin: 0 0 14px;\n padding: 16px;\n background: #fdfdfd;\n box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);\n }\n\n .case h3 {\n margin: 0 0 4px;\n font-size: 15px;\n line-height: 1.25;\n }\n\n .case p {\n margin: 0;\n color: #475569;\n }\n\n .flag-left {\n border-left: 4px solid #2563eb;\n border-radius: 10px;\n }\n\n .flag-right {\n border-right: 5px solid #dc2626;\n border-radius: 10px;\n }\n\n .flag-left-plain {\n border-left: 4px solid #0f766e;\n }\n\n .flag-top {\n border-top: 4px solid #7c3aed;\n border-radius: 10px;\n }\n\n .flag-bottom {\n border-bottom: 3px solid #ea580c;\n border-radius: 10px;\n }\n\n .flag-dark {\n background: #141820;\n color: #f4f7fb;\n border-left: 4px solid #38bdf8;\n border-radius: 10px;\n }\n\n .flag-dark p {\n color: #cbd5e1;\n }\n\n .pass-full-border {\n border: 1px solid #cbd5e1;\n border-radius: 10px;\n }\n\n .pass-neutral-side {\n border-left: 4px solid #d1d5db;\n border-radius: 10px;\n }\n\n .pass-thin-side {\n border-left: 1px solid #2563eb;\n border-radius: 10px;\n }\n\n .pass-status-alert {\n border-left: 4px solid #2563eb;\n }\n\n .flag-square-top {\n border-top: 4px solid #7c3aed;\n border-radius: 0;\n }\n\n .flag-square-bottom {\n border-bottom: 3px solid #ea580c;\n border-radius: 0;\n }\n\n .pass-tab-underline {\n border-bottom: 3px solid #2563eb;\n border-radius: 0;\n }\n\n .pass-thick-band {\n border-top: 16px solid #7c3aed;\n border-radius: 0;\n }\n\n .pass-dark-uniform {\n background: #161a22;\n color: #f4f7fb;\n border: 1px solid #334155;\n border-radius: 10px;\n }\n\n .pass-dark-uniform p {\n color: #cbd5e1;\n }\n ","classText":"intro\ngrid\ncol\ncase flag-left\ncase flag-right\ncase flag-left-plain\ncase flag-top\ncase flag-bottom\ncase flag-dark\ncol\ncase pass-full-border\ncase pass-neutral-side\ncase pass-thin-side\ncase pass-status-alert\ncase flag-square-top\ncase flag-square-bottom\ncase\ncase pass-tab-underline\ncase pass-thick-band\ncase pass-dark-uniform"}],"result":[]} {"args":["\n\n\n \n \n Anti-Patterns From Linked Stylesheet\n \n \n\n\n

Linked Stylesheet Anti-Patterns

\n

\n These elements get their anti-pattern styles from an external CSS file.\n Regex-only scanning misses these — only computed style analysis catches them.\n

\n\n
\n
\n

Should flag

\n
\n
\n

External side-tab class

\n

border-left plus border-radius from a linked stylesheet.

\n
\n\n
\n

External top accent class

\n

border-top plus border-radius from a linked stylesheet.

\n
\n
\n
\n\n
\n

Should pass

\n
\n
\n

External clean card

\n

Uniform 1px border from the linked stylesheet.

\n
\n\n
\n

External neutral side rule

\n

Thick side border, but the color is structural gray.

\n
\n\n
\n

External square top rule

\n

Heavy top border with no rounded card corners.

\n
\n
\n
\n
\n\n\n\n",{"styleText":"\n body {\n margin: 0;\n padding: 24px;\n background: #f9fafb;\n color: #111827;\n font: 14px/1.5 system-ui, sans-serif;\n }\n\n h1 {\n max-width: 1080px;\n margin: 0 auto 8px;\n font-size: 34px;\n line-height: 1.05;\n }\n\n p.intro {\n max-width: 1080px;\n margin: 0 auto 24px;\n color: #4b5563;\n }\n\n .grid {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n gap: 32px;\n max-width: 1080px;\n margin: 0 auto;\n }\n\n .col h2 {\n margin: 0 0 14px;\n color: #475569;\n font-size: 13px;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n }\n\n .cards {\n display: grid;\n gap: 14px;\n }\n\n h3 {\n margin: 0 0 4px;\n font-size: 15px;\n line-height: 1.25;\n }\n\n .cards p {\n margin: 0;\n color: #4b5563;\n }\n \n/* External stylesheet that applies anti-pattern styles */\n\n/* Side-tab via external class */\n.external-side-tab {\n background: white;\n padding: 1rem;\n border-radius: 12px;\n border-left: 4px solid #3b82f6;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n}\n\n/* Top border accent via external class */\n.external-top-accent {\n background: white;\n padding: 1rem;\n border-radius: 12px;\n border-top: 3px solid #8b5cf6;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n}\n\n/* Overused font from external stylesheet */\n.external-inter {\n font-family: 'Inter', sans-serif;\n}\n\n/* Clean card — should NOT flag */\n.external-clean {\n background: white;\n padding: 1rem;\n border-radius: 12px;\n border: 1px solid #e5e7eb;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n}\n\n/* Neutral side rule — should NOT flag */\n.external-neutral-side {\n background: white;\n padding: 1rem;\n border-radius: 12px;\n border-left: 4px solid #d1d5db;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n}\n\n/* Top rule without rounded card corners — should NOT flag */\n.external-square-top {\n background: white;\n padding: 1rem;\n border-radius: 0;\n border-top: 4px solid #8b5cf6;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n}\n","classText":"intro\ngrid\ncol\ncards\nexternal-side-tab\nexternal-top-accent\ncol\ncards\nexternal-clean\nexternal-neutral-side\nexternal-square-top"}],"result":[]} -{"args":["\n\n\n \n \n Color Anti-Patterns — Should Flag vs Should Pass\n \n\n\n
\n\n \n
\n

Should flag

\n\n

Pure black surfaces

\n
\n

Pure #000 background

\n
\n\n

Gray on color

\n
\n

Gray text on blue background

\n
\n
\n

Gray text on green background

\n
\n\n

Low contrast

\n
\n

Light gray text on white — very low contrast

\n
\n
\n

Dark gray text on near-black — low contrast

\n
\n \n
\n

Welcome to Our Platform

\n

The best solution for modern teams and businesses

\n
\n\n

Gradient text

\n

\n Gradient Heading\n

\n\n

AI color palette

\n

Purple heading text

\n\n

Styled <a> and <button> with low contrast

\n \n Get started\n \n \n\n

Text-bearing chip with low contrast

\n \n SEV-2\n\n

Tailwind color anti-patterns

\n
\n

bg-black — pure black bg

\n
\n
\n

text-gray-400 on bg-blue-500 — gray on color

\n
\n

text-purple-500 heading

\n
\n

Purple-to-indigo gradient

\n
\n\n

currentcolor surface via var() token

\n \n
\n

Faint warm gray on a bone currentcolor surface

\n
\n
\n\n \n
\n

Should pass

\n\n

Tinted neutrals

\n
\n

Near-black bg, near-white text — tinted, not pure

\n
\n
\n

Near-white bg, near-black text — good contrast, tinted

\n
\n\n

Pure white surface is acceptable

\n
\n

Pure #fff background with dark text — acceptable contrast

\n
\n\n

Good contrast

\n
\n

Near-white text on dark blue — high contrast, not pure white

\n
\n
\n

Dark green text on green bg — same hue family

\n
\n\n

Distinctive accents (not AI purple)

\n

Red heading — not AI purple

\n

Amber heading — distinctive

\n\n

Background-image url() ancestor (not low contrast)

\n \n
\n

White text on image background — should not flag low-contrast

\n
\n\n

Tailwind opacity-modified bg-black (not pure black)

\n \n
\n

bg-black/3 — 3% opacity, not pure black

\n
\n
\n

hover:bg-black/5 — hover state, not pure black

\n
\n
\n

bg-black/50 — 50% opacity, not pure black

\n
\n\n

Inline <a> without own background (must remain skipped)

\n \n

Read more about this here if you want to learn more about the topic.

\n\n

Styled <a> with good contrast (must not flag)

\n \n High contrast pill\n\n

Chip with good contrast (must not flag)

\n HEALTHY\n\n

Sub-9px decorative chip (below the font floor, must not flag)

\n tick\n\n

background: none resets an earlier background-color

\n \n
\n
light text over the dark panel, not the light code surface
\n
\n\n

Gradient-clipped text (issue #409 Case A — must not flag contrast)

\n \n

Gradient Clipped Heading Text

\n\n

Faint accent-glow gradient (issue #409 Case B — must not flag contrast)

\n \n
\n
\n

Light body copy on a faint accent glow that composites to near-black

\n

Muted secondary line on the same faint glow area here

\n
\n
\n\n

color-mix gradient stop: nested ingredient is not a surface

\n
\n
\n

Light copy on a faint mixed wash over a dark ground stays readable

\n
\n
\n\n

currentcolor surface with good contrast

\n
\n

Dark ink text on a bone currentcolor surface

\n
\n\n

currentcolor surface with unresolvable token (must abstain)

\n \n
\n

Light text on an unknowable currentcolor surface

\n
\n\n

Emoji on light backgrounds

\n \n
\n

⚠️ 🚨 ✨ 🎨

\n
\n
\n

⚠️ 🚨 ✨ 🎨

\n
\n
\n
\n \n\n\n",{"styleText":"\n body { font-family: system-ui, sans-serif; background: #fafafa; padding: 24px; margin: 0; color: #1a1a1a; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1200px; margin: 0 auto; }\n .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .col h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; margin: 24px 0 8px; color: #64748b; }\n .card { padding: 14px 16px; border-radius: 10px; margin-bottom: 10px; }\n /* Styled button color cases (declared via stylesheet so jsdom resolves them\n reliably — inline color doesn't always win over user-agent rules in jsdom\n for and \n\n

Text-bearing chip with low contrast

\n \n SEV-2\n\n

Tailwind color anti-patterns

\n
\n

bg-black — pure black bg

\n
\n
\n

text-gray-400 on bg-blue-500 — gray on color

\n
\n

text-purple-500 heading

\n
\n

Purple-to-indigo gradient

\n
\n\n

currentcolor surface via var() token

\n \n
\n

Faint warm gray on a bone currentcolor surface

\n
\n \n\n \n
\n

Should pass

\n\n

Tinted neutrals

\n
\n

Near-black bg, near-white text — tinted, not pure

\n
\n
\n

Near-white bg, near-black text — good contrast, tinted

\n
\n\n

Pure white surface is acceptable

\n
\n

Pure #fff background with dark text — acceptable contrast

\n
\n\n

Good contrast

\n
\n

Near-white text on dark blue — high contrast, not pure white

\n
\n
\n

Dark green text on green bg — same hue family

\n
\n\n

Distinctive accents (not AI purple)

\n

Red heading — not AI purple

\n

Amber heading — distinctive

\n\n

Background-image url() ancestor (not low contrast)

\n \n
\n

White text on image background — should not flag low-contrast

\n
\n\n

Tailwind opacity-modified bg-black (not pure black)

\n \n
\n

bg-black/3 — 3% opacity, not pure black

\n
\n
\n

hover:bg-black/5 — hover state, not pure black

\n
\n
\n

bg-black/50 — 50% opacity, not pure black

\n
\n\n

Inline <a> without own background (must remain skipped)

\n \n

Read more about this here if you want to learn more about the topic.

\n\n

Styled <a> with good contrast (must not flag)

\n \n High contrast pill\n\n

Chip with good contrast (must not flag)

\n HEALTHY\n\n

Sub-9px decorative chip (below the font floor, must not flag)

\n tick\n\n

background: none resets an earlier background-color

\n \n
\n
light text over the dark panel, not the light code surface
\n
\n\n

Gradient-clipped text (issue #409 Case A — must not flag contrast)

\n \n

Gradient Clipped Heading Text

\n\n

Faint accent-glow gradient (issue #409 Case B — must not flag contrast)

\n \n
\n
\n

Light body copy on a faint accent glow that composites to near-black

\n

Muted secondary line on the same faint glow area here

\n
\n
\n\n

color-mix gradient stop: nested ingredient is not a surface

\n
\n
\n

Light copy on a faint mixed wash over a dark ground stays readable

\n
\n
\n\n

currentcolor surface with good contrast

\n
\n

Dark ink text on a bone currentcolor surface

\n
\n\n

currentcolor surface with unresolvable token (must abstain)

\n \n
\n

Light text on an unknowable currentcolor surface

\n
\n\n

Emoji on light backgrounds

\n \n
\n

⚠️ 🚨 ✨ 🎨

\n
\n
\n

⚠️ 🚨 ✨ 🎨

\n
\n
\n \n \n\n\n",{"styleText":"\n body { font-family: system-ui, sans-serif; background: #fafafa; padding: 24px; margin: 0; color: #1a1a1a; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1200px; margin: 0 auto; }\n .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .col h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; margin: 24px 0 8px; color: #64748b; }\n .card { padding: 14px 16px; border-radius: 10px; margin-bottom: 10px; }\n /* Styled button color cases (declared via stylesheet so jsdom resolves them\n reliably — inline color doesn't always win over user-agent rules in jsdom\n for and \n \n \n \n \n\n \n

Data Table

\n
\n \n \n \n \n \n \n \n \n \n \n \n
NameRevenue
Acme Corp$1.2M
Globex$850K
\n
\n\n \n

Alert Banner

\n
\n
\n Warning: Your trial expires in 3 days. Upgrade now\n
\n
\n\n\n\n",{"styleText":"\n body { font-family: system-ui, sans-serif; background: #f9fafb; padding: 2rem; color: #111827; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; }\n h2 { font-size: 1.125rem; margin: 2rem 0 0.75rem; color: #6b7280; }\n .demo { max-width: 36rem; margin-bottom: 1.5rem; }\n \nstyle=\"color: #6b7280; margin-bottom: 2rem;\"\nstyle=\"border-left: 4px solid #d1d5db; padding-left: 1rem; margin: 0; color: #4b5563; font-style: italic;\"\nstyle=\"width: 200px; background: white; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden;\"\nstyle=\"display: block; padding: 0.75rem 1rem; color: #6b7280; text-decoration: none; border-left: 3px solid transparent;\"\nstyle=\"display: block; padding: 0.75rem 1rem; color: #1d4ed8; text-decoration: none; border-left: 3px solid #3b82f6; background: #eff6ff; font-weight: 500;\"\nstyle=\"display: block; padding: 0.75rem 1rem; color: #6b7280; text-decoration: none; border-left: 3px solid transparent;\"\nstyle=\"margin-bottom: 1rem;\"\nstyle=\"display: block; font-size: 0.875rem; font-weight: 500; margin-bottom: 0.25rem;\"\nstyle=\"width: 100%; padding: 0.5rem 0.75rem; border: 1px solid #fca5a5; border-left: 3px solid #b91c1c; border-radius: 6px; outline: none; font-size: 0.875rem;\"\nstyle=\"color: #b91c1c; font-size: 0.75rem; margin-top: 0.25rem;\"\nstyle=\"border-left: 3px solid #e5e7eb; padding-left: 1.5rem; margin-left: 0.75rem;\"\nstyle=\"position: relative; padding-bottom: 1.5rem;\"\nstyle=\"position: absolute; left: -2.05rem; top: 0.125rem; width: 10px; height: 10px; border-radius: 50%; background: #3b82f6; border: 2px solid white;\"\nstyle=\"font-weight: 500; margin: 0;\"\nstyle=\"font-size: 0.75rem; color: #6b7280; margin: 0.125rem 0 0;\"\nstyle=\"position: relative; padding-bottom: 1.5rem;\"\nstyle=\"position: absolute; left: -2.05rem; top: 0.125rem; width: 10px; height: 10px; border-radius: 50%; background: #3b82f6; border: 2px solid white;\"\nstyle=\"font-weight: 500; margin: 0;\"\nstyle=\"font-size: 0.75rem; color: #6b7280; margin: 0.125rem 0 0;\"\nstyle=\"position: relative;\"\nstyle=\"position: absolute; left: -2.05rem; top: 0.125rem; width: 10px; height: 10px; border-radius: 50%; background: #d1d5db; border: 2px solid white;\"\nstyle=\"font-weight: 500; margin: 0; color: #4b5563;\"\nstyle=\"font-size: 0.75rem; color: #6b7280; margin: 0.125rem 0 0;\"\nstyle=\"background: #1e293b; color: #e2e8f0; padding: 1rem; border-radius: 8px; font-size: 0.8125rem; overflow-x: auto; margin: 0;\"\nstyle=\"display: block; border-left: 3px solid #ef4444; padding-left: 0.75rem; background: rgba(239,68,68,0.1);\"\nstyle=\"display: block; border-left: 3px solid #22c55e; padding-left: 0.75rem; background: rgba(34,197,94,0.1);\"\nstyle=\"display: block; padding-left: calc(3px + 0.75rem);\"\nstyle=\"display: flex; border-bottom: 1px solid #e5e7eb;\"\nstyle=\"padding: 0.75rem 1.25rem; border: none; background: none; font-size: 0.875rem; color: #1d4ed8; border-bottom: 2px solid #3b82f6; font-weight: 500; cursor: pointer;\"\nstyle=\"padding: 0.75rem 1.25rem; border: none; background: none; font-size: 0.875rem; color: #6b7280; border-bottom: 2px solid transparent; cursor: pointer;\"\nstyle=\"padding: 0.75rem 1.25rem; border: none; background: none; font-size: 0.875rem; color: #6b7280; border-bottom: 2px solid transparent; cursor: pointer;\"\nstyle=\"width: 100%; border-collapse: collapse; font-size: 0.875rem;\"\nstyle=\"text-align: left; padding: 0.5rem; border-bottom: 2px solid #111827;\"\nstyle=\"text-align: right; padding: 0.5rem; border-bottom: 2px solid #111827;\"\nstyle=\"padding: 0.5rem; border-bottom: 1px solid #e5e7eb;\"\nstyle=\"text-align: right; padding: 0.5rem; border-bottom: 1px solid #e5e7eb;\"\nstyle=\"padding: 0.5rem; border-bottom: 1px solid #e5e7eb;\"\nstyle=\"text-align: right; padding: 0.5rem; border-bottom: 1px solid #e5e7eb;\"\nstyle=\"border: 1px solid #f59e0b; background: #fffbeb; padding: 0.75rem 1rem; font-size: 0.875rem; color: #92400e;\"\nstyle=\"color: #d97706;\"","classText":"demo\ndemo\ndemo\ndemo\ndemo\ndemo\ndemo\ndemo"}],"result":[]} {"args":["\n\n\n \n Side-Tab with Modern Color Formats (oklch/lab/lch/hsl/hwb)\n \n\n\n
\n
\n

Should flag

\n

oklch checklist

oklch border-left 3px + radius

\n

oklch medication card

neutral all + colored left 4px

\n

oklch alert

warm border-left 4px + radius

\n

oklab card

oklab border-left 4px + radius

\n

lch card

lch border-left 4px + radius

\n

lab card

lab border-left 4px + radius

\n \n \n

var() shorthand

border-left 5px + var(--brand)

\n

var() mixed

neutral all + colored var left

\n

var() right side

border-right 4px + var(--terracotta)

\n \n
\n
\n

Should pass

\n

oklch neutral

chroma 0 gray

\n

oklch near-neutral

chroma 0.01

\n

oklch all sides

uniform border

\n

oklch thin

1px too thin

\n

lab neutral

chroma 0

\n

lch neutral

chroma 0

\n
\n \n \n
\n \n
\n \n \n
\n \n

var() neutral

--line resolves to gray

\n

var() thin

1px too thin to qualify

\n

var() all sides

uniform, not a side-tab

\n

oklch neutral right divider

1px neutral context-bar hairline

\n
\n
\n \n\n\n",{"styleText":"\n /* Two-column fixture: left col = should-flag, right col = should-pass.\n The side-tab snippet doesn't embed identifying text, so the test\n asserts finding counts against the structural ids (#flag-N / #pass-N)\n by reading the element via data attributes in the check path. Since\n that isn't available to the Node fixture runner, we instead place a\n unique number of FLAG elements (each a distinct side-tab) and verify\n the side-tab count. */\n\n /* CSS custom properties — variables used by the var()-case fixtures.\n jsdom's CSSOM drops any border shorthand containing var(), which used\n to make every side-tab built with CSS variables invisible to the\n detector. These cases regression-test the fallback pass that parses\n border shorthands directly off the rule (not the computed style). */\n :root {\n --brand: #87a8ff;\n --warn: #8a6a2f;\n --terracotta: #aa674d;\n --line: #e5e7eb; /* neutral gray — must NOT trigger */\n --rule: #f3f4f6; /* near-white — must NOT trigger */\n }\n\n body { font-family: system-ui, sans-serif; margin: 0; padding: 24px; background: #fafafa; }\n .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1120px; margin: 0 auto; }\n .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }\n .case { padding: 12px 16px; margin-bottom: 16px; }\n .case h3 { font-size: 14px; margin: 0 0 4px; }\n .case p { font-size: 13px; margin: 0; color: #64748b; }\n\n /* ── FLAG cases: colored side-tab borders using modern color formats ── */\n\n /* 1: oklch border-left + border-radius (the canonical real-page bug) */\n #flag-oklch-1 {\n width: 400px;\n background: oklch(100% 0 0);\n border-radius: 4px;\n border-left: 3px solid oklch(65% 0.12 250);\n }\n\n /* 2: oklch mixed — neutral 1px border all around + colored 4px left +\n border-radius (mirrors .medication-card from the reproducer) */\n #flag-oklch-2 {\n width: 400px;\n background: oklch(100% 0 0);\n border: 1px solid oklch(80% 0.05 250);\n border-left: 4px solid oklch(75% 0.15 45);\n border-radius: 4px;\n }\n\n /* 3: oklch alert pattern — colored 4px border-left + border-radius */\n #flag-oklch-3 {\n width: 400px;\n background: oklch(98% 0.01 60);\n border-left: 4px solid oklch(75% 0.18 45);\n border-radius: 4px;\n }\n\n /* 4: oklab border-left + border-radius */\n #flag-oklab-1 {\n width: 400px;\n background: #ffffff;\n border-radius: 6px;\n border-left: 4px solid oklab(60% 0.1 0.15);\n }\n\n /* 5: lch border-left + border-radius */\n #flag-lch-1 {\n width: 400px;\n background: #ffffff;\n border-radius: 6px;\n border-left: 4px solid lch(55% 60 250);\n }\n\n /* 6: lab border-left + border-radius */\n #flag-lab-1 {\n width: 400px;\n background: #ffffff;\n border-radius: 6px;\n border-left: 4px solid lab(50% 40 -30);\n }\n\n /* 7: card-shaped