www.makepostsell.com/styleguide.html

1164 lines
51 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<title>Style Guide &#8212; Make Post Sell Design System</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#5871ad">
<link rel="stylesheet" href="tokens.css">
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="mps.css">
<link rel="stylesheet" href="landing.css">
<style>
body { color: var(--text-body); background-color: var(--surface-dim); }
a { color: var(--color-green); font-weight: 600; }
.bold-dark { color: var(--text-primary); font-weight: 550; }
.big-bold-dark { color: var(--text-primary); font-size: 1.4em; font-weight: 550; }
.huge-bold-dark { color: var(--text-primary); font-size: 2.7em; font-weight: 550; }
section.content { background-color: var(--surface-dim); }
/* Styleguide chrome */
.sg-toc { margin: 0 0 40px; }
.sg-toc a { color: var(--text-body); font-weight: 500; font-size: 15px; display: inline-block; margin: 4px 12px 4px 0; }
.sg-toc a:hover { color: var(--color-green); }
.sg-section { margin-bottom: 56px; }
.sg-section-title {
color: var(--text-primary);
font-size: 1.6em;
font-weight: var(--weight-bold);
border-bottom: 2px solid var(--border-default);
padding-bottom: 8px;
margin-bottom: 24px;
}
.sg-subsection { margin-bottom: 28px; }
.sg-label {
font-size: 13px;
font-weight: var(--weight-semibold);
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 10px;
}
.sg-swatches {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.sg-swatch {
width: 120px;
border-radius: var(--radius-md);
overflow: hidden;
border: 1px solid var(--border-default);
}
.sg-swatch-color { height: 60px; }
.sg-swatch-info {
padding: 8px;
background: var(--surface-base);
font-size: 12px;
line-height: 1.4;
}
.sg-swatch-name { font-weight: 600; color: var(--text-primary); }
.sg-swatch-hex { color: var(--text-faint); }
.sg-code {
background: var(--surface-container);
border: 1px solid var(--border-default);
border-radius: var(--radius-sm);
padding: 12px 16px;
font-family: var(--font-mono);
font-size: 13px;
overflow-x: auto;
white-space: pre;
margin-top: 8px;
line-height: 1.6;
}
.sg-demo {
padding: 24px;
background: var(--surface-base);
border: 1px solid var(--border-default);
border-radius: var(--radius-md);
margin-bottom: 8px;
}
.sg-demo-alt { background: var(--surface-dim); }
.sg-demo-dark { background: var(--surface-inverse); }
.sg-inline-demo {
display: flex;
flex-wrap: wrap;
gap: 16px;
align-items: center;
}
.sg-elevation-box {
width: 120px;
height: 80px;
background: var(--surface-base);
border-radius: var(--radius-lg);
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
font-weight: 600;
color: var(--text-secondary);
}
.sg-motion-box {
width: 80px;
height: 80px;
background: var(--color-navy);
border-radius: var(--radius-lg);
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 12px;
font-weight: 600;
cursor: pointer;
}
.sg-spacing-bar {
background: var(--color-navy-light);
opacity: 0.5;
height: 24px;
border-radius: var(--radius-sm);
display: flex;
align-items: center;
padding-left: 6px;
font-size: 11px;
font-weight: 600;
color: var(--text-primary);
}
.sg-radius-box {
width: 80px;
height: 80px;
background: var(--surface-container);
border: 2px solid var(--border-default);
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 600;
color: var(--text-secondary);
}
.sg-state-box {
width: 140px;
height: 60px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
font-weight: 600;
cursor: pointer;
background: var(--surface-base);
border: 1px solid var(--border-default);
}
.sg-focus-demo:focus-visible {
outline: 2px solid var(--border-focus);
outline-offset: 2px;
}
.sg-note {
font-size: 13px;
color: var(--text-muted);
margin-top: 8px;
line-height: 1.5;
}
.sg-token-table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
.sg-token-table th {
text-align: left;
font-weight: var(--weight-semibold);
color: var(--text-primary);
padding: 8px 12px;
border-bottom: 2px solid var(--border-default);
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.sg-token-table td {
padding: 8px 12px;
border-bottom: 1px solid var(--border-light);
vertical-align: middle;
}
.sg-token-table code {
font-family: var(--font-mono);
font-size: 12px;
background: var(--surface-container);
padding: 2px 6px;
border-radius: var(--radius-sm);
}
</style>
</head>
<body>
<div class="message-ribbon">
Style Guide &#8212; Make Post Sell Design System
</div>
<section class="main">
<section class="nav-grid">
<section class="nav">
<section class="logo">
<a href="/"><img class="logo" src="/static/mps.png" /></a>
</section>
<section class="middle"></section>
<section class="log-in">
<a href="/">Home</a>
<a href="/styleguide.html">Style Guide</a>
</section>
</section>
</section>
<section class="content">
<section class="one-column well">
<span class="huge-bold-dark">Design System</span>
<br/><br/>
<p style="max-width: 600px; line-height: 1.6;">
Comprehensive design tokens, components, and patterns for makepostsell.com. Built on CSS custom properties. Mobile-first. Accessible. Respects reduced motion.
</p>
<div class="sg-toc">
<a href="#tokens">Tokens</a>
<a href="#colors">Colors</a>
<a href="#typography">Typography</a>
<a href="#elevation">Elevation</a>
<a href="#motion">Motion</a>
<a href="#spacing">Spacing</a>
<a href="#shape">Shape</a>
<a href="#states">States</a>
<a href="#focus">Focus</a>
<a href="#ripple">Ripple</a>
<a href="#buttons">Buttons</a>
<a href="#landing-ctas">Landing CTAs</a>
<a href="#cards">Cards</a>
<a href="#pricing">Pricing</a>
<a href="#steps">Steps</a>
<a href="#lists">Lists</a>
<a href="#alerts">Alerts</a>
<a href="#loading">Loading</a>
<a href="#reveal">Reveal</a>
<a href="#wells">Wells</a>
<a href="#ribbon">Ribbon</a>
<a href="#sections">Sections</a>
<a href="#layout">Layout</a>
<a href="#footer">Footer</a>
</div>
<!-- ======== TOKENS ======== -->
<div class="sg-section" id="tokens">
<div class="sg-section-title">Design Tokens</div>
<p>All values live in <code style="font-family: var(--font-mono); background: var(--surface-container); padding: 2px 6px; border-radius: 4px;">tokens.css</code> as CSS custom properties. Every component references tokens, never raw values. Change a token, change everything.</p>
<div class="sg-code">/* Include order */
&lt;link rel="stylesheet" href="tokens.css"&gt; /* tokens first */
&lt;link rel="stylesheet" href="common.css"&gt; /* shared app */
&lt;link rel="stylesheet" href="mps.css"&gt; /* ribbon, alerts */
&lt;link rel="stylesheet" href="landing.css"&gt; /* landing page only */</div>
<div class="sg-note">tokens.css also provides base resets (box-sizing, font smoothing, scroll-behavior) and prefers-reduced-motion support.</div>
</div>
<!-- ======== COLORS ======== -->
<div class="sg-section" id="colors">
<div class="sg-section-title">Colors</div>
<div class="sg-subsection">
<div class="sg-label">Brand</div>
<div class="sg-swatches">
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--color-green);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Green CTA</div><div class="sg-swatch-hex">#a3c765</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--color-green-dark);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Green Dark</div><div class="sg-swatch-hex">#8ab34e</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--color-blue);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Blue</div><div class="sg-swatch-hex">#98b6fa</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--color-navy);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Navy</div><div class="sg-swatch-hex">#5871ad</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--color-navy-light);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Navy Light</div><div class="sg-swatch-hex">#82A8FF</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--color-purple);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Purple</div><div class="sg-swatch-hex">#9B59B6</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--color-purple-dark);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Purple Dark</div><div class="sg-swatch-hex">#7B2D8E</div></div></div>
</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Status</div>
<div class="sg-swatches">
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--color-check);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Check</div><div class="sg-swatch-hex">#678731</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--color-cross);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Cross</div><div class="sg-swatch-hex">#c77765</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--color-danger);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Danger</div><div class="sg-swatch-hex">#CC6958</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--color-gold);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Gold</div><div class="sg-swatch-hex">#d4a843</div></div></div>
</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Surfaces</div>
<div class="sg-swatches">
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--surface-base); border-bottom: 1px solid #e0e0e0;"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Base</div><div class="sg-swatch-hex">#FFFFFF</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--surface-dim); border-bottom: 1px solid #e0e0e0;"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Dim</div><div class="sg-swatch-hex">#F9F9FA</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--surface-container);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Container</div><div class="sg-swatch-hex">#F4F4F5</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--surface-container-high);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Container High</div><div class="sg-swatch-hex">#EEEEEF</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--surface-inverse);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Inverse</div><div class="sg-swatch-hex">#0b0b0b</div></div></div>
</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Text</div>
<div class="sg-swatches">
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--text-primary);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Primary</div><div class="sg-swatch-hex">#0b0b0b</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--text-body);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Body</div><div class="sg-swatch-hex">#515151</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--text-secondary);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Secondary</div><div class="sg-swatch-hex">#666666</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--text-muted);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Muted</div><div class="sg-swatch-hex">#777777</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--text-faint);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Faint</div><div class="sg-swatch-hex">#999999</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--text-disabled);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Disabled</div><div class="sg-swatch-hex">#BBBBBB</div></div></div>
</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Borders</div>
<div class="sg-swatches">
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--border-default);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Default</div><div class="sg-swatch-hex">#e0e0e0</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--border-light);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Light</div><div class="sg-swatch-hex">#eeeeee</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--border-focus);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Focus</div><div class="sg-swatch-hex">#5871ad</div></div></div>
<div class="sg-swatch"><div class="sg-swatch-color" style="background: var(--border-error);"></div><div class="sg-swatch-info"><div class="sg-swatch-name">Error</div><div class="sg-swatch-hex">#CC6958</div></div></div>
</div>
</div>
</div>
<!-- ======== TYPOGRAPHY ======== -->
<div class="sg-section" id="typography">
<div class="sg-section-title">Typography</div>
<div class="sg-subsection">
<div class="sg-label">Type scale (major third 1.250)</div>
<div class="sg-demo">
<div class="type-display" style="margin-bottom: 12px;">Display</div>
<div class="type-headline-1" style="margin-bottom: 12px;">Headline 1</div>
<div class="type-headline-2" style="margin-bottom: 12px;">Headline 2</div>
<div class="type-headline-3" style="margin-bottom: 12px;">Headline 3</div>
<div class="type-title-lg" style="margin-bottom: 12px;">Title Large</div>
<div class="type-title" style="margin-bottom: 12px;">Title</div>
<div class="type-title-sm" style="margin-bottom: 12px;">Title Small</div>
<div class="type-body-lg" style="margin-bottom: 12px;">Body Large &#8212; ideal for landing pages and long reads.</div>
<div class="type-body" style="margin-bottom: 12px;">Body &#8212; default for app interfaces and dashboard text.</div>
<div class="type-body-sm" style="margin-bottom: 12px;">Body Small &#8212; secondary information, metadata, timestamps.</div>
<div class="type-label-lg" style="margin-bottom: 12px;">Label Large</div>
<div class="type-label" style="margin-bottom: 12px;">LABEL &#8212; SECTION HEADERS, GROUP TITLES</div>
<div class="type-caption" style="margin-bottom: 12px;">Caption &#8212; smallest text, footnotes</div>
<div class="type-overline" style="margin-bottom: 12px;">OVERLINE &#8212; CATEGORY TAGS</div>
</div>
<div class="sg-code">.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</div>
</div>
<div class="sg-subsection">
<div class="sg-label">App typography classes (common.css)</div>
<div class="sg-demo">
<span class="huge-bold-dark">Huge Bold Dark</span>
<br/><br/>
<span class="big-bold-dark">Big Bold Dark</span>
<br/><br/>
<span class="bold-dark">Bold Dark</span>
<br/><br/>
Body text in #515151 on Helvetica.
<br/><br/>
<a href="#">Link style &#8212; green, weight 600</a>
</div>
<div class="sg-note">Legacy classes. New code should prefer .type-* classes from tokens.css.</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Font rendering</div>
<div class="sg-code">html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
font-size: 16px; /* 1rem = 16px base */
}</div>
<div class="sg-note">Antialiased rendering on macOS/iOS. optimizeLegibility enables kerning and ligatures. 16px base ensures rem values map cleanly to pixel equivalents.</div>
</div>
</div>
<!-- ======== ELEVATION ======== -->
<div class="sg-section" id="elevation">
<div class="sg-section-title">Elevation</div>
<p>Five shadow levels. Higher = more prominent = closer to the viewer. Every interactive element should shift elevation on hover.</p>
<div class="sg-demo sg-demo-alt">
<div class="sg-inline-demo">
<div class="sg-elevation-box elevation-0">0</div>
<div class="sg-elevation-box elevation-1">1</div>
<div class="sg-elevation-box elevation-2">2</div>
<div class="sg-elevation-box elevation-3">3</div>
<div class="sg-elevation-box elevation-4">4</div>
<div class="sg-elevation-box elevation-5">5</div>
</div>
</div>
<div class="sg-code">--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</div>
</div>
<!-- ======== MOTION ======== -->
<div class="sg-section" id="motion">
<div class="sg-section-title">Motion</div>
<div class="sg-subsection">
<div class="sg-label">Easing curves</div>
<div class="sg-demo">
<div class="sg-inline-demo">
<div class="sg-motion-box" style="transition: transform var(--duration-slow) var(--ease-standard);" onmouseenter="this.style.transform='scale(1.15)'" onmouseleave="this.style.transform='scale(1)'">Standard</div>
<div class="sg-motion-box" style="transition: transform var(--duration-slow) var(--ease-decelerate);" onmouseenter="this.style.transform='scale(1.15)'" onmouseleave="this.style.transform='scale(1)'">Decel</div>
<div class="sg-motion-box" style="transition: transform var(--duration-slow) var(--ease-accelerate);" onmouseenter="this.style.transform='scale(1.15)'" onmouseleave="this.style.transform='scale(1)'">Accel</div>
<div class="sg-motion-box" style="transition: transform var(--duration-slow) var(--ease-spring);" onmouseenter="this.style.transform='scale(1.15)'" onmouseleave="this.style.transform='scale(1)'">Spring</div>
</div>
</div>
<div class="sg-code">--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.</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Durations</div>
<div class="sg-code">--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) */</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Entrance animations</div>
<div class="sg-demo">
<div class="sg-inline-demo">
<div class="sg-motion-box animate-fade-in">fade-in</div>
<div class="sg-motion-box animate-fade-in-up stagger-1">fade-up</div>
<div class="sg-motion-box animate-fade-in-scale stagger-2">scale</div>
<div class="sg-motion-box animate-slide-in-right stagger-3">slide-R</div>
</div>
</div>
<div class="sg-code">.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)</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Reduced motion</div>
<div class="sg-code">@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.</div>
</div>
</div>
<!-- ======== SPACING ======== -->
<div class="sg-section" id="spacing">
<div class="sg-section-title">Spacing</div>
<p>4px base unit. Consistent spacing prevents the "off by 3px" disease.</p>
<div class="sg-demo sg-demo-alt">
<div style="display: grid; gap: 6px; max-width: 500px;">
<div class="sg-spacing-bar" style="width: 4px;">&nbsp;</div>
<div class="sg-spacing-bar" style="width: 8px;">2</div>
<div class="sg-spacing-bar" style="width: 12px;">3</div>
<div class="sg-spacing-bar" style="width: 16px;">4</div>
<div class="sg-spacing-bar" style="width: 20px;">5</div>
<div class="sg-spacing-bar" style="width: 24px;">6</div>
<div class="sg-spacing-bar" style="width: 32px;">8</div>
<div class="sg-spacing-bar" style="width: 40px;">10</div>
<div class="sg-spacing-bar" style="width: 48px;">12</div>
<div class="sg-spacing-bar" style="width: 64px;">16</div>
<div class="sg-spacing-bar" style="width: 80px;">20</div>
<div class="sg-spacing-bar" style="width: 96px;">24</div>
</div>
</div>
<div class="sg-code">--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}</div>
</div>
<!-- ======== SHAPE ======== -->
<div class="sg-section" id="shape">
<div class="sg-section-title">Shape</div>
<div class="sg-demo">
<div class="sg-inline-demo">
<div class="sg-radius-box" style="border-radius: var(--radius-none);">none</div>
<div class="sg-radius-box" style="border-radius: var(--radius-sm);">sm 4px</div>
<div class="sg-radius-box" style="border-radius: var(--radius-md);">md 8px</div>
<div class="sg-radius-box" style="border-radius: var(--radius-lg);">lg 12px</div>
<div class="sg-radius-box" style="border-radius: var(--radius-xl);">xl 16px</div>
<div class="sg-radius-box" style="border-radius: var(--radius-2xl);">2xl 24px</div>
<div class="sg-radius-box" style="border-radius: var(--radius-full); width: 80px;">full</div>
</div>
</div>
<div class="sg-code">--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.</div>
</div>
<!-- ======== STATES ======== -->
<div class="sg-section" id="states">
<div class="sg-section-title">Interactive States</div>
<p>State layer: a semi-transparent overlay that responds to interaction. Apply <code style="font-family: var(--font-mono); background: var(--surface-container); padding: 2px 6px; border-radius: 4px;">.state-layer</code> to any interactive element.</p>
<div class="sg-demo">
<div class="sg-inline-demo">
<div class="sg-state-box state-layer">Hover me</div>
<button class="sg-state-box state-layer" tabindex="0" style="border: 1px solid var(--border-default); background: var(--surface-base); cursor: pointer; font-family: var(--font-family); font-size: 13px; font-weight: 600;">Focus me (Tab)</button>
</div>
</div>
<div class="sg-code">.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)</div>
</div>
<!-- ======== FOCUS ======== -->
<div class="sg-section" id="focus">
<div class="sg-section-title">Focus Rings</div>
<p>Keyboard-only focus rings. Visible on Tab, invisible on click. Navy blue, 2px, 2px offset.</p>
<div class="sg-demo">
<div class="sg-inline-demo">
<button class="sg-focus-demo" style="padding: 12px 24px; border: 1px solid var(--border-default); background: var(--surface-base); border-radius: var(--radius-md); cursor: pointer; font-family: var(--font-family); font-size: 14px; font-weight: 600;">Tab to focus this button</button>
<a href="#" class="sg-focus-demo" style="padding: 12px 24px; border-radius: var(--radius-md); font-size: 14px;">Tab to focus this link</a>
</div>
</div>
<div class="sg-code">: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.</div>
</div>
<!-- ======== RIPPLE ======== -->
<div class="sg-section" id="ripple">
<div class="sg-section-title">Ripple Effect</div>
<p>Material-style touch feedback. Add <code style="font-family: var(--font-mono); background: var(--surface-container); padding: 2px 6px; border-radius: 4px;">.ripple</code> class and initialize with JS.</p>
<div class="sg-demo">
<div class="sg-inline-demo">
<div class="sg-motion-box ripple ripple-dark" style="background: var(--color-green); border-radius: var(--radius-lg);" onclick="createRipple(event)">Click me</div>
<div class="sg-motion-box ripple" style="border-radius: var(--radius-lg);" onclick="createRipple(event)">Click me</div>
</div>
</div>
<div class="sg-code">/* 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());
}</div>
</div>
<!-- ======== BUTTONS ======== -->
<div class="sg-section" id="buttons">
<div class="sg-section-title">Buttons</div>
<div class="sg-subsection">
<div class="sg-label">App buttons (common.css)</div>
<div class="sg-demo">
<div class="sg-inline-demo" style="flex-wrap: wrap;">
<a href="#" class="shop-new-button mps-button">+ New Shop</a>
<a href="#" class="product-edit-button mps-button">Edit</a>
<a href="#" class="source-button mps-button">Source Code</a>
<a href="#" class="log-out-button mps-button">Log Out</a>
<a href="#" class="cart-delete-button mps-button">Delete</a>
<a href="#" class="shop-switch-button mps-button">Switch Shop</a>
</div>
</div>
<div class="sg-code">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</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Disabled state</div>
<div class="sg-demo">
<div class="sg-inline-demo">
<a href="#" class="shop-new-button mps-button disabled">+ New Shop</a>
<a href="#" class="product-edit-button mps-button disabled">Edit</a>
</div>
</div>
<div class="sg-code">[disabled], .disabled {
opacity: 0.38;
pointer-events: none;
cursor: not-allowed;
}</div>
</div>
</div>
<!-- ======== LANDING CTAS ======== -->
<div class="sg-section" id="landing-ctas">
<div class="sg-section-title">Landing CTAs</div>
<div class="sg-demo">
<div class="landing-cta-group">
<a href="#" class="shop-new-button mps-button landing-cta">+ Open a Shop</a>
<a href="#" class="source-button mps-button landing-cta">Source Code</a>
</div>
<br/>
<div class="landing-cta-group">
<a href="#" class="shop-new-button mps-button landing-cta landing-cta-large">+ Open a Shop (large)</a>
</div>
</div>
<div class="sg-code">.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</div>
</div>
<!-- ======== CARDS ======== -->
<div class="sg-section" id="cards">
<div class="sg-section-title">Feature Cards</div>
<div class="sg-demo">
<div class="mps-card-grid" style="max-width: 500px;">
<div class="mps-card">
<span class="mps-card-icon">&#128176;</span>
<span class="mps-card-title">Card Title</span>
<span class="mps-card-desc">Card description with supporting text.</span>
</div>
<div class="mps-card">
<span class="mps-card-icon">&#128200;</span>
<span class="mps-card-title"><a href="#">Linked Card</a></span>
<span class="mps-card-desc">Cards in .landing-content get 12px radius, subtle shadow, hover lift.</span>
</div>
</div>
</div>
<div class="sg-code">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)</div>
</div>
<!-- ======== PRICING ======== -->
<div class="sg-section" id="pricing">
<div class="sg-section-title">Pricing Cards</div>
<div class="sg-demo sg-demo-alt">
<div class="landing-pricing" style="max-width: 500px;">
<div class="landing-pricing-card">
<div class="landing-pricing-banner">Monthly</div>
<span class="landing-pricing-amount">$14<span class="landing-pricing-period">/mo</span></span>
<span class="landing-pricing-desc">Pay as you go.</span>
</div>
<div class="landing-pricing-card landing-pricing-featured">
<div class="landing-pricing-banner landing-pricing-banner-featured">Best value</div>
<span class="landing-pricing-amount">$97<span class="landing-pricing-period">/yr</span></span>
<span class="landing-pricing-desc">Save 42%.</span>
</div>
</div>
</div>
<div class="sg-code">.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</div>
</div>
<!-- ======== STEPS ======== -->
<div class="sg-section" id="steps">
<div class="sg-section-title">Step Cards</div>
<div class="sg-demo">
<div class="mps-card-grid three-col" style="max-width: 600px;">
<div class="mps-card landing-step-card">
<span class="landing-step-number">1</span>
<span class="mps-card-title">First</span>
<span class="mps-card-desc">Description.</span>
</div>
<div class="mps-card landing-step-card">
<span class="landing-step-number">2</span>
<span class="mps-card-title">Second</span>
<span class="mps-card-desc">Description.</span>
</div>
<div class="mps-card landing-step-card">
<span class="landing-step-number">3</span>
<span class="mps-card-title">Third</span>
<span class="mps-card-desc">Description.</span>
</div>
</div>
</div>
<div class="sg-code">.landing-step-number: 44px green circle, white number, weight 700
.landing-step-card: centered text alignment</div>
</div>
<!-- ======== LISTS ======== -->
<div class="sg-section" id="lists">
<div class="sg-section-title">Protection Lists</div>
<div class="sg-demo">
<div class="landing-two-lists" style="max-width: 600px;">
<div class="landing-list-card landing-list-bad">
<ul>
<li><span class="landing-x">&#x274C;</span> Negative item</li>
<li><span class="landing-x">&#x274C;</span> Another negative</li>
</ul>
</div>
<div class="landing-list-card landing-list-good">
<ul>
<li><span class="landing-check">&#x2714;</span> <b>Positive</b> <span class="landing-list-detail">&#8212; Details</span></li>
<li><span class="landing-check">&#x2714;</span> <b>Another</b> <span class="landing-list-detail">&#8212; More</span></li>
</ul>
</div>
</div>
</div>
<div class="sg-code">.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</div>
</div>
<!-- ======== ALERTS ======== -->
<div class="sg-section" id="alerts">
<div class="sg-section-title">Alerts</div>
<div class="sg-demo">
<div class="alert alert-success" style="display: block; padding: 10px; margin-bottom: 8px; border-radius: 4px;">
<div class="alert-message">Success &#8212; --alert-success-bg</div>
</div>
<div class="alert alert-info" style="display: block; padding: 10px; margin-bottom: 8px; border-radius: 4px;">
<div class="alert-message">Info &#8212; --alert-info-bg</div>
</div>
<div class="alert alert-warning" style="display: block; padding: 10px; margin-bottom: 8px; border-radius: 4px;">
<div class="alert-message">Warning &#8212; --alert-warning-bg</div>
</div>
<div class="alert alert-danger" style="display: block; padding: 10px; margin-bottom: 8px; border-radius: 4px;">
<div class="alert-message">Danger &#8212; --alert-danger-bg</div>
</div>
</div>
<div class="sg-code">Variants: .alert-success, .alert-info, .alert-warning, .alert-danger
Token pairs: --alert-{variant}-bg, --alert-{variant}-text, --alert-{variant}-border</div>
</div>
<!-- ======== LOADING ======== -->
<div class="sg-section" id="loading">
<div class="sg-section-title">Loading States</div>
<div class="sg-subsection">
<div class="sg-label">Skeleton</div>
<div class="sg-demo">
<div style="max-width: 300px;">
<div class="skeleton skeleton-text" style="width: 80%; height: 24px; margin-bottom: 12px;"></div>
<div class="skeleton skeleton-text" style="width: 100%;"></div>
<div class="skeleton skeleton-text" style="width: 60%;"></div>
<br/>
<div style="display: flex; gap: 12px; align-items: center;">
<div class="skeleton skeleton-circle" style="width: 40px; height: 40px; flex-shrink: 0;"></div>
<div style="flex: 1;">
<div class="skeleton skeleton-text" style="width: 50%;"></div>
<div class="skeleton skeleton-text" style="width: 30%;"></div>
</div>
</div>
</div>
</div>
<div class="sg-code">.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.</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Spinner</div>
<div class="sg-demo">
<div class="sg-inline-demo">
<span class="spinner spinner-sm"></span>
<span class="spinner"></span>
<span class="spinner spinner-lg"></span>
</div>
</div>
<div class="sg-code">.spinner 20px, 2px border, navy top
.spinner-sm 14px
.spinner-lg 32px, 3px border
Spins at 0.6s linear infinite.</div>
</div>
</div>
<!-- ======== REVEAL ======== -->
<div class="sg-section" id="reveal">
<div class="sg-section-title">Scroll Reveal</div>
<p>Elements with <code style="font-family: var(--font-mono); background: var(--surface-container); padding: 2px 6px; border-radius: 4px;">.reveal</code> start invisible and slide up when scrolled into view. JS adds <code style="font-family: var(--font-mono); background: var(--surface-container); padding: 2px 6px; border-radius: 4px;">.revealed</code>.</p>
<div class="sg-demo">
<div class="sg-inline-demo">
<div class="sg-motion-box reveal revealed">reveal</div>
<div class="sg-motion-box reveal-scale revealed" style="animation-delay: 100ms;">scale</div>
</div>
</div>
<div class="sg-code">.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));</div>
</div>
<!-- ======== WELLS ======== -->
<div class="sg-section" id="wells">
<div class="sg-section-title">Wells</div>
<div class="sg-subsection">
<div class="sg-label">Well (gray background)</div>
<div class="sg-demo">
<section class="one-column well">
Content inside a gray well.
</section>
</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Well White</div>
<div class="sg-demo sg-demo-alt">
<section class="one-column well well-white">
Content inside a white well.
</section>
</div>
<div class="sg-code">.well bg: surface-dim, radius: 10px
.well-white bg: surface-base</div>
</div>
</div>
<!-- ======== RIBBON ======== -->
<div class="sg-section" id="ribbon">
<div class="sg-section-title">Message Ribbon</div>
<div class="sg-demo">
<div class="message-ribbon" style="display: block;">
Sell digital downloads or physical products &#8212; commission free!
</div>
</div>
<div class="sg-code">.message-ribbon
gradient: navy #5871ad to navy-light #82A8FF
white text, bold, 18px, centered
hidden on mobile, visible at 800px+</div>
</div>
<!-- ======== SECTIONS ======== -->
<div class="sg-section" id="sections">
<div class="sg-section-title">Landing Sections</div>
<div class="sg-demo" style="padding: 0; overflow: hidden;">
<div style="padding: 24px; background: var(--surface-base);">
<div style="text-align: center; font-weight: 600; color: var(--text-secondary);">.landing-section (white)</div>
</div>
<div style="padding: 24px; background: var(--surface-dim);">
<div style="text-align: center; font-weight: 600; color: var(--text-secondary);">.landing-section-alt (#F9F9FA)</div>
</div>
<div style="padding: 24px; background: linear-gradient(135deg, #f4f6fb 0%, #f0f3fa 100%);">
<div style="text-align: center; font-weight: 600; color: var(--text-secondary);">.landing-final-cta (gradient)</div>
</div>
<div style="padding: 24px; background: linear-gradient(180deg, #f4f6fb 0%, #FFFFFF 100%);">
<div style="text-align: center; font-weight: 600; color: var(--text-secondary);">.landing-hero (top gradient)</div>
</div>
</div>
<div class="sg-code">.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.</div>
</div>
<!-- ======== LAYOUT ======== -->
<div class="sg-section" id="layout">
<div class="sg-section-title">Layout</div>
<div class="sg-subsection">
<div class="sg-label">Containers</div>
<div class="sg-code">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</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Breakpoints</div>
<div class="sg-code">Mobile first (no media query)
@media (min-width: 800px) &#8212; tablet/desktop
@media (min-width: 1200px) &#8212; wide desktop
Tokens: --bp-tablet: 800px, --bp-desktop: 1200px</div>
</div>
<div class="sg-subsection">
<div class="sg-label">Z-index scale</div>
<div class="sg-code">--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 */</div>
</div>
<div class="sg-subsection">
<div class="sg-label">CSS files</div>
<div class="sg-code">tokens.css &#8212; design tokens, base resets, utilities, animations
common.css &#8212; shared app styles (layout, buttons, nav, wells, footer, cards)
mps.css &#8212; message ribbon, alerts
landing.css &#8212; landing page (hero, sections, pricing, CTAs, lists, steps)</div>
</div>
</div>
<!-- ======== FOOTER ======== -->
<div class="sg-section" id="footer">
<div class="sg-section-title">Footer</div>
<div class="sg-code">&lt;footer class="mps-footer"&gt;
&lt;div class="mps-footer-grid"&gt; 4-column at 800px+
&lt;div class="mps-footer-brand"&gt; logo + tagline
&lt;div class="mps-footer-group"&gt; title + links
&lt;/div&gt;
&lt;div class="mps-footer-ctas"&gt; buttons row
&lt;div class="mps-footer-bottom"&gt; copyright
&lt;/footer&gt;</div>
<p>See live footer below &#x2193;</p>
</div>
</section>
</section>
</section>
<footer class="mps-footer">
<div class="mps-footer-grid">
<div class="mps-footer-brand">
<a href="/" class="mps-footer-logo">Make Post Sell</a>
<p class="mps-footer-tagline">Commission-free shops for creators, makers, and media. Public domain software by <a href="https://www.unturf.com/software/" target="_blank">unturf</a>.</p>
</div>
<div class="mps-footer-group">
<span class="mps-footer-group-title">Get Started</span>
<nav class="mps-footer-links">
<a href="https://blog.makepostsell.com/c/0b408430-3a2a-11ef-8208-c3d535a3beac/how-to-create-a-new-shop-on-makepostsell">Create a Shop</a>
<a href="https://blog.makepostsell.com/c/83c41f98-3a2f-11ef-8208-c3d535a3beac/how-to-create-a-new-product-on-makepostsell">Create a Product</a>
<a href="https://blog.makepostsell.com/c/59c8c980-3a3b-11ef-8208-c3d535a3beac/how-to-create-new-content-on-makepostsell">Create Content</a>
<a href="https://blog.makepostsell.com/c/64903474-3a3c-11ef-8208-c3d535a3beac/how-to-create-a-digital-bundle-for-products-content-on-makepostsell">Create a Bundle</a>
</nav>
</div>
<div class="mps-footer-group">
<span class="mps-footer-group-title">Resources</span>
<nav class="mps-footer-links">
<a href="https://blog.makepostsell.com/">Blog</a>
<a href="https://git.unturf.com/engineering/make-post-sell/make_post_sell" target="_blank">Source Code</a>
<a href="https://pypi.org/project/make-post-sell/" target="_blank">PyPi</a>
<a href="/styleguide.html">Style Guide</a>
</nav>
</div>
<div class="mps-footer-group">
<span class="mps-footer-group-title">Account</span>
<nav class="mps-footer-links">
<a href="https://my.makepostsell.com/u/settings">My Account</a>
<a href="https://my.makepostsell.com/s/new">Open a Shop</a>
</nav>
</div>
</div>
<div class="mps-footer-ctas">
<a href="https://my.makepostsell.com/s/new" class="shop-new-button mps-button">+ Open a Shop</a>
<a href="https://git.unturf.com/engineering/make-post-sell/make_post_sell" target="_blank" class="source-button mps-button">Contribute Code</a>
</div>
<div class="mps-footer-bottom">
makepostsell.com &copy; 2026 &mdash; Public domain software by <a href="https://www.unturf.com/software/" target="_blank">unturf.com</a>
</div>
</footer>
<script>
// Ripple effect
function createRipple(e) {
var el = e.currentTarget;
var rect = el.getBoundingClientRect();
var size = Math.max(rect.width, rect.height);
var 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', function() { wave.remove(); });
}
// Scroll reveal
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(e) {
if (e.isIntersecting) {
e.target.classList.add('revealed');
observer.unobserve(e.target);
}
});
}, { threshold: 0.15 });
document.querySelectorAll('.reveal, .reveal-scale').forEach(function(el) {
observer.observe(el);
});
// Prevent href="#" demo links from scrolling to top
document.querySelectorAll('a[href="#"]').forEach(function(a) {
a.addEventListener('click', function(e) { e.preventDefault(); });
});
</script>
</body>
</html>