Style Guide — Make Post Sell Design System
Design System

Comprehensive design tokens, components, and patterns for makepostsell.com. Built on CSS custom properties. Mobile-first. Accessible. Respects reduced motion.

Design Tokens

All values live in tokens.css as CSS custom properties. Every component references tokens, never raw values. Change a token, change everything.

/* Include order */ <link rel="stylesheet" href="tokens.css"> /* tokens first */ <link rel="stylesheet" href="common.css"> /* shared app */ <link rel="stylesheet" href="mps.css"> /* ribbon, alerts */ <link rel="stylesheet" href="landing.css"> /* landing page only */
tokens.css also provides base resets (box-sizing, font smoothing, scroll-behavior) and prefers-reduced-motion support.
Colors
Brand
Green CTA
#a3c765
Green Dark
#8ab34e
Blue
#98b6fa
Navy
#5871ad
Navy Light
#82A8FF
Purple
#9B59B6
Purple Dark
#7B2D8E
Status
Check
#678731
Cross
#c77765
Danger
#CC6958
Gold
#d4a843
Surfaces
Base
#FFFFFF
Dim
#F9F9FA
Container
#F4F4F5
Container High
#EEEEEF
Inverse
#0b0b0b
Text
Primary
#0b0b0b
Body
#515151
Secondary
#666666
Muted
#777777
Faint
#999999
Disabled
#BBBBBB
Borders
Default
#e0e0e0
Light
#eeeeee
Focus
#5871ad
Error
#CC6958
Typography
Type scale (major third 1.250)
Display
Headline 1
Headline 2
Headline 3
Title Large
Title
Title Small
Body Large — ideal for landing pages and long reads.
Body — default for app interfaces and dashboard text.
Body Small — secondary information, metadata, timestamps.
Label Large
LABEL — SECTION HEADERS, GROUP TITLES
Caption — smallest text, footnotes
OVERLINE — CATEGORY TAGS
.type-display clamp(2.25rem, 5vw, 3.75rem) 700 tight .type-headline-1 3rem (48px) 700 tight .type-headline-2 2.25rem (36px) 700 tight .type-headline-3 1.875rem (30px) 700 snug .type-title-lg 1.5rem (24px) 600 snug .type-title 1.25rem (20px) 600 snug .type-title-sm 1rem (16px) 600 normal .type-body-lg 1.125rem (18px) 400 relaxed .type-body 1rem (16px) 400 relaxed .type-body-sm 0.875rem (14px) 400 relaxed .type-label-lg 0.875rem (14px) 600 wide .type-label 0.75rem (12px) 600 UPPERCASE wider .type-caption 0.75rem (12px) 400 normal .type-overline 11px 700 UPPERCASE widest .type-code monospace 0.9em inline code
App typography classes (common.css)
Huge Bold Dark

Big Bold Dark

Bold Dark

Body text in #515151 on Helvetica.

Link style — green, weight 600
Legacy classes. New code should prefer .type-* classes from tokens.css.
Font rendering
html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; font-size: 16px; /* 1rem = 16px base */ }
Antialiased rendering on macOS/iOS. optimizeLegibility enables kerning and ligatures. 16px base ensures rem values map cleanly to pixel equivalents.
Elevation

Five shadow levels. Higher = more prominent = closer to the viewer. Every interactive element should shift elevation on hover.

0
1
2
3
4
5
--elevation-0: none --elevation-1: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04) /* cards at rest */ --elevation-2: 0 2px 6px rgba(0,0,0,0.06), 0 2px 4px rgba(0,0,0,0.04) /* cards hovered */ --elevation-3: 0 4px 12px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.04) /* dropdown, popover */ --elevation-4: 0 8px 24px rgba(0,0,0,0.08), 0 2px 6px rgba(0,0,0,0.04) /* modal, dialog */ --elevation-5: 0 16px 48px rgba(0,0,0,0.10), 0 4px 12px rgba(0,0,0,0.05) /* toast, overlay */ Usage: element rests at N, hovers at N+1 or N+2 Cards: rest 1, hover 3 Buttons: rest 1, hover 2 Modals: 4 Toasts: 5
Motion
Easing curves
Standard
Decel
Accel
Spring
--ease-standard: cubic-bezier(0.2, 0, 0, 1) /* default for most transitions */ --ease-decelerate: cubic-bezier(0, 0, 0, 1) /* entering elements (fade in, slide in) */ --ease-accelerate: cubic-bezier(0.3, 0, 1, 1) /* exiting elements (fade out) */ --ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275) /* playful overshoot */ Hover each box above to feel the curve difference.
Durations
--duration-instant: 50ms /* micro-feedback (opacity toggle) */ --duration-fast: 100ms /* state layer opacity changes */ --duration-normal: 200ms /* color, shadow, border transitions */ --duration-slow: 300ms /* transform transitions (scale, translate) */ --duration-slower: 400ms /* complex animations (ripple) */ --duration-entrance: 250ms /* element enters viewport */ --duration-exit: 200ms /* element leaves (shorter = snappier) */
Entrance animations
fade-in
fade-up
scale
slide-R
.animate-fade-in /* opacity 0 to 1 */ .animate-fade-in-up /* fade + translate up 16px */ .animate-fade-in-down /* fade + translate down 16px */ .animate-fade-in-scale /* fade + scale from 0.95 */ .animate-slide-in-right /* fade + translate from right 24px */ .animate-slide-in-left /* fade + translate from left 24px */ .animate-pulse /* breathing opacity loop */ .animate-spin /* continuous rotation */ /* Stagger delays for lists */ .stagger-1 through .stagger-6 (50ms increments)
Reduced motion
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } } Automatically applied. No opt-in needed. All animations and transitions collapse to instant for users who prefer reduced motion.
Spacing

4px base unit. Consistent spacing prevents the "off by 3px" disease.

 
2
3
4
5
6
8
10
12
16
20
24
--space-1: 4px --space-8: 32px --space-2: 8px --space-10: 40px --space-3: 12px --space-12: 48px --space-4: 16px --space-16: 64px --space-5: 20px --space-20: 80px --space-6: 24px --space-24: 96px Utilities: .mt-{n} .mb-{n} .p-{n} .gap-{n}
Shape
none
sm 4px
md 8px
lg 12px
xl 16px
2xl 24px
full
--radius-none: 0 /* hard edges */ --radius-sm: 4px /* inputs, code blocks, app buttons */ --radius-md: 8px /* small cards, wells */ --radius-lg: 12px /* feature cards, landing cards */ --radius-xl: 16px /* pricing cards, comparison cards */ --radius-2xl: 24px /* large containers */ --radius-full: 9999px /* pills, avatars, badges */ Rule of thumb: bigger element = bigger radius.
Interactive States

State layer: a semi-transparent overlay that responds to interaction. Apply .state-layer to any interactive element.

Hover me
.state-layer::after { content: ''; position: absolute; inset: 0; background: currentColor; opacity: 0; transition: opacity 100ms ease; pointer-events: none; } .state-layer:hover::after { opacity: 0.04; } .state-layer:focus-visible::after { opacity: 0.08; } .state-layer:active::after { opacity: 0.10; } State overlay tokens: --state-hover: rgba(0,0,0, 0.04) --state-focus: rgba(88,113,173, 0.12) --state-pressed: rgba(0,0,0, 0.08) --state-dragged: rgba(0,0,0, 0.12)
Focus Rings

Keyboard-only focus rings. Visible on Tab, invisible on click. Navy blue, 2px, 2px offset.

Tab to focus this link
:focus-visible { outline: 2px solid var(--border-focus); /* navy #5871ad */ outline-offset: 2px; } :focus:not(:focus-visible) { outline: none; /* hide on mouse click */ } This is set globally in tokens.css. Works on all elements.
Ripple Effect

Material-style touch feedback. Add .ripple class and initialize with JS.

Click me
Click me
/* CSS */ .ripple { position: relative; overflow: hidden; } .ripple-wave { position: absolute; border-radius: 50%; background: rgba(255,255,255, 0.35); transform: scale(0); animation: ripple-expand 400ms ease-out forwards; } .ripple-dark .ripple-wave { background: rgba(0,0,0, 0.12); } /* JS initialization */ function createRipple(e) { const el = e.currentTarget; const rect = el.getBoundingClientRect(); const size = Math.max(rect.width, rect.height); const wave = document.createElement('span'); wave.className = 'ripple-wave'; wave.style.width = wave.style.height = size + 'px'; wave.style.left = (e.clientX - rect.left - size/2) + 'px'; wave.style.top = (e.clientY - rect.top - size/2) + 'px'; el.appendChild(wave); wave.addEventListener('animationend', () => wave.remove()); }
Buttons
App buttons (common.css)
Green CTA: .shop-new-button.mps-button #a3c765 Blue: .product-edit-button.mps-button #98b6fa Purple: .source-button.mps-button #9B59B6 Navy: .log-out-button.mps-button #5871ad Danger: .cart-delete-button.mps-button #CC6958 Outline: .shop-switch-button.mps-button border only All: border-radius 4px, min-width 250px, white text, bold
Disabled state
[disabled], .disabled { opacity: 0.38; pointer-events: none; cursor: not-allowed; }
Landing CTAs
.landing-cta: border-radius: 50px (pill) padding: 16px 32px box-shadow: elevation-1 hover: translateY(-1px) + elevation-2 .landing-cta-large: font-size: 18px padding: 18px 48px Nav CTA (.nav-cta): dark pill in nav bar, #0b0b0b bg
Feature Cards
💰 Card Title Card description with supporting text.
📈 Linked Card Cards in .landing-content get 12px radius, subtle shadow, hover lift.
Grid: .mps-card-grid (1col mobile, 2col tablet+) .mps-card-grid.three-col (3col at tablet+) Card: .mps-card App: border 1px #e0e0e0, radius 10px, padding 20px Landing: border 1px #eee, radius 12px, shadow elevation-1 Hover: elevation-3 + translateY(-2px)
Pricing Cards
Monthly
$14/mo Pay as you go.
.landing-pricing-card white, radius-xl, overflow hidden .landing-pricing-featured 2px green border, green shadow .landing-pricing-banner gray top strip, uppercase .landing-pricing-banner-featured green bg, white text .landing-pricing-amount 3em, weight 700 .landing-pricing-period 0.35em, color faint
Step Cards
1 First Description.
2 Second Description.
3 Third Description.
.landing-step-number: 44px green circle, white number, weight 700 .landing-step-card: centered text alignment
Protection Lists
  • Negative item
  • Another negative
  • Positive — Details
  • Another — More
.landing-list-bad: bg #fef2f2, border #f5d5d5 .landing-list-good: bg #f0f9e8, border #d5e8c0 .landing-x: color --color-cross .landing-check: color --color-check Items separated by 1px border-top at 5% opacity
Alerts
Success — --alert-success-bg
Info — --alert-info-bg
Warning — --alert-warning-bg
Danger — --alert-danger-bg
Variants: .alert-success, .alert-info, .alert-warning, .alert-danger Token pairs: --alert-{variant}-bg, --alert-{variant}-text, --alert-{variant}-border
Loading States
Skeleton

.skeleton shimmer gradient animation (1.5s loop) .skeleton-text height: 1em, small radius .skeleton-circle border-radius: full The shimmer runs through surface-container to surface-container-high.
Spinner
.spinner 20px, 2px border, navy top .spinner-sm 14px .spinner-lg 32px, 3px border Spins at 0.6s linear infinite.
Scroll Reveal

Elements with .reveal start invisible and slide up when scrolled into view. JS adds .revealed.

reveal
scale
.reveal { opacity: 0; transform: translateY(20px); transition: opacity 300ms ease-out, transform 300ms ease-out; } .reveal.revealed { opacity: 1; transform: translateY(0); } /* JS — IntersectionObserver */ const observer = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('revealed'); observer.unobserve(e.target); } }); }, { threshold: 0.15 }); document.querySelectorAll('.reveal, .reveal-scale') .forEach(el => observer.observe(el));
Wells
Well (gray background)
Content inside a gray well.
Well White
Content inside a white well.
.well bg: surface-dim, radius: 10px .well-white bg: surface-base
Message Ribbon
Sell digital downloads or physical products — commission free!
.message-ribbon gradient: navy #5871ad to navy-light #82A8FF white text, bold, 18px, centered hidden on mobile, visible at 800px+
Landing Sections
.landing-section (white)
.landing-section-alt (#F9F9FA)
.landing-final-cta (gradient)
.landing-hero (top gradient)
.landing-section padding: 64px mobile, 80px tablet, 100px desktop .landing-section-alt background: surface-dim .landing-final-cta gradient: #f4f6fb to #f0f3fa .landing-hero gradient: #f4f6fb to white (top-down) Alternating white/dim sections replace HR dividers.
Layout
Containers
Legacy: .one-column max-width: 800px, centered .one-column-thin max-width: 400px Token-based: .container max-width: var(--content-width) 800px, auto padding .container-narrow max-width: var(--content-narrow) 400px .container-wide max-width: var(--content-wide) 1200px
Breakpoints
Mobile first (no media query) @media (min-width: 800px) — tablet/desktop @media (min-width: 1200px) — wide desktop Tokens: --bp-tablet: 800px, --bp-desktop: 1200px
Z-index scale
--z-base: 0 /* default */ --z-dropdown: 100 /* dropdown menus */ --z-sticky: 200 /* sticky headers */ --z-overlay: 300 /* backdrop overlays */ --z-modal: 400 /* modal dialogs */ --z-toast: 500 /* toast notifications */ --z-ribbon: 600 /* top ribbon banner */
CSS files
tokens.css — design tokens, base resets, utilities, animations common.css — shared app styles (layout, buttons, nav, wells, footer, cards) mps.css — message ribbon, alerts landing.css — landing page (hero, sections, pricing, CTAs, lists, steps)