1---
2import Base from '../../layouts/Base.astro';
3import '../../styles/sub-pages.css';
4---
5
6<Base
7 title="Slop | Impeccable"
8 description="37 patterns that mark an interface as AI-generated, plus the live detection overlay that catches them in place. The rule catalog behind npx impeccable detect, the browser extension, and /impeccable critique."
9 activeNav="slop"
10 canonicalPath="/slop"
11 bodyClass="sub-page skills-layout-page slop-page"
12>
13
14<div class="skills-layout">
15
16<aside class="skills-sidebar slop-sidebar" aria-label="Slop page sections">
17 <button class="skills-sidebar-toggle" type="button" aria-expanded="false" aria-controls="slop-sidebar-inner">
18 <span class="skills-sidebar-toggle-label">On this page</span>
19 <svg class="skills-sidebar-toggle-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
20 </button>
21 <div class="skills-sidebar-inner" id="slop-sidebar-inner">
22 <p class="skills-sidebar-label">On this page</p>
23 <div class="skills-sidebar-group">
24 <ul class="skills-sidebar-list anti-patterns-sidebar-list">
25 <li><a href="#see-it"><span>See it</span></a></li>
26 <li><a href="#try-it-live"><span>Try it live</span><span class="anti-patterns-sidebar-count">11</span></a></li>
27 <li>
28 <a href="#catalog"><span>The catalog</span><span class="anti-patterns-sidebar-count">37</span></a>
29 <ul class="slop-sidebar-sublist">
30 <li><a href="#section-visual-details"><span>Visual Details</span><span class="anti-patterns-sidebar-count">6</span></a></li>
31 <li><a href="#section-typography"><span>Typography</span><span class="anti-patterns-sidebar-count">6</span></a></li>
32 <li><a href="#section-color-contrast"><span>Color & Contrast</span><span class="anti-patterns-sidebar-count">6</span></a></li>
33 <li><a href="#section-layout-space"><span>Layout & Space</span><span class="anti-patterns-sidebar-count">7</span></a></li>
34 <li><a href="#section-motion"><span>Motion</span><span class="anti-patterns-sidebar-count">2</span></a></li>
35 <li><a href="#section-interaction"><span>Interaction</span><span class="anti-patterns-sidebar-count">2</span></a></li>
36 <li><a href="#section-responsive"><span>Responsive</span><span class="anti-patterns-sidebar-count">1</span></a></li>
37 <li><a href="#section-general-quality"><span>General quality</span><span class="anti-patterns-sidebar-count">7</span></a></li>
38 </ul>
39 </li>
40 <li><a href="#run-it"><span>Run it yourself</span></a></li>
41 </ul>
42 </div>
43 </div>
44</aside>
45 <div class="skills-main">
46
47<div class="anti-patterns-content slop-content">
48 <header class="anti-patterns-header slop-header">
49 <p class="sub-page-eyebrow">The visible tells of AI design</p>
50 <h1 class="sub-page-title">Slop</h1>
51 <p class="sub-page-lede">37 patterns that mark an interface as AI-generated, and the detection overlay that catches them in place. Watch it flag them live, try it on 11 synthetic specimens, or browse the full catalog. 25 rules run deterministically (<code>npx impeccable detect</code> or the browser extension); 12 need <a href="/docs/critique">/impeccable critique</a>'s LLM review pass.</p>
52 </header>
53
54 <section class="slop-section slop-then-now" id="see-it" aria-label="Detection overlay demo">
55 <h2 class="slop-section-heading"><span class="slop-section-num">01</span> See it</h2>
56 <div class="slop-then-now-intro">
57 <p class="slop-then-now-lede">Every wave of AI-generated UIs converges on a recognizable aesthetic. The detector catches both. The patterns just change.</p>
58 <div class="slop-era-toggle" role="tablist" aria-label="Select slop era">
59 <button class="slop-era-tab is-active" role="tab" aria-selected="true" data-era="2022">2022</button>
60 <button class="slop-era-tab" role="tab" aria-selected="false" data-era="2026">2026</button>
61 </div>
62 </div>
63 <div class="visual-mode-preview">
64 <div class="visual-mode-preview-header">
65 <span class="visual-mode-preview-dot red"></span>
66 <span class="visual-mode-preview-dot yellow"></span>
67 <span class="visual-mode-preview-dot green"></span>
68 <span class="visual-mode-preview-title" data-title-2022="Purple gradients, glassmorphism, neon glow" data-title-2026="Fraunces, warm cream, editorial restraint">Purple gradients, glassmorphism, neon glow</span>
69 </div>
70 <iframe src="/antipattern-examples/old-slop-2022.html" class="visual-mode-frame slop-era-frame" data-era="2022" loading="lazy" title="Impeccable overlay on 2022-era AI slop"></iframe>
71 <iframe src="/antipattern-examples/new-slop-2026.html" class="visual-mode-frame slop-era-frame" data-era="2026" loading="lazy" title="Impeccable overlay on 2026-era AI slop" style="display:none"></iframe>
72 </div>
73 <p class="visual-mode-demo-caption">Hover or tap any outlined element to see which rule fired. Toggle the era to see how the patterns shifted.</p>
74 </section>
75
76 <section class="slop-section visual-mode-gallery" id="try-it-live" aria-label="Try the overlay on synthetic specimens">
77 <header class="visual-mode-gallery-header">
78 <h2 class="slop-section-heading"><span class="slop-section-num">02</span> Try it live</h2>
79 <p class="visual-mode-gallery-lede">These 11 synthetic slop pages ship with the detector script baked in. Click any to see the overlay running on a real page, then hover the outlined elements.</p>
80 </header>
81 <div class="gallery-grid">
82
83 <a class="gallery-card" href="/antipattern-examples/purple-gradients.html">
84 <div class="gallery-card-thumb">
85 <img src="/antipattern-images/purple-gradients.png" alt="Purple Gradients Everywhere specimen" loading="lazy" width="540" height="540">
86 </div>
87 <div class="gallery-card-body">
88 <h3 class="gallery-card-title">Purple Gradients Everywhere</h3>
89 <p class="gallery-card-desc">The AI color palette: purple-to-blue gradients on everything. Buttons, text, backgrounds, orbs. The new "make it pop."</p>
90 </div>
91 </a>
92
93 <a class="gallery-card" href="/antipattern-examples/lazy-cool.html">
94 <div class="gallery-card-thumb">
95 <img src="/antipattern-images/lazy-cool.png" alt="Lazy "Cool" specimen" loading="lazy" width="540" height="540">
96 </div>
97 <div class="gallery-card-body">
98 <h3 class="gallery-card-title">Lazy "Cool"</h3>
99 <p class="gallery-card-desc">Glassmorphism, neon glows, blurred orbs, monospace everything. Looks like a hackathon project, not a product.</p>
100 </div>
101 </a>
102
103 <a class="gallery-card" href="/antipattern-examples/lazy-impact.html">
104 <div class="gallery-card-thumb">
105 <img src="/antipattern-images/lazy-impact.png" alt="Lazy "Impact" specimen" loading="lazy" width="540" height="540">
106 </div>
107 <div class="gallery-card-body">
108 <h3 class="gallery-card-title">Lazy "Impact"</h3>
109 <p class="gallery-card-desc">When in doubt, animate everything. Bouncing buttons, wiggling icons, gradient text, floating badges. Motion without meaning.</p>
110 </div>
111 </a>
112
113 <a class="gallery-card" href="/antipattern-examples/thick-border-cards.html">
114 <div class="gallery-card-thumb">
115 <img src="/antipattern-images/thick-border-cards.png" alt="Side-Tab Cards specimen" loading="lazy" width="540" height="540">
116 </div>
117 <div class="gallery-card-body">
118 <h3 class="gallery-card-title">Side-Tab Cards</h3>
119 <p class="gallery-card-desc">A thick colored border on one side of a rounded card. The single most recognizable tell of AI-generated UI.</p>
120 </div>
121 </a>
122
123 <a class="gallery-card" href="/antipattern-examples/cardocalypse.html">
124 <div class="gallery-card-thumb">
125 <img src="/antipattern-images/cardocalypse.png" alt="Cardocalypse specimen" loading="lazy" width="540" height="540">
126 </div>
127 <div class="gallery-card-body">
128 <h3 class="gallery-card-title">Cardocalypse</h3>
129 <p class="gallery-card-desc">Cards inside cards inside cards. Five levels of nesting, each with its own padding and shadow.</p>
130 </div>
131 </a>
132
133 <a class="gallery-card" href="/antipattern-examples/layout-templates.html">
134 <div class="gallery-card-thumb">
135 <img src="/antipattern-images/layout-templates.png" alt="Copy-Paste Layouts specimen" loading="lazy" width="540" height="540">
136 </div>
137 <div class="gallery-card-body">
138 <h3 class="gallery-card-title">Copy-Paste Layouts</h3>
139 <p class="gallery-card-desc">The same hero-metric-features template repeated with different colors. When every section looks the same, nothing stands out.</p>
140 </div>
141 </a>
142
143 <a class="gallery-card" href="/antipattern-examples/inter-everywhere.html">
144 <div class="gallery-card-thumb">
145 <img src="/antipattern-images/inter-everywhere.png" alt="Inter Everywhere specimen" loading="lazy" width="540" height="540">
146 </div>
147 <div class="gallery-card-body">
148 <h3 class="gallery-card-title">Inter Everywhere</h3>
149 <p class="gallery-card-desc">One font for everything. Headings, body, labels, buttons. No typographic hierarchy, no personality, no design.</p>
150 </div>
151 </a>
152
153 <a class="gallery-card" href="/antipattern-examples/massive-icons.html">
154 <div class="gallery-card-thumb">
155 <img src="/antipattern-images/massive-icons.png" alt="Massive Icons specimen" loading="lazy" width="540" height="540">
156 </div>
157 <div class="gallery-card-body">
158 <h3 class="gallery-card-title">Massive Icons</h3>
159 <p class="gallery-card-desc">Icon containers larger than the content they introduce. When the decoration is bigger than the message, priorities are backwards.</p>
160 </div>
161 </a>
162
163 <a class="gallery-card" href="/antipattern-examples/bad-contrast.html">
164 <div class="gallery-card-thumb">
165 <img src="/antipattern-images/bad-contrast.png" alt="Bad Contrast Choices specimen" loading="lazy" width="540" height="540">
166 </div>
167 <div class="gallery-card-body">
168 <h3 class="gallery-card-title">Bad Contrast Choices</h3>
169 <p class="gallery-card-desc">Gray text on colored backgrounds, low-contrast labels, unreadable combinations. Looking good and being readable should not conflict.</p>
170 </div>
171 </a>
172
173 <a class="gallery-card" href="/antipattern-examples/redundant-ux-writing.html">
174 <div class="gallery-card-thumb">
175 <img src="/antipattern-images/redundant-ux-writing.png" alt="Redundant UX Writing specimen" loading="lazy" width="540" height="540">
176 </div>
177 <div class="gallery-card-body">
178 <h3 class="gallery-card-title">Redundant UX Writing</h3>
179 <p class="gallery-card-desc">Label, sublabel, helper text, and hint text all saying the same thing in slightly different words. Say it once, say it well.</p>
180 </div>
181 </a>
182
183 <a class="gallery-card" href="/antipattern-examples/modal-abuse.html">
184 <div class="gallery-card-thumb">
185 <img src="/antipattern-images/modal-abuse.png" alt="Modal Abuse specimen" loading="lazy" width="540" height="540">
186 </div>
187 <div class="gallery-card-body">
188 <h3 class="gallery-card-title">Modal Abuse</h3>
189 <p class="gallery-card-desc">Complex settings crammed into a modal. If it needs a scroll bar and three columns, it deserves its own page.</p>
190 </div>
191 </a>
192 </div>
193 </section>
194
195 <section class="slop-section slop-catalog" id="catalog" aria-label="Rule catalog">
196 <header class="slop-catalog-header">
197 <h2 class="slop-section-heading"><span class="slop-section-num">03</span> The catalog</h2>
198 <p class="slop-catalog-lede">Every pattern <a href="/docs/impeccable">/impeccable</a> teaches against. <strong>AI slop</strong> rules flag the tells of AI-generated UIs; <strong>Quality</strong> rules flag general design mistakes that hurt regardless of who wrote them.</p>
199 </header>
200
201 <details class="anti-patterns-legend">
202 <summary class="anti-patterns-legend-summary">
203 <span class="anti-patterns-legend-title">How to read this</span>
204 <svg class="anti-patterns-legend-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
205 </summary>
206 <div class="anti-patterns-legend-body">
207 <p>Each rule shows how it is detected:</p>
208 <dl class="anti-patterns-legend-layers">
209 <div><dt><span class="rule-card-layer" data-layer="cli">CLI</span></dt><dd>Deterministic. Runs from <code>npx impeccable detect</code> on files, no browser required.</dd></div>
210 <div><dt><span class="rule-card-layer" data-layer="browser">Browser</span></dt><dd>Deterministic, but needs real browser layout. Runs via the browser extension or Puppeteer, not the plain CLI.</dd></div>
211 <div><dt><span class="rule-card-layer" data-layer="llm">LLM only</span></dt><dd>No deterministic detector. Caught by <a href="/docs/critique">/impeccable critique</a> during its LLM design review.</dd></div>
212 </dl>
213 </div>
214 </details>
215
216 <div class="anti-patterns-sections">
217
218 <section class="anti-patterns-section" id="section-visual-details">
219 <header class="anti-patterns-section-header">
220 <h3 class="anti-patterns-section-title">Visual Details</h3>
221 <p class="anti-patterns-section-count">6 rules</p>
222 </header>
223 <div class="rule-card-grid">
224
225 <article class="rule-card" id="rule-border-accent-on-rounded" data-layer="cli">
226 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #fff; border: 2px solid oklch(60% 0.22 290); border-radius: 16px; padding: 14px 18px; width: 220px; font-family: system-ui, sans-serif; font-size: 13px; color: #111;"><div style="font-weight: 600;">Rounded card</div><div style="color: #666; font-size: 12px;">Thick colored border clashes with the radius.</div></div></div></div>
227 <div class="rule-card-body">
228 <div class="rule-card-head">
229 <span class="rule-card-category" data-category="slop">AI slop</span>
230 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
231 </div>
232 <h3 class="rule-card-name">Border accent on rounded element</h3>
233 <p class="rule-card-desc">Thick accent border on a rounded card. The border clashes with the rounded corners. Remove the border or the border-radius.</p>
234 <a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
235 </div>
236 </article>
237
238 <article class="rule-card" id="rule-glassmorphism" data-layer="llm">
239 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="position: relative; width: 100%; height: 100%; background: linear-gradient(135deg, oklch(70% 0.22 265), oklch(70% 0.25 340)); border-radius: 10px; overflow: hidden; display: flex; align-items: center; justify-content: center;"><div style="background: rgba(255,255,255,0.25); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); border: 1px solid rgba(255,255,255,0.4); border-radius: 10px; padding: 14px 18px; color: #fff; font-family: system-ui, sans-serif; font-size: 12px; font-weight: 600; box-shadow: 0 8px 30px rgba(0,0,0,0.12);">Frosted glass card</div></div></div></div>
240 <div class="rule-card-body">
241 <div class="rule-card-head">
242 <span class="rule-card-category" data-category="slop">AI slop</span>
243 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
244 </div>
245 <h3 class="rule-card-name">Glassmorphism everywhere</h3>
246 <p class="rule-card-desc">Blur effects, glass cards, and glow borders used as decoration rather than to solve a real layering problem.</p>
247 <a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
248 </div>
249 </article>
250
251 <article class="rule-card" id="rule-modal-reflex" data-layer="llm">
252 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="position: relative; width: 100%; height: 100%; background: #f5f3ef; border-radius: 8px; overflow: hidden;"><div style="position: absolute; inset: 0; background: rgba(0,0,0,0.35);"></div><div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #fff; border-radius: 8px; padding: 14px 18px; width: 200px; font-family: system-ui, sans-serif; box-shadow: 0 20px 60px rgba(0,0,0,0.2);"><div style="font-size: 13px; font-weight: 600; color: #111; margin-bottom: 4px;">Are you sure?</div><div style="font-size: 11px; color: #666; margin-bottom: 8px;">Really, truly sure about this?</div><div style="display: flex; gap: 6px; justify-content: flex-end;"><div style="background: #eee; color: #555; padding: 4px 8px; border-radius: 4px; font-size: 10px;">Cancel</div><div style="background: oklch(60% 0.22 265); color: #fff; padding: 4px 8px; border-radius: 4px; font-size: 10px;">OK</div></div></div></div></div></div>
253 <div class="rule-card-body">
254 <div class="rule-card-head">
255 <span class="rule-card-category" data-category="slop">AI slop</span>
256 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
257 </div>
258 <h3 class="rule-card-name">Reaching for modals by reflex</h3>
259 <p class="rule-card-desc">Modals interrupt the user and are lazy as a design default. Use them only when there is truly no better place for the interaction.</p>
260 <a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
261 </div>
262 </article>
263
264 <article class="rule-card" id="rule-generic-drop-shadows" data-layer="llm">
265 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="display: flex; gap: 10px;"><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 10px; width: 70px; height: 70px; box-shadow: 0 10px 30px rgba(0,0,0,0.08);"></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 10px; width: 70px; height: 70px; box-shadow: 0 10px 30px rgba(0,0,0,0.08);"></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 10px; width: 70px; height: 70px; box-shadow: 0 10px 30px rgba(0,0,0,0.08);"></div></div></div></div>
266 <div class="rule-card-body">
267 <div class="rule-card-head">
268 <span class="rule-card-category" data-category="slop">AI slop</span>
269 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
270 </div>
271 <h3 class="rule-card-name">Rounded rectangles with generic drop shadows</h3>
272 <p class="rule-card-desc">The safest, most forgettable shape on the web. Could be the output of any AI. Commit to a stronger visual treatment.</p>
273 <a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
274 </div>
275 </article>
276
277 <article class="rule-card" id="rule-side-tab" data-layer="cli">
278 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #fff; border: 1px solid #e8e4df; border-left: 4px solid oklch(60% 0.22 265); border-radius: 6px; padding: 14px 16px; width: 220px; font-family: system-ui, sans-serif; font-size: 13px; color: #111;"><div style="font-weight: 600; margin-bottom: 4px;">Alert title</div><div style="color: #666; font-size: 12px;">Thick colored stripe on one side.</div></div></div></div>
279 <div class="rule-card-body">
280 <div class="rule-card-head">
281 <span class="rule-card-category" data-category="slop">AI slop</span>
282 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
283 </div>
284 <h3 class="rule-card-name">Side-tab accent border</h3>
285 <p class="rule-card-desc">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.</p>
286 <a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
287 </div>
288 </article>
289
290 <article class="rule-card" id="rule-sparkline-decoration" data-layer="llm">
291 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 8px; padding: 14px 16px; width: 220px; font-family: system-ui, sans-serif;"><div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px;"><div><div style="font-size: 10px; color: #888; text-transform: uppercase; letter-spacing: 0.08em;">Revenue</div><div style="font-size: 20px; font-weight: 700; color: #111;">$42.1k</div></div><svg width="60" height="28" viewBox="0 0 60 28" style="flex-shrink: 0;"><polyline points="0,20 10,18 20,22 30,10 40,14 50,6 60,12" stroke="oklch(62% 0.22 265)" stroke-width="2" fill="none"/></svg></div><div style="font-size: 10px; color: #888;">Tiny chart, no real information.</div></div></div></div>
292 <div class="rule-card-body">
293 <div class="rule-card-head">
294 <span class="rule-card-category" data-category="slop">AI slop</span>
295 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
296 </div>
297 <h3 class="rule-card-name">Sparklines as decoration</h3>
298 <p class="rule-card-desc">Tiny charts that look sophisticated but convey no meaningful information. If the data matters, give it room.</p>
299 <a class="rule-card-skill-link" href="/docs/impeccable#visual-details">See in /impeccable</a>
300 </div>
301 </article>
302 </div>
303 </section>
304 <section class="anti-patterns-section" id="section-typography">
305 <header class="anti-patterns-section-header">
306 <h3 class="anti-patterns-section-title">Typography</h3>
307 <p class="anti-patterns-section-count">6 rules</p>
308 </header>
309 <div class="rule-card-grid">
310
311 <article class="rule-card" id="rule-flat-type-hierarchy" data-layer="cli">
312 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; line-height: 1.3;"><div style="font-size: 17px; font-weight: 600;">Heading</div><div style="font-size: 16px; font-weight: 500; margin: 2px 0;">Subheading</div><div style="font-size: 15px; color: #555;">Body text at almost the same size.</div></div></div></div>
313 <div class="rule-card-body">
314 <div class="rule-card-head">
315 <span class="rule-card-category" data-category="slop">AI slop</span>
316 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
317 </div>
318 <h3 class="rule-card-name">Flat type hierarchy</h3>
319 <p class="rule-card-desc">Font sizes are too close together. No clear visual hierarchy. Use fewer sizes with more contrast (aim for at least a 1.25 ratio between steps).</p>
320 <a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
321 </div>
322 </article>
323
324 <article class="rule-card" id="rule-icon-tile-stack" data-layer="cli">
325 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111;"><div style="width: 44px; height: 44px; border-radius: 10px; background: linear-gradient(135deg, oklch(62% 0.22 265), oklch(70% 0.20 320)); display: flex; align-items: center; justify-content: center; font-size: 20px; color: #fff; margin-bottom: 10px;">✦</div><div style="font-size: 14px; font-weight: 600; margin-bottom: 2px;">Feature name</div><div style="font-size: 12px; color: #666;">Rounded icon tile above heading.</div></div></div></div>
326 <div class="rule-card-body">
327 <div class="rule-card-head">
328 <span class="rule-card-category" data-category="slop">AI slop</span>
329 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
330 </div>
331 <h3 class="rule-card-name">Icon tile stacked above heading</h3>
332 <p class="rule-card-desc">A small rounded-square icon container above a heading is the universal AI feature-card template. Every generator outputs this exact shape. Try a side-by-side icon and heading, or let the icon sit in flow without its own container.</p>
333 <a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
334 </div>
335 </article>
336
337 <article class="rule-card" id="rule-monospace-as-technical" data-layer="llm">
338 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: 'Courier New', monospace; color: #111;"><div style="font-size: 18px; font-weight: 700; margin-bottom: 6px;">TECHNICAL_TOOL</div><div style="font-size: 11px; color: #555;">Mono for "developer" vibes. Lazy.</div></div></div></div>
339 <div class="rule-card-body">
340 <div class="rule-card-head">
341 <span class="rule-card-category" data-category="slop">AI slop</span>
342 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
343 </div>
344 <h3 class="rule-card-name">Monospace as "technical" shorthand</h3>
345 <p class="rule-card-desc">Using a monospace typeface to signal "developer / technical" vibes. Reach for real type choices instead of a lazy stereotype.</p>
346 <a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
347 </div>
348 </article>
349
350 <article class="rule-card" id="rule-overused-font" data-layer="cli">
351 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: Inter, system-ui, sans-serif; font-size: 15px; color: #111; line-height: 1.4;"><div style="font-weight: 600; margin-bottom: 4px;">Just another Inter headline</div><div style="color: #555; font-size: 13px;">Every SaaS homepage looks like this.</div></div></div></div>
352 <div class="rule-card-body">
353 <div class="rule-card-head">
354 <span class="rule-card-category" data-category="slop">AI slop</span>
355 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
356 </div>
357 <h3 class="rule-card-name">Overused font</h3>
358 <p class="rule-card-desc">Inter, Roboto, Fraunces, Geist, Plus Jakarta Sans, and Space Grotesk are used on so many sites they no longer feel distinctive. Each new wave of AI-generated UIs converges on the same handful of faces. Choose a face that gives your interface personality.</p>
359 <a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
360 </div>
361 </article>
362
363 <article class="rule-card" id="rule-single-font" data-layer="cli">
364 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; font-size: 14px; color: #111;"><div style="font-size: 19px; font-weight: 600; margin-bottom: 6px;">Heading in the body font</div><div style="color: #555;">Body in the same font. No contrast. Flat.</div></div></div></div>
365 <div class="rule-card-body">
366 <div class="rule-card-head">
367 <span class="rule-card-category" data-category="slop">AI slop</span>
368 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
369 </div>
370 <h3 class="rule-card-name">Single font for everything</h3>
371 <p class="rule-card-desc">Only one font family is used for the entire page. Pair a distinctive display font with a refined body font to create typographic hierarchy.</p>
372 <a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
373 </div>
374 </article>
375
376 <article class="rule-card" id="rule-all-caps-body" data-layer="cli">
377 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; line-height: 1.5;">Long passages in uppercase are hard to read. We recognize words by their shape, which all-caps removes.</div></div></div>
378 <div class="rule-card-body">
379 <div class="rule-card-head">
380 <span class="rule-card-category" data-category="quality">Quality</span>
381 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
382 </div>
383 <h3 class="rule-card-name">All-caps body text</h3>
384 <p class="rule-card-desc">Long passages in uppercase are hard to read. We recognize words by shape (ascenders and descenders), which all-caps removes. Reserve uppercase for short labels and headings.</p>
385 <a class="rule-card-skill-link" href="/docs/impeccable#typography">See in /impeccable</a>
386 </div>
387 </article>
388 </div>
389 </section>
390 <section class="anti-patterns-section" id="section-color-contrast">
391 <header class="anti-patterns-section-header">
392 <h3 class="anti-patterns-section-title">Color & Contrast</h3>
393 <p class="anti-patterns-section-count">6 rules</p>
394 </header>
395 <div class="rule-card-grid">
396
397 <article class="rule-card" id="rule-ai-color-palette" data-layer="cli">
398 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="display: flex; gap: 6px;"><div style="width: 44px; height: 44px; border-radius: 6px; background: oklch(60% 0.22 265);"></div><div style="width: 44px; height: 44px; border-radius: 6px; background: oklch(62% 0.25 300);"></div><div style="width: 44px; height: 44px; border-radius: 6px; background: oklch(64% 0.25 340);"></div><div style="width: 44px; height: 44px; border-radius: 6px; background: oklch(70% 0.20 200);"></div></div></div></div>
399 <div class="rule-card-body">
400 <div class="rule-card-head">
401 <span class="rule-card-category" data-category="slop">AI slop</span>
402 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
403 </div>
404 <h3 class="rule-card-name">AI color palette</h3>
405 <p class="rule-card-desc">Purple/violet gradients and cyan-on-dark are the most recognizable tells of AI-generated UIs. Choose a distinctive, intentional palette.</p>
406 <a class="rule-card-skill-link" href="/docs/impeccable#color-contrast">See in /impeccable</a>
407 </div>
408 </article>
409
410 <article class="rule-card" id="rule-dark-glow" data-layer="cli">
411 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #0a0b14; padding: 18px 20px; border-radius: 10px; font-family: system-ui, sans-serif;"><div style="color: oklch(78% 0.22 280); text-shadow: 0 0 12px oklch(78% 0.22 280 / 0.7); font-size: 16px; font-weight: 600;">Neon on dark</div><div style="color: oklch(60% 0.12 260); font-size: 12px; margin-top: 4px;">Cyberpunk-by-default slop.</div></div></div></div>
412 <div class="rule-card-body">
413 <div class="rule-card-head">
414 <span class="rule-card-category" data-category="slop">AI slop</span>
415 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
416 </div>
417 <h3 class="rule-card-name">Dark mode with glowing accents</h3>
418 <p class="rule-card-desc">Dark backgrounds with colored box-shadow glows are the default "cool" look of AI-generated UIs. Use subtle, purposeful lighting instead, or skip the dark theme entirely.</p>
419 <a class="rule-card-skill-link" href="/docs/impeccable#color-contrast">See in /impeccable</a>
420 </div>
421 </article>
422
423 <article class="rule-card" id="rule-dark-mode-default" data-layer="llm">
424 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #0f1117; padding: 18px; border-radius: 8px; font-family: system-ui, sans-serif;"><div style="color: #e5e7eb; font-size: 14px; font-weight: 600; margin-bottom: 4px;">Dark by default</div><div style="color: #9ca3af; font-size: 11px;">Defaulting to dark is a retreat from a decision.</div></div></div></div>
425 <div class="rule-card-body">
426 <div class="rule-card-head">
427 <span class="rule-card-category" data-category="slop">AI slop</span>
428 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
429 </div>
430 <h3 class="rule-card-name">Defaulting to dark mode for "safety"</h3>
431 <p class="rule-card-desc">Defaulting to light mode to be safe is the inverse of defaulting to dark mode to look cool. Either way you are retreating from a decision.</p>
432 <a class="rule-card-skill-link" href="/docs/impeccable#color-contrast">See in /impeccable</a>
433 </div>
434 </article>
435
436 <article class="rule-card" id="rule-gradient-text" data-layer="cli">
437 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif;"><div style="font-size: 28px; font-weight: 700; background: linear-gradient(135deg, oklch(65% 0.25 320), oklch(60% 0.25 265)); -webkit-background-clip: text; background-clip: text; color: transparent; line-height: 1.1;">Build the Future</div><div style="font-size: 12px; color: #888; margin-top: 4px;">Gradient text kills scannability.</div></div></div></div>
438 <div class="rule-card-body">
439 <div class="rule-card-head">
440 <span class="rule-card-category" data-category="slop">AI slop</span>
441 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
442 </div>
443 <h3 class="rule-card-name">Gradient text</h3>
444 <p class="rule-card-desc">Gradient text is decorative rather than meaningful. A common AI tell, especially on headings and metrics. Use solid colors for text.</p>
445 <a class="rule-card-skill-link" href="/docs/impeccable#color-contrast">See in /impeccable</a>
446 </div>
447 </article>
448
449 <article class="rule-card" id="rule-gray-on-color" data-layer="cli">
450 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: oklch(60% 0.20 265); padding: 16px 18px; border-radius: 6px; font-family: system-ui, sans-serif;"><div style="color: #9ca3af; font-size: 13px;">Gray text on a colored background. Washed out and hard to read.</div></div></div></div>
451 <div class="rule-card-body">
452 <div class="rule-card-head">
453 <span class="rule-card-category" data-category="quality">Quality</span>
454 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
455 </div>
456 <h3 class="rule-card-name">Gray text on colored background</h3>
457 <p class="rule-card-desc">Gray text looks washed out on colored backgrounds. Use a darker shade of the background color instead, or white/near-white for contrast.</p>
458 <a class="rule-card-skill-link" href="/docs/impeccable#color-contrast">See in /impeccable</a>
459 </div>
460 </article>
461
462 <article class="rule-card" id="rule-pure-black-white" data-layer="cli">
463 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #ffffff; padding: 16px 18px; color: #000000; font-family: system-ui, sans-serif; font-size: 14px;"><div style="font-weight: 600; margin-bottom: 4px;">Pure black on pure white</div><div style="font-size: 12px; color: #000;">Neither exists in nature. Always tint.</div></div></div></div>
464 <div class="rule-card-body">
465 <div class="rule-card-head">
466 <span class="rule-card-category" data-category="quality">Quality</span>
467 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
468 </div>
469 <h3 class="rule-card-name">Pure black background</h3>
470 <p class="rule-card-desc">Pure #000000 as a background color looks harsh and unnatural. Tint it slightly toward your brand hue (e.g., oklch(12% 0.01 250)) for a more refined feel.</p>
471 <a class="rule-card-skill-link" href="/docs/impeccable#color-contrast">See in /impeccable</a>
472 </div>
473 </article>
474 </div>
475 </section>
476 <section class="anti-patterns-section" id="section-layout-space">
477 <header class="anti-patterns-section-header">
478 <h3 class="anti-patterns-section-title">Layout & Space</h3>
479 <p class="anti-patterns-section-count">7 rules</p>
480 </header>
481 <div class="rule-card-grid">
482
483 <article class="rule-card" id="rule-everything-centered" data-layer="cli">
484 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; text-align: center; color: #111;"><div style="font-size: 16px; font-weight: 600; margin-bottom: 6px;">Centered headline</div><div style="font-size: 12px; color: #555; margin-bottom: 10px;">Everything centered by default.</div><div style="display: inline-block; background: #111; color: #fff; padding: 6px 14px; border-radius: 6px; font-size: 12px;">Call to action</div></div></div></div>
485 <div class="rule-card-body">
486 <div class="rule-card-head">
487 <span class="rule-card-category" data-category="slop">AI slop</span>
488 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
489 </div>
490 <h3 class="rule-card-name">Everything centered</h3>
491 <p class="rule-card-desc">Every text element is center-aligned. Left-aligned text with asymmetric layouts feels more designed. Center only hero sections and CTAs.</p>
492 <a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
493 </div>
494 </article>
495
496 <article class="rule-card" id="rule-hero-metric-layout" data-layer="llm">
497 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; text-align: left;"><div style="font-size: 42px; font-weight: 800; background: linear-gradient(135deg, oklch(65% 0.25 265), oklch(65% 0.25 340)); -webkit-background-clip: text; background-clip: text; color: transparent; line-height: 1;">10M+</div><div style="font-size: 10px; color: #888; text-transform: uppercase; letter-spacing: 0.1em; margin-top: 2px;">Active users</div><div style="display: flex; gap: 14px; margin-top: 10px; font-size: 10px; color: #555;"><span><strong>99.9%</strong> uptime</span><span><strong>200ms</strong> p50</span></div></div></div></div>
498 <div class="rule-card-body">
499 <div class="rule-card-head">
500 <span class="rule-card-category" data-category="slop">AI slop</span>
501 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
502 </div>
503 <h3 class="rule-card-name">Hero metric layout</h3>
504 <p class="rule-card-desc">Big number, small label, three supporting stats, gradient accent. Used everywhere, trusted nowhere.</p>
505 <a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
506 </div>
507 </article>
508
509 <article class="rule-card" id="rule-identical-card-grids" data-layer="llm">
510 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; font-family: system-ui, sans-serif;"><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;"><div style="width: 18px; height: 18px; background: oklch(62% 0.20 265); border-radius: 4px;"></div><div style="font-size: 10px; font-weight: 600; color: #111;">Feature</div><div style="font-size: 9px; color: #888;">Short copy.</div></div></div></div></div>
511 <div class="rule-card-body">
512 <div class="rule-card-head">
513 <span class="rule-card-category" data-category="slop">AI slop</span>
514 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
515 </div>
516 <h3 class="rule-card-name">Identical card grids</h3>
517 <p class="rule-card-desc">Same-sized cards with icon + heading + text repeated endlessly. The default AI homepage layout.</p>
518 <a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
519 </div>
520 </article>
521
522 <article class="rule-card" id="rule-monotonous-spacing" data-layer="cli">
523 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;"><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; height: 48px;"></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; height: 48px;"></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; height: 48px;"></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; height: 48px;"></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; height: 48px;"></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; height: 48px;"></div></div></div></div>
524 <div class="rule-card-body">
525 <div class="rule-card-head">
526 <span class="rule-card-category" data-category="slop">AI slop</span>
527 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
528 </div>
529 <h3 class="rule-card-name">Monotonous spacing</h3>
530 <p class="rule-card-desc">The same spacing value used everywhere. No rhythm, no variation. Use tight groupings for related items and generous separations between sections.</p>
531 <a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
532 </div>
533 </article>
534
535 <article class="rule-card" id="rule-nested-cards" data-layer="cli">
536 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #f5f3ef; border: 1px solid #e0dcd4; border-radius: 10px; padding: 10px;"><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 8px; padding: 10px;"><div style="background: #f5f3ef; border: 1px solid #e8e4df; border-radius: 6px; padding: 8px; font-size: 12px; font-family: system-ui, sans-serif; color: #555;">Card inside card inside card.</div></div></div></div></div>
537 <div class="rule-card-body">
538 <div class="rule-card-head">
539 <span class="rule-card-category" data-category="slop">AI slop</span>
540 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
541 </div>
542 <h3 class="rule-card-name">Nested cards</h3>
543 <p class="rule-card-desc">Cards inside cards create visual noise and excessive depth. Flatten the hierarchy: use spacing, typography, and dividers instead of nesting containers.</p>
544 <a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
545 </div>
546 </article>
547
548 <article class="rule-card" id="rule-everything-in-cards" data-layer="llm">
549 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 8px; padding: 10px;"><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 8px; font-family: system-ui, sans-serif; font-size: 12px; color: #111;"><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 4px; padding: 6px;">Title</div></div><div style="background: #fff; border: 1px solid #e8e4df; border-radius: 6px; padding: 8px; margin-top: 6px; font-family: system-ui, sans-serif; font-size: 11px; color: #555;">Card around every single thing.</div></div></div></div>
550 <div class="rule-card-body">
551 <div class="rule-card-head">
552 <span class="rule-card-category" data-category="slop">AI slop</span>
553 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
554 </div>
555 <h3 class="rule-card-name">Wrapping everything in cards</h3>
556 <p class="rule-card-desc">Not every piece of content needs a bordered container. Spacing and alignment create visual grouping without the overhead of a card.</p>
557 <a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
558 </div>
559 </article>
560
561 <article class="rule-card" id="rule-line-length" data-layer="browser">
562 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; font-size: 13px; color: #111; line-height: 1.55; max-width: 100%;">Paragraphs wider than roughly 75 characters per line become fatiguing because the eye has to track an excessive distance back to the start of the next line, losing its place.</div></div></div>
563 <div class="rule-card-body">
564 <div class="rule-card-head">
565 <span class="rule-card-category" data-category="quality">Quality</span>
566 <span class="rule-card-layer" data-layer="browser" title="Deterministic, but needs real browser layout. Runs via the browser extension or Puppeteer, not the plain CLI.">Browser</span>
567 </div>
568 <h3 class="rule-card-name">Line length too long</h3>
569 <p class="rule-card-desc">Text lines wider than ~80 characters are hard to read. The eye loses its place tracking back to the start of the next line. Add a max-width (65ch to 75ch) to text containers.</p>
570 <a class="rule-card-skill-link" href="/docs/impeccable#layout-space">See in /impeccable</a>
571 </div>
572 </article>
573 </div>
574 </section>
575 <section class="anti-patterns-section" id="section-motion">
576 <header class="anti-patterns-section-header">
577 <h3 class="anti-patterns-section-title">Motion</h3>
578 <p class="anti-patterns-section-count">2 rules</p>
579 </header>
580 <div class="rule-card-grid">
581
582 <article class="rule-card" id="rule-bounce-easing" data-layer="cli">
583 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; display: flex; align-items: center; gap: 10px;"><div style="width: 36px; height: 36px; border-radius: 50%; background: oklch(65% 0.22 265); animation: bouncey 0.9s cubic-bezier(0.68, -0.55, 0.27, 1.55) infinite;"></div><div style="font-size: 12px; color: #555;">Bounce + elastic easing feels dated.</div><style>@keyframes bouncey { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }</style></div></div></div>
584 <div class="rule-card-body">
585 <div class="rule-card-head">
586 <span class="rule-card-category" data-category="slop">AI slop</span>
587 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
588 </div>
589 <h3 class="rule-card-name">Bounce or elastic easing</h3>
590 <p class="rule-card-desc">Bounce and elastic easing feel dated and tacky. Real objects decelerate smoothly. Use exponential easing (ease-out-quart/quint/expo) instead.</p>
591 <a class="rule-card-skill-link" href="/docs/impeccable#motion">See in /impeccable</a>
592 </div>
593 </article>
594
595 <article class="rule-card" id="rule-layout-transition" data-layer="cli">
596 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; display: flex; align-items: center; gap: 10px;"><div style="background: oklch(65% 0.22 265); border-radius: 6px; animation: janky 1.2s ease-in-out infinite; width: 60px; height: 30px;"></div><div style="font-size: 12px; color: #555;">Animating width/height causes layout jank.</div><style>@keyframes janky { 0%,100% { width: 60px; } 50% { width: 120px; } }</style></div></div></div>
597 <div class="rule-card-body">
598 <div class="rule-card-head">
599 <span class="rule-card-category" data-category="quality">Quality</span>
600 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
601 </div>
602 <h3 class="rule-card-name">Layout property animation</h3>
603 <p class="rule-card-desc">Animating width, height, padding, or margin causes layout thrash and janky performance. Use transform and opacity instead, or grid-template-rows for height animations.</p>
604 <a class="rule-card-skill-link" href="/docs/impeccable#motion">See in /impeccable</a>
605 </div>
606 </article>
607 </div>
608 </section>
609 <section class="anti-patterns-section" id="section-interaction">
610 <header class="anti-patterns-section-header">
611 <h3 class="anti-patterns-section-title">Interaction</h3>
612 <p class="anti-patterns-section-count">2 rules</p>
613 </header>
614 <div class="rule-card-grid">
615
616 <article class="rule-card" id="rule-every-button-primary" data-layer="llm">
617 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="display: flex; flex-direction: column; gap: 6px; font-family: system-ui, sans-serif;"><div style="display: flex; gap: 6px;"><button style="background: oklch(60% 0.22 265); color: #fff; border: none; border-radius: 5px; padding: 6px 12px; font-size: 11px; font-weight: 600;">Save</button><button style="background: oklch(60% 0.22 265); color: #fff; border: none; border-radius: 5px; padding: 6px 12px; font-size: 11px; font-weight: 600;">Cancel</button><button style="background: oklch(60% 0.22 265); color: #fff; border: none; border-radius: 5px; padding: 6px 12px; font-size: 11px; font-weight: 600;">Delete</button></div><div style="font-size: 10px; color: #888;">Every action shouts equally.</div></div></div></div>
618 <div class="rule-card-body">
619 <div class="rule-card-head">
620 <span class="rule-card-category" data-category="quality">Quality</span>
621 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
622 </div>
623 <h3 class="rule-card-name">Every button is a primary button</h3>
624 <p class="rule-card-desc">When every button looks equally important, nothing reads as the primary action. Use ghost buttons, text links, and secondary styles to build hierarchy.</p>
625 <a class="rule-card-skill-link" href="/docs/impeccable#interaction">See in /impeccable</a>
626 </div>
627 </article>
628
629 <article class="rule-card" id="rule-redundant-headers" data-layer="llm">
630 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111; max-width: 230px;"><div style="font-size: 14px; font-weight: 600; margin-bottom: 4px;">Overview</div><div style="font-size: 11px; color: #555; line-height: 1.5;">This is the overview section, which provides an overview of the overview.</div></div></div></div>
631 <div class="rule-card-body">
632 <div class="rule-card-head">
633 <span class="rule-card-category" data-category="quality">Quality</span>
634 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
635 </div>
636 <h3 class="rule-card-name">Redundant information</h3>
637 <p class="rule-card-desc">Intros that restate the heading. Section labels that repeat the page title. Cards that echo their own caption. Make every word earn its place.</p>
638 <a class="rule-card-skill-link" href="/docs/impeccable#interaction">See in /impeccable</a>
639 </div>
640 </article>
641 </div>
642 </section>
643 <section class="anti-patterns-section" id="section-responsive">
644 <header class="anti-patterns-section-header">
645 <h3 class="anti-patterns-section-title">Responsive</h3>
646 <p class="anti-patterns-section-count">1 rule</p>
647 </header>
648 <div class="rule-card-grid">
649
650 <article class="rule-card" id="rule-mobile-amputation" data-layer="llm">
651 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif;"><div style="display: flex; align-items: center; gap: 8px; padding: 8px 10px; background: #fff; border: 1px solid #e8e4df; border-radius: 6px; margin-bottom: 4px; font-size: 12px; color: #999; text-decoration: line-through;"><span>Export to CSV</span></div><div style="font-size: 10px; color: #888; margin-top: 4px;">"Not available on mobile."</div></div></div></div>
652 <div class="rule-card-body">
653 <div class="rule-card-head">
654 <span class="rule-card-category" data-category="quality">Quality</span>
655 <span class="rule-card-layer" data-layer="llm" title="Not caught by any deterministic detector. Flagged by /impeccable critique during its LLM design review.">LLM only</span>
656 </div>
657 <h3 class="rule-card-name">Amputating features on mobile</h3>
658 <p class="rule-card-desc">Hiding critical functionality on mobile because it is inconvenient. Adapt the interface to the context, do not strip it.</p>
659 <a class="rule-card-skill-link" href="/docs/impeccable#responsive">See in /impeccable</a>
660 </div>
661 </article>
662 </div>
663 </section>
664 <section class="anti-patterns-section" id="section-general-quality">
665 <header class="anti-patterns-section-header">
666 <h3 class="anti-patterns-section-title">General quality</h3>
667 <p class="anti-patterns-section-count">7 rules</p>
668 </header>
669 <div class="rule-card-grid">
670
671 <article class="rule-card" id="rule-cramped-padding" data-layer="browser">
672 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif;"><button style="background: #111; color: #fff; border: none; border-radius: 4px; padding: 2px 6px; font-size: 13px; font-weight: 500;">Buy now</button> <span style="color: #555; font-size: 12px; margin-left: 8px;">2px vertical padding.</span></div></div></div>
673 <div class="rule-card-body">
674 <div class="rule-card-head">
675 <span class="rule-card-category" data-category="quality">Quality</span>
676 <span class="rule-card-layer" data-layer="browser" title="Deterministic, but needs real browser layout. Runs via the browser extension or Puppeteer, not the plain CLI.">Browser</span>
677 </div>
678 <h3 class="rule-card-name">Cramped padding</h3>
679 <p class="rule-card-desc">Text is too close to the edge of its container. Add at least 8px (ideally 12-16px) of padding inside bordered or colored containers.</p>
680
681 </div>
682 </article>
683
684 <article class="rule-card" id="rule-justified-text" data-layer="cli">
685 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; font-size: 12px; color: #111; text-align: justify; max-width: 230px; line-height: 1.5;">Justified text on screens creates rivers of whitespace because browsers can't hyphenate well. Leave this for print.</div></div></div>
686 <div class="rule-card-body">
687 <div class="rule-card-head">
688 <span class="rule-card-category" data-category="quality">Quality</span>
689 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
690 </div>
691 <h3 class="rule-card-name">Justified text</h3>
692 <p class="rule-card-desc">Justified text without hyphenation creates uneven word spacing ("rivers of white"). Use text-align: left for body text, or enable hyphens: auto if you must justify.</p>
693
694 </div>
695 </article>
696
697 <article class="rule-card" id="rule-low-contrast" data-layer="cli">
698 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="background: #fff; padding: 16px 18px; font-family: system-ui, sans-serif;"><div style="color: #d4d4d4; font-size: 13px;">Light gray text on a white background. 1.6:1 contrast, fails WCAG.</div></div></div></div>
699 <div class="rule-card-body">
700 <div class="rule-card-head">
701 <span class="rule-card-category" data-category="quality">Quality</span>
702 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
703 </div>
704 <h3 class="rule-card-name">Low contrast text</h3>
705 <p class="rule-card-desc">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.</p>
706
707 </div>
708 </article>
709
710 <article class="rule-card" id="rule-skipped-heading" data-layer="cli">
711 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111;"><h1 style="font-size: 20px; font-weight: 700; margin: 0 0 4px;">Page title (h1)</h1><h3 style="font-size: 13px; font-weight: 600; margin: 0; color: #555;">Subsection (h3), skipped h2</h3></div></div></div>
712 <div class="rule-card-body">
713 <div class="rule-card-head">
714 <span class="rule-card-category" data-category="quality">Quality</span>
715 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
716 </div>
717 <h3 class="rule-card-name">Skipped heading level</h3>
718 <p class="rule-card-desc">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.</p>
719
720 </div>
721 </article>
722
723 <article class="rule-card" id="rule-tight-leading" data-layer="cli">
724 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; font-size: 13px; color: #111; line-height: 1.0; max-width: 220px;">Tight leading makes multi-line body text feel crammed and hard for the eye to track between lines.</div></div></div>
725 <div class="rule-card-body">
726 <div class="rule-card-head">
727 <span class="rule-card-category" data-category="quality">Quality</span>
728 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
729 </div>
730 <h3 class="rule-card-name">Tight line height</h3>
731 <p class="rule-card-desc">Line height below 1.3x the font size makes multi-line text hard to read. Use 1.5 to 1.7 for body text so lines have room to breathe.</p>
732
733 </div>
734 </article>
735
736 <article class="rule-card" id="rule-tiny-text" data-layer="cli">
737 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; color: #111;"><div style="font-size: 15px; margin-bottom: 6px;">Regular body text</div><div style="font-size: 9px; color: #555;">And then fine print at 9 pixels that no one will ever read.</div></div></div></div>
738 <div class="rule-card-body">
739 <div class="rule-card-head">
740 <span class="rule-card-category" data-category="quality">Quality</span>
741 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
742 </div>
743 <h3 class="rule-card-name">Tiny body text</h3>
744 <p class="rule-card-desc">Body text below 12px is hard to read, especially on high-DPI screens. Use at least 14px for body content, 16px is ideal.</p>
745
746 </div>
747 </article>
748
749 <article class="rule-card" id="rule-wide-tracking" data-layer="cli">
750 <div class="rule-card-visual" aria-hidden="true"><div class="rule-card-visual-inner"><div style="font-family: system-ui, sans-serif; font-size: 13px; color: #111; letter-spacing: 0.22em; max-width: 230px; line-height: 1.6;">Wide tracking on body text slows reading by breaking up natural character groupings.</div></div></div>
751 <div class="rule-card-body">
752 <div class="rule-card-head">
753 <span class="rule-card-category" data-category="quality">Quality</span>
754 <span class="rule-card-layer" data-layer="cli" title="Deterministic. Runs from `npx impeccable detect` on files, no browser required.">CLI</span>
755 </div>
756 <h3 class="rule-card-name">Wide letter spacing on body text</h3>
757 <p class="rule-card-desc">Letter spacing above 0.05em on body text disrupts natural character groupings and slows reading. Reserve wide tracking for short uppercase labels only.</p>
758
759 </div>
760 </article>
761 </div>
762 </section>
763 </div>
764 </section>
765
766 <section class="slop-section visual-mode-methods" id="run-it" aria-label="Where to run the overlay">
767 <h2 class="slop-section-heading"><span class="slop-section-num">04</span> Run it yourself</h2>
768 <div class="visual-mode-methods-grid">
769 <article class="visual-mode-method">
770 <p class="visual-mode-method-label">Inside /impeccable critique</p>
771 <h3 class="visual-mode-method-name"><a href="/docs/critique">/impeccable critique</a></h3>
772 <p class="visual-mode-method-desc">The design review command opens the overlay automatically during its browser assessment pass. Deterministic findings highlighted in place while the LLM runs its separate heuristic review.</p>
773 </article>
774 <article class="visual-mode-method">
775 <p class="visual-mode-method-label">Standalone CLI</p>
776 <h3 class="visual-mode-method-name"><code>npx impeccable live</code></h3>
777 <p class="visual-mode-method-desc">Starts a local server that serves the detector script. Inject it into any page via a <code><script></code> tag to see the overlay. Works on your own dev server, a staging URL, or anyone's live page.</p>
778 </article>
779 <article class="visual-mode-method">
780 <p class="visual-mode-method-label">Easiest</p>
781 <h3 class="visual-mode-method-name">Chrome extension</h3>
782 <p class="visual-mode-method-desc">One-click activation on any tab. <a href="https://chromewebstore.google.com/detail/impeccable/bdkgmiklpdmaojlpflclinlofgjfpabf" target="_blank" rel="noopener">Install from Chrome Web Store →</a></p>
783 </article>
784 </div>
785 </section>
786</div>
787 </div>
788</div>
789
790<script is:inline>
791 // Copy buttons on rendered code blocks
792 document.addEventListener('click', (e) => {
793 const btn = e.target.closest('[data-copy]');
794 if (!btn) return;
795 const text = btn.getAttribute('data-copy');
796 if (!text) return;
797 navigator.clipboard.writeText(text).then(() => {
798 btn.classList.add('is-copied');
799 setTimeout(() => btn.classList.remove('is-copied'), 1500);
800 }).catch(() => {});
801 });
802
803 // Mobile sidebar toggle (shown on narrow viewports, hidden on desktop).
804 document.addEventListener('click', (e) => {
805 const toggle = e.target.closest('.skills-sidebar-toggle');
806 if (!toggle) return;
807 const expanded = toggle.getAttribute('aria-expanded') === 'true';
808 toggle.setAttribute('aria-expanded', String(!expanded));
809 });
810
811 // Slop era toggle (2022 vs 2026)
812 document.addEventListener('click', (e) => {
813 const tab = e.target.closest('.slop-era-tab');
814 if (!tab) return;
815 const era = tab.getAttribute('data-era');
816 document.querySelectorAll('.slop-era-tab').forEach(t => {
817 t.classList.toggle('is-active', t === tab);
818 t.setAttribute('aria-selected', String(t === tab));
819 });
820 document.querySelectorAll('.slop-era-frame').forEach(f => {
821 f.style.display = f.getAttribute('data-era') === era ? '' : 'none';
822 });
823 const title = document.querySelector('.visual-mode-preview-title[data-title-2022]');
824 if (title) title.textContent = title.getAttribute('data-title-' + era);
825 });
826
827 // Before/after split-compare: drag on touch, hover OR drag on mouse.
828 // Pointer events attach to the padded .split-comparison wrapper so
829 // there is a ~20px invisible buffer around the visible box. The
830 // divider only snaps back when the pointer leaves that outer buffer.
831 (function initSplitCompare() {
832 const wrappers = document.querySelectorAll('.split-comparison');
833 if (wrappers.length === 0) return;
834 const hasHover = matchMedia('(hover: hover)').matches;
835 const DEFAULT_POSITION = 50;
836
837 for (const wrapper of wrappers) {
838 const container = wrapper.querySelector('.split-container');
839 const splitAfter = wrapper.querySelector('.split-after');
840 const splitDivider = wrapper.querySelector('.split-divider');
841 if (!container || !splitAfter || !splitDivider) continue;
842
843 const tanAngle = Math.tan(10 * Math.PI / 180);
844 let skewOffset = 8;
845 const recalcSkew = () => {
846 const r = container.getBoundingClientRect();
847 if (r.width > 0 && r.height > 0) {
848 skewOffset = 50 * r.height * tanAngle / r.width;
849 }
850 };
851 recalcSkew();
852 window.addEventListener('resize', recalcSkew, { passive: true });
853
854 let targetX = DEFAULT_POSITION;
855 let currentX = DEFAULT_POSITION;
856 let rafId = null;
857
858 const paint = (pct) => {
859 const x = Math.max(-skewOffset, Math.min(100 + skewOffset, pct));
860 splitAfter.style.clipPath =
861 `polygon(${x + skewOffset}% 0%, 100% 0%, 100% 100%, ${x - skewOffset}% 100%)`;
862 splitDivider.style.left = `${x}%`;
863 };
864
865 const step = () => {
866 currentX += (targetX - currentX) * 0.2;
867 if (Math.abs(targetX - currentX) < 0.1) {
868 currentX = targetX;
869 rafId = null;
870 } else {
871 rafId = requestAnimationFrame(step);
872 }
873 paint(currentX);
874 };
875
876 const setTarget = (pct) => {
877 targetX = pct;
878 if (rafId === null) rafId = requestAnimationFrame(step);
879 };
880
881 paint(DEFAULT_POSITION);
882
883 // Percentage is always relative to the VISIBLE .split-container,
884 // not the padded .split-comparison wrapper. The pointer event
885 // target is the wrapper but the clip-path math uses the inner box.
886 const pctFromClientX = (clientX) => {
887 const rect = container.getBoundingClientRect();
888 return ((clientX - rect.left) / rect.width) * 100;
889 };
890
891 let hovering = false;
892 let dragging = false;
893
894 wrapper.addEventListener('pointerenter', (e) => {
895 if (hasHover && e.pointerType === 'mouse') {
896 hovering = true;
897 }
898 });
899
900 wrapper.addEventListener('pointerdown', (e) => {
901 dragging = true;
902 wrapper.setPointerCapture(e.pointerId);
903 setTarget(pctFromClientX(e.clientX));
904 });
905
906 wrapper.addEventListener('pointermove', (e) => {
907 if (dragging || hovering) {
908 setTarget(pctFromClientX(e.clientX));
909 }
910 });
911
912 const endDrag = (e) => {
913 if (dragging) {
914 dragging = false;
915 try { wrapper.releasePointerCapture(e.pointerId); } catch {}
916 }
917 };
918
919 wrapper.addEventListener('pointerup', endDrag);
920 wrapper.addEventListener('pointercancel', endDrag);
921
922 wrapper.addEventListener('pointerleave', (e) => {
923 endDrag(e);
924 if (hovering) {
925 hovering = false;
926 setTarget(DEFAULT_POSITION);
927 }
928 });
929 }
930 })();
931 </script>
932
933</Base>