index.astro

  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 &amp; Contrast</span><span class="anti-patterns-sidebar-count">6</span></a></li>
 33            <li><a href="#section-layout-space"><span>Layout &amp; 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 &quot;make it pop.&quot;</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 &quot;Cool&quot; specimen" loading="lazy" width="540" height="540">
 96        </div>
 97        <div class="gallery-card-body">
 98          <h3 class="gallery-card-title">Lazy &quot;Cool&quot;</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 &quot;Impact&quot; specimen" loading="lazy" width="540" height="540">
106        </div>
107        <div class="gallery-card-body">
108          <h3 class="gallery-card-title">Lazy &quot;Impact&quot;</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 &quot;technical&quot; shorthand</h3>
345        <p class="rule-card-desc">Using a monospace typeface to signal &quot;developer / technical&quot; 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 &amp; 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 &quot;cool&quot; 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 &quot;safety&quot;</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 &amp; 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 (&quot;rivers of white&quot;). 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>&lt;script&gt;</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 &rarr;</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>