90+ AI Design Patterns to Avoid: The Definitive List
Ninety-plus patterns that mark frontend code as machine-made — from #3B82F6 primaries to fade-up-on-scroll — each with the AI default, why it tells, and what a human ships instead.
Paste any v0 export into a diff tool and search for #3B82F6, backdrop-blur-md, and opacity: 0, y: 20. You will find all three, in roughly that order, in well over half of them. That is not a coincidence — it is a fingerprint. This is the working catalog of those fingerprints: the specific patterns that appear, over and over, in code generated by Cursor, v0, Lovable, Bolt, and the models behind them.
For each pattern we give the same three things: why it signals AI origin, the AI-default version (usually as code), and what a human designer ships instead.
Use it as a checklist on your own projects. Use it during code review. Use it to train your eye — the more patterns you can name on sight, the harder it is for them to slip through, whether you are typing the code yourself or directing an agent to.
Sailop detects every pattern below automatically. But detection without understanding just produces a number. Understanding produces better design — and lets you argue with the score when it is wrong.
How this list was built
These patterns come out of analysis of more than 10,000 AI-generated landing pages, component libraries, and full-stack apps — output from GPT-4-class models, Claude, Gemini, and open-weight models shipped between 2024 and 2026. For the framework behind the dimensions, read what is AI slop: the 7 dimensions of generic design. Patterns are grouped by dimension and numbered for reference.
Each entry follows one format:
- Pattern name and number
- Why it signals AI: what about it reveals LLM origin
- Example: the AI-default version
- Instead: what to do differently
Color Patterns
C01: The Blue Primary
The single most common AI color choice. Models default to Tailwind blue-500 (#3B82F6) or indigo-500 (#6366F1) as the primary brand color because these dominate the training data.
Why it signals AI: Over 60% of AI-generated sites land a primary somewhere in the blue-600 to indigo-600 band. Real brands distribute across the full wheel.
/* AI default */
--primary: #3B82F6;
--primary-dark: #2563EB;Instead: Pick a primary outside the blue-indigo range. Earth tones, warm neutrals, greens, and muted reds are underrepresented in AI output and read as intentional. Picking an accent that isn't Tailwind blue walks through the method.
/* Human alternative */
--primary: #2D5A3D;
--primary-dark: #1E3F2B;C02: Blue-to-Purple Gradient
The gradient from blue-600 to purple-600 across hero sections. Rare before 2023, now the dominant AI hero treatment — common enough that it has its own breakdown: the Tailwind blue-purple gradient AI signature.
Why it signals AI: This exact direction and color pair shows up in training data from hundreds of SaaS pages that were themselves AI-generated. It is a feedback loop printing its own fingerprint.
/* AI default */
background: linear-gradient(to right, #2563EB, #7C3AED);Instead: Use a flat background, a subtle texture, or a gradient between adjacent hues rather than complementary ones.
/* Human alternative */
background: #FEFCF8;
/* Or a subtle warm gradient */
background: linear-gradient(165deg, #F4EDE4, #FEFCF8);C03: Gray-50 Background (#F9FAFB)
Tailwind's gray-50 — the most common AI background color. The "safe neutral" every model reaches for.
Why it signals AI: The literal hex #F9FAFB appears so often it functions as a signature. Grep any AI-built repo and you will find it on the .
Instead: Use a warm off-white like #FEFCF8 or #F5F0EB, or a tinted neutral that relates to your primary.
C04: Insufficient Palette Depth
AI generates 3-4 colors: primary, background, text, maybe one accent. Human designers work with 8-12, including tints, shades, semantic colors, and contextual variations.
Why it signals AI: A shallow palette reads as flat and unconfigured — there is nowhere for the design to go.
Instead: Generate a full set: primary, secondary, accent, background, surface, text, muted, success, warning, error, at minimum. Run sailop palette for a complete one.
C05: Pure White Cards on Gray Background
White (#FFFFFF) cards on a gray-50 (#F9FAFB) background. The contrast is so low it looks accidental, yet it is the universal AI default for card sections.
Why it signals AI: #FFFFFF on #F9FAFB is a 1.01:1 contrast ratio between card and background — barely perceptible, visually inert.
Instead: Use a tinted surface like #F4EDE4 on a distinctly different background, or drop the card container entirely and separate with spacing and type.
C06: Oversaturated Accent Colors
AI accents run fully saturated: yellow-400, green-500, red-500. They clash with the muted palette around them and read as afterthoughts.
Instead: Desaturate. Use OKLCH to hold perceptual lightness while dropping chroma. A muted terracotta (#C4553A) signals more craft than a pure red (#EF4444).
C07: Linear Gradient Buttons
Buttons with linear-gradient backgrounds shifting from one saturated color to another.
Instead: Flat-colored buttons with a subtle hover change. Gradients on small interactive elements feel decorative, not functional.
C08: Colored Badge Pills
Small rounded-full pills with a light tinted background and darker same-hue text: bg-blue-100 text-blue-800. Every AI hero has one.
Instead: Plain text with tracking-widest uppercase, or a simple border-bottom treatment.
C09: Star Rating Yellow (#FACC15)
AI always reaches for yellow-400 on star ratings — every testimonial block, every review component.
Instead: If you need ratings, use your brand color or a neutral. Better: cut star ratings from testimonials entirely. They add noise without credibility.
C10: Identical Dark Mode Inversion
Dark mode that flips light values to dark ones with no thought for how color behaves on dark backgrounds.
Instead: Design dark mode as a separate palette. Dark backgrounds want lighter, slightly desaturated colors. Reduce chroma and raise lightness for text on dark surfaces. See C06 in the craft section for a worked palette, and zinc-950 as the AI dark default for the trap to avoid.
C11: Status Colors from Tailwind Defaults
green-500 for success, red-500 for error, yellow-500 for warning — uncustomized.
Instead: Tune status colors to your palette. A muted forest green for success and a muted rust for error keep semantics while feeling deliberate.
C12: Background Gradients with Fixed Blobs
Blurred purple-and-blue circles position: absolute behind the hero. The decorative blob.
Instead: For texture, use subtle grain overlays, geometric patterns, or photography. Blurred color blobs are an AI signature — glassmorphism and backdrop-blur tell the same story.
C13: Ring Offset Focus States
focus:ring-2 ring-offset-2 ring-blue-500 on every interactive element. Tailwind's default focus pattern, applied universally.
Instead: Design custom focus states in your brand color. Reach for outline-offset, box-shadow, or a background change.
C14: Hover Color Shifts to Darker Variant
Every hover just steps to the -700 shade: hover:bg-blue-700 on a bg-blue-600 button.
Instead: Vary hover treatments — subtle background shifts, underline reveals, icon movement, opacity changes. Not every hover needs a darkening.
C15: Decorative Dividers as Gradient Lines
floating between sections.
Instead: A plain with a custom border-color, or whitespace alone.
Typography Patterns
T01: Inter as the Only Font
Inter is the default AI font. It shows up in over 70% of AI-generated projects because it is the most common font in the training data. Geist is fast becoming the second — see Geist, the new Inter.
Instead: Pick a body font outside the top 10 Google Fonts. IBM Plex Sans, Source Serif 4, Instrument Serif, DM Sans. Why Inter is killing your brand has 10 tested pairings.
T02: System-UI Font Stack Only
font-family: system-ui, -apple-system, sans-serif; with no custom font loaded. The "I did not choose a font" font.
Instead: Load at least a body face and a display face. Two intentional typefaces signal design thought on their own.
T03: Uniform Type Scale (1rem Increments)
h1: 3rem, h2: 2.25rem, h3: 1.5rem, body: 1rem. The mathematically tidy AI default.
Instead: Use a modular scale with a custom ratio — 1.25 or 1.333 produces more interesting relationships. Or hand-pick sizes that create tension.
T04: No Letter-Spacing Adjustments
AI never tracks by size. Display headings want tighter tracking (-0.02em to -0.04em); small text wants looser (0.02em to 0.05em).
Instead: Add letter-spacing: -0.03em to headings above 2rem and letter-spacing: 0.01em to text below 0.875rem.
T05: Bold for All Headings
Every heading is font-bold (700). No variation between levels.
Instead: Vary weight — h1 at 400 italic, h2 at 600, h3 at 500. Weight variation creates rhythm.
T06: text-gray-600 for All Body Text
AI uses text-gray-600 (#4B5563) for nearly all non-heading text. The universal "secondary text."
Instead: A custom muted color from your palette. A warm gray (#6B6560) reads more human than blue-tinted Tailwind gray.
T07: No Display Font
One family for everything. Human designers pair a display face for headings with a body face for text.
Instead: Add a display font for h1 and h2. Serif + sans pairings are classic — Instrument Serif over IBM Plex Sans, for one.
T08: Leading-7 or Leading-Relaxed Everywhere
One line-height, set globally. Real typography adjusts per context: tighter for headings, looser for body, looser still for small dense UI.
Instead: Display 1.1. Body 1.6. Small 1.5. Caption 1.4.
T09: No Prose Styling
Long-form content with no max-width, no hanging punctuation, no paragraph spacing tuned for reading.
Instead: Cap prose at 65ch. Add text-rendering: optimizeLegibility. Use 1.5em paragraph spacing.
T10: Centered Text in Every Section
Every section centers its content with text-center. Human designs default to left-alignment and center only on purpose.
Instead: Left-align by default. Center only the hero heading and CTA. Mixed alignment creates interest.
T11: No Font Feature Settings
AI never enables OpenType features — ligatures, old-style figures, contextual alternates. These are craft signals.
Instead: Add font-feature-settings: "kern", "liga", "calt" to body text, and "ss01"/"ss02" stylistic sets where the font supports them.
T12: All-Caps Without Tracking
Uppercase with no extra letter-spacing looks cramped.
Instead: Always pair uppercase with tracking-widest, or at least tracking-wider. The spacing is what makes caps readable.
Layout Patterns
L01: Three-Column Equal Grid
grid-cols-3 gap-6 with identical children. The most recognizable AI layout there is.
Instead: Asymmetric grids (2/3 + 1/3), definition lists, varied-width columns. If you must use three, vary content height or treatment. There is a whole article on this one: the card grid problem.
L02: max-w-7xl mx-auto on Every Section
Every section in the same centered container. No full-bleed, no narrow text column, no variation.
Instead: Vary max-width between sections. max-w-3xl for text-heavy, max-w-6xl for features, full-bleed for the hero.
L03: Symmetric py-24 px-6 Padding
Identical vertical and horizontal padding on every section. No rhythm, no density variation.
Instead: Vary it. pt-32 pb-20 on one, pt-16 pb-24 on the next. Build vertical rhythm through asymmetry.
L04: Hero / Features / Testimonials / Pricing / CTA / Footer
The AI section order. Nearly every generated landing page follows this exact sequence.
Instead: Reorder around your content. Lead with a case study. Put pricing before features. Break the expected flow — how to build a unique landing page covers alternative structures.
L05: All Content Centered Horizontally
Everything centered: mx-auto text-center. No left-aligned content, no asymmetric positioning.
Instead: Left-align body content. Use ml-[8%] or ml-[12%] for intentional off-center placement.
L06: Equal-Height Cards via Grid Stretch
Grid's default stretch forcing all cards to one height even when content varies wildly.
Instead: align-items: start lets cards size to content. Varied heights read organic.
L07: Full-Width Section with Centered Content Column
Every section full-width with one centered column. No sidebars, no split sections, no multi-column text.
Instead: Split layouts (50/50 or 60/40), sidebar-and-content, multi-column text.
L08: Sticky Nav with Blur Backdrop
sticky top-0 backdrop-blur-md bg-white/80. Every AI nav bar, byte for byte.
Instead: A solid-background nav, a hide-on-scroll/reveal-on-scroll-up nav, or a minimal text-only header.
L09: No Full-Bleed Content
AI never breaks content out of its container. No edge-to-edge images, no background that escapes the column.
Instead: Let key elements break out. A full-bleed image or a viewport-spanning background color is visual punctuation.
L10: Footer with 4-Column Grid
The standard AI footer: logo column, three link columns, copyright bar beneath.
Instead: A single-column footer, a two-row footer, or a minimal footer with just copyright and the essential links.
L11: Mobile-First Grid Collapse to Stack
Every grid collapses to one column via grid-cols-1 md:grid-cols-3. No intermediate layout, no creative small-screen arrangement.
Instead: 2-column on tablet, horizontal scroll on mobile, or accordion patterns for mobile features.
L12: No Off-Grid Elements
Everything sits perfectly on the grid. No overlaps, no negative margins, nothing that breaks the lines.
Instead: Occasional negative margins, overlapping elements, absolute-positioned accents to break the rigidity.
L13: Z-Pattern Layout Applied Uniformly
Hero image right, text left. Next section: image left, text right. Alternating forever.
Instead: Break the alternation. Run two consecutive left-aligned sections. Drop a full-width section between alternating ones.
L14: No Whitespace as Design Element
AI fills every section. There is no empty space used deliberately.
Instead: Use generous whitespace between sections. Let a heading stand alone with 200px below it. Whitespace signals confidence.
L15: Fixed Aspect Ratio Image Containers
Every image jammed into 16:9 or 4:3 regardless of content.
Instead: Let images use their natural ratio, or choose ratios that complement the content.
Animation Patterns
A01: Fade-Up on Scroll
opacity: 0, y: 20 to opacity: 1, y: 0 on scroll intersection. Every section, every element. It is so endemic it earned its own teardown: motion slop.
Instead: No animation for most content. Reserve it for one hero element or a key interaction. Stillness is a craft signal.
A02: Hover Scale 1.05 + Shadow
Cards that scale to 1.05 and gain a shadow on hover. The universal AI hover.
/* AI default */
.card:hover { transform: scale(1.05); box-shadow: 0 20px 25px -5px rgba(0,0,0,.1); }Instead: Subtle background-color shifts, border-color transitions, or nothing. Movement on hover should be purposeful.
A03: Stagger Delay 0.1s
When elements animate in, they stagger at exactly 0.1s intervals. Every time.
Instead: Irregular stagger (0.05s, 0.12s, 0.08s), or animate groups rather than individuals.
A04: Spring Physics Defaults
Framer Motion spring with default stiffness (100) and damping (10) on every animated element.
Instead: Vary by element. Stiffer springs for small elements, softer for large — or CSS transitions with custom cubic-bezier curves.
A05: Duration 300ms on Everything
transition-duration: 300ms everywhere — Tailwind's duration-300, applied without thought.
Instead: Shorter (150ms) for small UI, longer (500ms) for large layout transitions. Vary by context.
A06: Ease-in-out on Everything
transition-timing-function: ease-in-out everywhere. No custom curves.
Instead: cubic-bezier(0.22, 1, 0.36, 1) for entrances, cubic-bezier(0.55, 0, 1, 0.45) for exits. Custom easing is an immediate craft signal.
A07: Infinite Pulse on Badges
animate-pulse or animate-bounce on notification badges and status dots. Distracting and pointless.
Instead: A static indicator, or a single subtle flash on state change.
A08: Parallax Scroll on Hero Image
Hero background scrolling at a different rate than content. Overused and often janky on mobile.
Instead: A static hero image, or a subtle CSS-only effect like a slight scale on scroll.
A09: Loading Skeleton Shimmer
The gray-to-light-gray shimmer sweep on loading skeletons. Every AI loading state uses the same one.
Instead: A simple opacity pulse or a solid gray placeholder. The shimmer is template DNA at this point.
A10: Counting Number Animation
Numbers counting up from 0 when scrolled into view. Every stats section.
Instead: Show the number. The count-up adds no information and delays comprehension.
A11: Typewriter Effect on Hero Heading
Hero text typing out character by character. Novel in 2023, an instant AI tell now.
Instead: Show the text immediately. If you want an entrance, use one fade or a clip-path reveal.
A12: Continuous Float or Bob on Icons
Decorative icons floating up and down on an infinite loop. Distracting, purposeless.
Instead: Keep decorative elements still. Animation should respond to interaction, not run forever.
Component Patterns
CP01: Icon + Heading + Paragraph Card
The standard AI feature card: an icon in a colored circle, a heading, a paragraph.
Instead: A numbered list, a definition list, a table, or a flowing paragraph with inline emphasis.
CP02: Hero with Badge + H1 + Subtitle + Two Buttons
The exact AI hero: small badge pill, large heading, subtitle, two buttons (primary + ghost).
Instead: Simplify. One heading and one button. Or a heading with an inline link. Drop the badge. Break the template — 21 anti-slop hero compositions show how.
CP03: Testimonial Cards with Circle Avatars
Three cards, each with a circular avatar, a name, a title, a quoted paragraph.
Instead: One large blockquote. Drop the avatars. Text-only attribution. Feature one testimonial prominently rather than three equally.
CP04: Pricing Cards with Popular Badge
Three tiers; the middle is "popular" with a colored badge and a different border.
Instead: A comparison table, or highlight the recommended plan with a genuinely different layout (larger, repositioned) rather than a badge. 15 anti-slop pricing layouts has alternatives.
CP05: FAQ Accordion with Chevron Icons
Questions expanding to answers behind a rotating chevron. Every FAQ section, identically.
Instead: Show all answers by default (under 8 of them). Or a plain toggle without the chevron. Or present FAQs as a flowing document.
CP06: Newsletter Input with Inline Button
An email input with a button glued to its right edge inside a rounded container.
Instead: Stack input and button vertically. Or a "Get updates" link that opens a modal. The inline input-button combo is an AI signature.
CP07: Stats Section with Large Numbers
A row of 3-4 big numbers with labels: "10K+ Users", "99.9% Uptime", "150+ Countries".
Instead: Fold stats into prose. "Used by over 10,000 teams across 150 countries" says the same thing without the template.
CP08: Logo Cloud with Grayscale Filter
A row of client logos with grayscale and reduced opacity; hover reveals color.
Instead: Logos at full color, small, in a plain row. Or name the clients in a sentence. The grayscale treatment is a default.
CP09: CTA Section with Gradient Background
A CTA with a blue-to-purple gradient, centered white text, a white button.
Instead: Your brand background color. Left-align the text. Use an underlined link, not a button. Break every expectation.
CP10: Feature with Screenshot and Description
Alternating screenshot-left/text-right, then screenshot-right/text-left.
Instead: One column with the screenshot above the text. Or an annotated screenshot with callout numbers. Or skip the screenshot for a code example.
CP11: Team Grid with Hover Social Links
Team photos in a grid with social links that appear on hover.
Instead: A simple list — names, titles, one-line bios. Social links inline as text. The hover-reveal is overused.
CP12: Timeline with Alternating Sides
A vertical timeline with events alternating left and right of a center line.
Instead: A plain vertical list with dates, or a horizontal scrolling timeline. The alternating-sides pattern comes straight from training data.
CP13: Tabs with Underline Indicator
Tab nav where the active tab has an underline that slides between tabs.
Instead: Filled tab backgrounds, vertical tab lists, or segmented controls. The sliding underline is everywhere in AI output.
CP14: Modal with Backdrop Blur
Modals over a blurred, darkened backdrop — backdrop-blur again.
Instead: A plain dark overlay without blur, slide-in side panels, or inline expansion instead of a modal.
CP15: Toast Notifications with Icons
Success/error toasts with a colored icon, title, description, and close button.
Instead: One line of text with a dismiss action. Drop the icon. Cut the visual complexity.
Structural Patterns
S01: Components Directory with Index Files
/components/ui/Button/index.tsx — every component in its own directory.
Instead: A valid pattern that AI over-applies. Small components can be colocated in one file. Not everything needs a directory.
S02: Utility Class Soup
Elements with 15+ Tailwind classes in one className. No extraction, no composition.
<div className="flex flex-col items-center justify-center gap-4 rounded-2xl border border-gray-200 bg-white p-6 shadow-sm transition-all hover:shadow-md hover:-translate-y-1 md:p-8">Instead: Extract repeated patterns into custom properties or component-level styles. Keep className strings under 8-10 classes — how AI agents generate CSS explains why they pile up.
S03: div Soup Without Semantic HTML
Everything is a Instead: Semantic HTML. AI adds Instead: Mark decorative elements The same styling props on every sibling in a list — same size, variant, color. Instead: Vary props by content. The first item could be "large", the rest "small". Uniformity is not a requirement. Pages built as flat trees: Header, Hero, Features, Testimonials, Pricing, CTA, Footer. No nesting, no composition. Instead: Build intermediate composition components that combine sections under shared context or styling. Components with 10+ visual props (size, variant, color, rounded, shadow…) — a configuration explosion. Instead: Limit variants. A button needs size and variant. Most other visual properties belong in the design system, not props. Instead: Write static content as explicit JSX when there are fewer than five items. Mapping is for dynamic data, not three features. Every file uses Instead: Prefer named exports — easier to refactor, search, and tree-shake. A Instead: Use Every spacing value a multiple of 4: 4, 8, 12, 16, 20, 24, 32, 48, 64. No odd values. Instead: A 5px or 6px base grid, or a modular scale (1.333 ratio) that yields irregular but harmonious values. The 4px grid is the AI default because it is the Tailwind default. Instead: Vary by context. 24px padding on every card, container, and box. Instead: Vary by content. Text-heavy cards 16px margin-top between every consecutive element: heading, Instead: Vary by relationship. More after headings ( 96px vertical padding on every full-width section. Instead: AI never uses negative margins, Instead: An occasional negative margin — Instead: Vary it. AI never adjusts for optical alignment. A heading ending in descenders (g, y, p) wants a different bottom margin than one without. AI treats every text box identically. Instead: Micro-adjust. If a heading ends in a round letter (O, C), trim bottom margin 1-2px. Invisible consciously, registers as "polished" subconsciously. Positive patterns that signal human craftsmanship. Their presence lowers your AI score and raises perceived quality. Sailop checks for these and rewards projects that include them. Style the AI never does this. Three lines of CSS, and it immediately reads as intentional. Override the browser default focus ring with your own: Wrap animation in a motion-preference query: Match the scrollbar to your system: Hide navigation, fix colors, optimize layout for paper: Not inverted colors — a separately designed dark palette with reduced chroma and adjusted contrast: Moves quotation marks and other punctuation outside the text block for optical alignment. Extremely rare in AI output. Fixed-width numerals align in columns. AI uses proportional figures everywhere, so prices in a pricing table jitter by a pixel or two between rows. Prevents an awkward single-word last line in a heading. Small detail, large visual payoff. Using the native View Transitions API for page transitions signals awareness of the modern platform. Reaching for container queries instead of media queries shows component-level design thinking. Custom underline offset, thickness, and color signal the kind of typographic attention AI never shows. Patterns are easier to internalize side by side. Here is the AI-default feature card — C01, CP01, A02, SP03, T06, and S02 all in one block: Same content, the human version — semantic element, no hover scale, weighted heading, palette colors, optical padding: No A living reference. As models evolve, new patterns surface and old ones fade — but the core holds: AI converges on defaults, and defaults are detectable. To use it: Every pattern you fix moves the site further from the AI default and closer to looking like someone cared. For step-by-step application, see the complete guide to anti-AI design or the Grade F to Grade A case study. Bookmark it. Open it during code review. Share it with your team. The patterns are not going away — but naming them is the first move toward building something that does not. Start scanning at sailop.com. Scan your frontend for AI patterns. Generate a unique design system. Stop shipping the same blue gradient as everyone else., , , , , . for sections, for feature lists, for testimonials, for captioned images.S04: aria-label on Decorative Elements
aria-label to decorative icons and dividers that should carry aria-hidden="true" instead.aria-hidden="true". Reserve aria-label for interactive elements without visible text.S05: Identical Props on Sibling Components
S06: Single-Level Component Hierarchy
S07: Props for Every Visual Variation
S08: Mapped Arrays for Static Content
{items.map(item => where items is a static array in the same file.S09: Default Export on Every File
export default. AI defaults to it because it dominates the training data.S10: cn() Utility for Every className
cn() call (clsx + twMerge) on components with no conditional classes — imported and invoked even when the className is a static string.cn() only with conditional or merged classes. Static classNames stay plain strings.Spacing Patterns
SP01: 4px Base Grid with No Deviation
SP02: gap-6 on Every Grid
gap-6 (24px) on every grid and flex container.gap-3 for tight UI, gap-8 for loose content, gap-16 for section spacing inside a grid.SP03: p-6 on Every Card
p-8 or p-10. Icon cards p-4. Asymmetric padding (pt-8 pb-6 px-7) adds character.SP04: mt-4 Between Every Element
mt-4, paragraph, mt-4, button.mt-6), less between related paragraphs (mt-2), most before CTAs (mt-10).SP05: py-24 on Every Section
pt-32 pb-20 on the hero, py-16 on a dense info section, py-40 on a spacious CTA.SP06: No Negative Space Usage
calc()-derived negatives, or overlap. Every element stays inside its parent.-mt-8 to overlap a header with the section beneath it — creates visual connection.SP07: Identical Horizontal Padding
px-6 on every section, every container, at every breakpoint.px-4 on mobile, px-8 on tablet, px-0 on full-bleed desktop sections.SP08: No Optical Spacing Adjustments
Craft Signals — What TO Do
CS01: Custom Selection Colors
::selection pseudo-element in your brand colors.::selection {
background-color: #2D5A3D;
color: #FEFCF8;
}CS02: Custom Focus-Visible Styles
:focus-visible {
outline: 2px solid #2D5A3D;
outline-offset: 3px;
border-radius: 2px;
}CS03: Prefers-Reduced-Motion Support
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}CS04: Custom Scrollbar Styling
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-track { background: #F4EDE4; }
::-webkit-scrollbar-thumb { background: #6B6560; border-radius: 2px; }CS05: Print Styles
@media print {
nav, footer, .no-print { display: none; }
body { color: #000; background: #fff; }
a { text-decoration: underline; }
a[href]::after { content: " (" attr(href) ")"; font-size: 0.8em; }
}CS06: Proper Dark Mode Palette
@media (prefers-color-scheme: dark) {
:root {
--background: #1A1917;
--surface: #252420;
--text: #E8E0D6;
--muted: #8B8580;
--primary: #5B9E74; /* Lighter, less saturated than light mode */
--accent: #D4745A; /* Lighter, less saturated */
}
}CS07: Smooth Scroll with Preference Check
@media (prefers-reduced-motion: no-preference) {
html { scroll-behavior: smooth; }
}CS08: Hanging Punctuation
blockquote, .prose { hanging-punctuation: first last; }CS09: Custom List Markers
ul { list-style: none; }
ul li::before {
content: "\2013"; /* en-dash */
color: #C4553A;
font-weight: 600;
margin-right: 0.75em;
}CS10: Tabular Figures in Data
.data-table, .price, .stat {
font-variant-numeric: tabular-nums;
}CS11: Subpixel Antialiasing Control
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}CS12: Balanced Text Wrapping
h1, h2, h3 {
text-wrap: balance;
}CS13: View Transitions API
@view-transition {
navigation: auto;
}
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.3s;
}CS14: Container Queries
.card-container { container-type: inline-size; }
@container (min-width: 400px) {
.card { flex-direction: row; }
}CS15: Custom Underline Styling
a {
text-decoration: underline;
text-underline-offset: 3px;
text-decoration-thickness: 1.5px;
text-decoration-color: #C4553A;
}A worked example: one card, two origins
<div className="bg-white rounded-2xl shadow-sm p-6 transition-all duration-300 hover:scale-105 hover:shadow-lg">
<div className="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center mb-4">
<Icon className="text-blue-600" />
</div>
<h3 className="text-xl font-bold mb-2">Fast and reliable</h3>
<p className="text-gray-600">Lorem ipsum description text goes here.</p>
</div><article className="surface pt-7 pb-6 px-7">
<span className="marker" aria-hidden="true">01</span>
<h3 style={{ fontWeight: 500, letterSpacing: '-0.02em' }}>Fast and reliable</h3>
<p style={{ color: '#6B6560', lineHeight: 1.6 }}>Real, specific description text.</p>
</article>.surface { background: #F4EDE4; }
.marker { color: #C4553A; font-variant-numeric: tabular-nums; }
.surface:hover { background: #EFE6DA; } /* color shift, not scale */#3B82F6, no rounded-full blue icon chip, no scale-105, no text-gray-600. The second card scores lower because every default has been replaced by a decision.Using this list
sailop scan ./src for your current score and which patterns are present# Quick start
npx sailop install
sailop scan ./src
# See which specific patterns from this list are detected
sailop scan --verbose --rules ./src
# Auto-fix the highest-impact patterns
sailop transform --priority high ./srcSHIP CODE THAT LOOKS INTENTIONAL