1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Color Anti-Patterns — Should Flag vs Should Pass</title>
7 <style>
8 body { font-family: system-ui, sans-serif; background: #fafafa; padding: 24px; margin: 0; color: #1a1a1a; }
9 .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1200px; margin: 0 auto; }
10 .col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }
11 .col h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; margin: 24px 0 8px; color: #64748b; }
12 .card { padding: 14px 16px; border-radius: 10px; margin-bottom: 10px; }
13 /* Styled button color cases (declared via stylesheet so jsdom resolves them
14 reliably — inline color doesn't always win over user-agent rules in jsdom
15 for <a> and <button>). */
16 .styled-pill-low { background-color: rgb(31, 26, 21); color: rgb(91, 79, 68); display: inline-block; padding: 9px 18px; border-radius: 999px; font-weight: 500; font-size: 14px; text-decoration: none; }
17 .low-contrast-button { background-color: rgb(55, 65, 81); color: rgb(108, 114, 128); display: inline-block; padding: 10px 20px; border-radius: 8px; border: 0; font-size: 14px; }
18 .good-pill-high { background-color: rgb(20, 20, 25); color: rgb(245, 240, 232); display: inline-block; padding: 9px 18px; border-radius: 999px; font-weight: 500; font-size: 14px; text-decoration: none; }
19 .inline-link-low { color: rgb(170, 170, 170); }
20 </style>
21</head>
22<body>
23 <div class="grid">
24
25 <!-- ════════════════════════════════════════════════════════════
26 LEFT COLUMN: should flag
27 ═══════════════════════════════════════════════════════════ -->
28 <div class="col" data-col="flag">
29 <h2>Should flag</h2>
30
31 <h3>Pure black surfaces</h3>
32 <div class="card" style="background: #000000; color: white;">
33 <p>Pure #000 background</p>
34 </div>
35
36 <h3>Gray on color</h3>
37 <div class="card" style="background: rgb(59, 130, 246);">
38 <p style="color: rgb(150, 150, 150);">Gray text on blue background</p>
39 </div>
40 <div class="card" style="background: rgb(16, 185, 129);">
41 <p style="color: rgb(180, 180, 180);">Gray text on green background</p>
42 </div>
43
44 <h3>Low contrast</h3>
45 <div class="card" style="background: white;">
46 <p style="color: rgb(200, 200, 200);">Light gray text on white — very low contrast</p>
47 </div>
48 <div class="card" style="background: rgb(30, 30, 30);">
49 <p style="color: rgb(80, 80, 80);">Dark gray text on near-black — low contrast</p>
50 </div>
51 <!-- Gradient background — gray heading is unreadable across every stop -->
52 <div class="card" style="background: linear-gradient(180deg, #3b82f6 0%, #8b5cf6 100%); padding: 16px;">
53 <h1 style="color: #808080; font-size: 32px; font-weight: 800; margin: 0;">Welcome to Our Platform</h1>
54 <p style="color: #666666; font-size: 14px;">The best solution for modern teams and businesses</p>
55 </div>
56
57 <h3>Gradient text</h3>
58 <h3 style="background: linear-gradient(135deg, #667eea, #764ba2); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; font-size: 1.5rem;">
59 Gradient Heading
60 </h3>
61
62 <h3>AI color palette</h3>
63 <h1 style="color: rgb(139, 92, 246); font-size: 1.5rem; margin: 0;">Purple heading text</h1>
64
65 <h3>Styled <a> and <button> with low contrast</h3>
66 <!-- A pill-style <a> with its own opaque background and low-contrast text.
67 Currently SAFE_TAGS skips <a> entirely; this case asserts the contrast
68 check still runs when the element is styled as a button. Mirrors a real
69 bug from the landing-demo: warm-charcoal text on near-black bg. -->
70 <a href="#" class="styled-pill-low" data-test="styled-pill">Get started</a>
71 <!-- A <button> element with its own opaque background and low-contrast text.
72 Same SAFE_TAGS exception — buttons styled with their own background should
73 still pass through the contrast check. -->
74 <button class="low-contrast-button" data-test="low-contrast-button">Submit</button>
75
76 <h3>Tailwind color anti-patterns</h3>
77 <div class="bg-black text-white p-4 rounded card" style="background: black; color: white;">
78 <p>bg-black — pure black bg</p>
79 </div>
80 <div class="bg-blue-500 text-gray-400 p-4 rounded card" style="background: rgb(59, 130, 246);">
81 <p style="color: rgb(156, 163, 175);">text-gray-400 on bg-blue-500 — gray on color</p>
82 </div>
83 <h3 class="text-purple-500 text-2xl font-bold" style="color: rgb(168, 85, 247); font-size: 1.5rem; font-weight: 700;">text-purple-500 heading</h3>
84 <div class="bg-gradient-to-r from-purple-500 to-indigo-500 text-white p-4 rounded card" style="background: linear-gradient(to right, rgb(168, 85, 247), rgb(99, 102, 241)); color: white;">
85 <p>Purple-to-indigo gradient</p>
86 </div>
87 </div>
88
89 <!-- ════════════════════════════════════════════════════════════
90 RIGHT COLUMN: should pass
91 ═══════════════════════════════════════════════════════════ -->
92 <div class="col" data-col="pass">
93 <h2>Should pass</h2>
94
95 <h3>Tinted neutrals</h3>
96 <div class="card" style="background: rgb(26, 26, 30);">
97 <p style="color: rgb(240, 240, 245);">Near-black bg, near-white text — tinted, not pure</p>
98 </div>
99 <div class="card" style="background: rgb(250, 250, 252);">
100 <p style="color: rgb(20, 20, 25);">Near-white bg, near-black text — good contrast, tinted</p>
101 </div>
102
103 <h3>Pure white surface is acceptable</h3>
104 <div class="card" style="background: #ffffff;">
105 <p style="color: #111827;">Pure #fff background with dark text — acceptable contrast</p>
106 </div>
107
108 <h3>Good contrast</h3>
109 <div class="card" style="background: rgb(30, 64, 175);">
110 <p style="color: rgb(240, 240, 245);">Near-white text on dark blue — high contrast, not pure white</p>
111 </div>
112 <div class="card" style="background: rgb(16, 185, 129);">
113 <p style="color: rgb(5, 46, 32);">Dark green text on green bg — same hue family</p>
114 </div>
115
116 <h3>Distinctive accents (not AI purple)</h3>
117 <h3 style="color: rgb(220, 38, 38); font-size: 1.25rem; margin: 0;">Red heading — not AI purple</h3>
118 <h3 style="color: rgb(180, 83, 9); font-size: 1.25rem; margin: 8px 0 0;">Amber heading — distinctive</h3>
119
120 <h3>Background-image url() ancestor (not low contrast)</h3>
121 <!-- White text on transparent bg where ancestor has a background-image.
122 The detector cannot determine the image color, so it must NOT assume
123 white and report a false low-contrast finding. -->
124 <div data-test="bg-image-ancestor" style="background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg=='); background-size: cover; padding: 20px;">
125 <p style="color: rgb(255, 255, 255); font-size: 16px;">White text on image background — should not flag low-contrast</p>
126 </div>
127
128 <h3>Tailwind opacity-modified bg-black (not pure black)</h3>
129 <!-- bg-black/N classes are NOT pure black — they apply an alpha modifier.
130 The detector must not match these as pure-black-white. -->
131 <div class="bg-black/3 p-4 rounded card" data-test="bg-black-opacity" style="background: rgba(0,0,0,0.03);">
132 <p>bg-black/3 — 3% opacity, not pure black</p>
133 </div>
134 <div class="hover:bg-black/5 p-4 rounded card" data-test="bg-black-hover-opacity" style="background: rgba(0,0,0,0);">
135 <p>hover:bg-black/5 — hover state, not pure black</p>
136 </div>
137 <div class="bg-black/50 p-4 rounded card" data-test="bg-black-half-opacity" style="background: rgba(0,0,0,0.5);">
138 <p style="color: white;">bg-black/50 — 50% opacity, not pure black</p>
139 </div>
140
141 <h3>Inline <a> without own background (must remain skipped)</h3>
142 <!-- A regular text link inside a paragraph. No own background. SAFE_TAGS
143 must continue to skip these — flagging them would create noise on
144 every text link on the web. The detector exception for styled
145 buttons must not regress to flagging plain inline links. -->
146 <p>Read more about this <a href="#" class="inline-link-low" data-test="inline-link">here</a> if you want to learn more about the topic.</p>
147
148 <h3>Styled <a> with good contrast (must not flag)</h3>
149 <!-- A pill-style <a> styled correctly: cream text on near-black bg,
150 high contrast. The detector exception for styled buttons must
151 let the contrast check run, but this case must clearly pass. -->
152 <a href="#" class="good-pill-high" data-test="good-pill">High contrast pill</a>
153
154 <h3>Emoji on light backgrounds</h3>
155 <!-- Emojis render as multicolor glyphs regardless of CSS color, so the
156 CSS color is irrelevant for contrast. These should NOT be flagged. -->
157 <div class="card emoji-test" data-test="emoji-light" style="background: #ffe4e6;">
158 <p style="color: #ffe4e6; font-size: 24px;">⚠️ 🚨 ✨ 🎨</p>
159 </div>
160 <div class="card emoji-test" data-test="emoji-dark" style="background: #1a1a1a;">
161 <p style="color: #1a1a1a; font-size: 24px;">⚠️ 🚨 ✨ 🎨</p>
162 </div>
163 </div>
164 </div>
165 <script src="/js/detect-antipatterns-browser.js"></script>
166</body>
167</html>