tokens.css: CSS custom properties for colors, surfaces, text, borders, typography scale (major third), spacing (4px base), shape (7 radius levels), elevation (5 shadow levels), motion (4 easing curves, 7 durations), state layers, ripple effect, entrance animations (6 types + stagger), skeleton loading, spinner, scroll reveal, disabled states, spacing/margin utilities, prefers-reduced-motion, font smoothing, box-sizing reset. styleguide.html: live interactive demos for every token and component. Elevation boxes, motion curve hover demos, ripple click demo, skeleton shimmer, spinner sizes, focus ring demo, state layer demo, full TOC with anchor links.
1159 lines
51 KiB
HTML
1159 lines
51 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
|
|
<title>Style Guide — 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 — 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 */
|
|
<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 */</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 — ideal for landing pages and long reads.</div>
|
|
<div class="type-body" style="margin-bottom: 12px;">Body — default for app interfaces and dashboard text.</div>
|
|
<div class="type-body-sm" style="margin-bottom: 12px;">Body Small — 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 — SECTION HEADERS, GROUP TITLES</div>
|
|
<div class="type-caption" style="margin-bottom: 12px;">Caption — smallest text, footnotes</div>
|
|
<div class="type-overline" style="margin-bottom: 12px;">OVERLINE — 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 — 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;"> </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">💰</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">📈</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">❌</span> Negative item</li>
|
|
<li><span class="landing-x">❌</span> Another negative</li>
|
|
</ul>
|
|
</div>
|
|
<div class="landing-list-card landing-list-good">
|
|
<ul>
|
|
<li><span class="landing-check">✔</span> <b>Positive</b> <span class="landing-list-detail">— Details</span></li>
|
|
<li><span class="landing-check">✔</span> <b>Another</b> <span class="landing-list-detail">— 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 — --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 — --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 — --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 — --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 — 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) — tablet/desktop
|
|
@media (min-width: 1200px) — 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 — 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)</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- ======== FOOTER ======== -->
|
|
<div class="sg-section" id="footer">
|
|
<div class="sg-section-title">Footer</div>
|
|
|
|
<div class="sg-code"><footer class="mps-footer">
|
|
<div class="mps-footer-grid"> 4-column at 800px+
|
|
<div class="mps-footer-brand"> logo + tagline
|
|
<div class="mps-footer-group"> title + links
|
|
</div>
|
|
<div class="mps-footer-ctas"> buttons row
|
|
<div class="mps-footer-bottom"> copyright
|
|
</footer></div>
|
|
<p>See live footer below ↓</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 © 2026 — 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);
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|